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
|
Sep
|
Oct
|
Nov
|
Dec
|
From: openocd-gerrit <ope...@us...> - 2024-04-07 19:37: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 47d983a77aeefa511d18450d65e7111799d926a8 (commit) from 79b51fedab9e8023a2e72551c4dcaf4373274287 (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 47d983a77aeefa511d18450d65e7111799d926a8 Author: Walter Ji <wal...@os...> Date: Mon Mar 18 17:24:51 2024 +0800 target/mips32: fix clang sbuild check fail Initialized `value` variables that could only be set in a branch. Change-Id: Iec7413ade9d053c93352a58ff954ad49a6545923 Signed-off-by: Walter Ji <wal...@os...> Reviewed-on: https://review.openocd.org/c/openocd/+/8179 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/mips32.c b/src/target/mips32.c index 6bbf71bd8..81faab72d 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -2109,7 +2109,7 @@ static int mips32_dsp_find_register_by_name(const char *reg_name) */ static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) { - uint32_t value; + uint32_t value = 0; for (int i = 0; i < MIPS32NUMDSPREGS; i++) { int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i); if (retval != ERROR_OK) { @@ -2134,7 +2134,7 @@ static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_e */ static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) { - uint32_t value; + uint32_t value = 0; int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); if (index == MIPS32NUMDSPREGS) { command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); ----------------------------------------------------------------------- Summary of changes: src/target/mips32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-04-07 19:37:02
|
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 79b51fedab9e8023a2e72551c4dcaf4373274287 (commit) from e035756b22f96adc95b791aaa01de7a2c11d7f2e (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 79b51fedab9e8023a2e72551c4dcaf4373274287 Author: J. Neuschäfer <j.n...@gm...> Date: Sat Mar 30 13:18:43 2024 +0100 remote_bitbang: Change sleep commands to Zz to avoid conflict with SWD It was noticed that the remote_bitbang protocol has a design issue: SWD and sleep commands cannot be implemented at the same time, because they overlap: - SWD uses d,e,f,g for setting pin state - sleep uses d,D for microsecond and millisecond sleep, respectively This has previously been reported by Marek Vrbka, but it wasn't fixed. This commit does the following to resolve the issue: - Change the sleep commands to 'Z' for 1 ms, 'z' for 1 µs - Document 'D' and 'd' as deprecated aliases - Switch the remote_bitbang driver in OpenOCD to 'Z' and 'z' Unfortunately that's a breaking change, because existing adapter-side implementations of the protocol will have to implement the new commands to keep working with future versions of OpenOCD. Fortunately, the remote sleep commands haven't been part of an OpenOCD release yet, which should limit the breakage somewhat. Reported-by: Marek Vrbka <mar...@co...> Link: https://sourceforge.net/p/openocd/mailman/openocd-devel/thread/670d28d2-75a1-45ec-afe5-541415701d7a%40codasip.com/ Fixes: e8e09b1b5 ("remote_bitbang: add use_remote_sleep option to send delays to remote") Change-Id: I04d2790a33bff9d47eb7f69b3275fd9a271625ae Signed-off-by: J. Neuschäfer <j.n...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8191 Reviewed-by: David Ryskalczyk <dav...@gm...> Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins Reviewed-by: Jeremy Herbert <jer...@gm...> diff --git a/doc/manual/jtag/drivers/remote_bitbang.txt b/doc/manual/jtag/drivers/remote_bitbang.txt index 94d603816..8316cb0dd 100644 --- a/doc/manual/jtag/drivers/remote_bitbang.txt +++ b/doc/manual/jtag/drivers/remote_bitbang.txt @@ -77,7 +77,12 @@ The read responses are encoded in ASCII as either digit 0 or 1. If the use_remote_sleep option is set to 'yes', two additional requests may be sent: - D - Sleep for 1 millisecond - d - Sleep for 1 microsecond + Z - Sleep for 1 millisecond + z - Sleep for 1 microsecond + +NOTE: Previously these were specified as 'D' and 'd', which conflicts with the +"SWD write 0 0" command defined above. Adapters that implement Dd for remote +sleep must be updated to work with Zz. + */ diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index c97b6b6ab..53d2151fd 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -230,13 +230,13 @@ static int remote_bitbang_sleep(unsigned int microseconds) unsigned int us = microseconds % 1000; for (unsigned int i = 0; i < ms; i++) { - tmp = remote_bitbang_queue('D', NO_FLUSH); + tmp = remote_bitbang_queue('Z', NO_FLUSH); if (tmp != ERROR_OK) return tmp; } for (unsigned int i = 0; i < us; i++) { - tmp = remote_bitbang_queue('d', NO_FLUSH); + tmp = remote_bitbang_queue('z', NO_FLUSH); if (tmp != ERROR_OK) return tmp; } ----------------------------------------------------------------------- Summary of changes: doc/manual/jtag/drivers/remote_bitbang.txt | 9 +++++++-- src/jtag/drivers/remote_bitbang.c | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-04-07 19:36: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 e035756b22f96adc95b791aaa01de7a2c11d7f2e (commit) from 74e7fcb2dd96c09f946bc8b0f59bfdf6215d8873 (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 e035756b22f96adc95b791aaa01de7a2c11d7f2e Author: Antonio Borneo <bor...@gm...> Date: Sun Mar 24 16:17:11 2024 +0100 jtag: linuxgpiod: fix detection for line request bias Commit 290eac04b93c ("drivers/linuxgpiod: Migrate to adapter gpio commands") introduced an incorrect check to determine if the library libgpiod declares the line request flags: GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN The names above are declared by the library inside an enum, thus cannot be used by the C preprocessor in a #ifdef. Determine in configure if the version of libgpiod provides the line request flags for "bias" and define a C macro. Use the new macro in the driver code. Change-Id: Iaa452230f4753fce4c6e9daa254299cedb7cab7f Signed-off-by: Antonio Borneo <bor...@gm...> Fixes: 290eac04b93c ("drivers/linuxgpiod: Migrate to adapter gpio commands") Reviewed-on: https://review.openocd.org/c/openocd/+/8186 Tested-by: jenkins Reviewed-by: Michael Heimpold <mic...@gm...> diff --git a/configure.ac b/configure.ac index fd7b64d15..761384837 100644 --- a/configure.ac +++ b/configure.ac @@ -669,7 +669,11 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [use_libgpiod=yes], [use_libgpiod=no]) +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [ + use_libgpiod=yes + PKG_CHECK_EXISTS([libgpiod >= 1.5], + [AC_DEFINE([HAVE_LIBGPIOD1_FLAGS_BIAS], [1], [define if libgpiod v1 has line request flags bias])]) +], [use_libgpiod=no]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 942883788..3ca452357 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -320,12 +320,12 @@ static int helper_get_line(enum adapter_gpio_config_index idx) switch (adapter_gpio_config[idx].pull) { case ADAPTER_GPIO_PULL_NONE: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; #endif break; case ADAPTER_GPIO_PULL_UP: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; #else LOG_WARNING("linuxgpiod: ignoring request for pull-up on %s: not supported by gpiod v%s", @@ -333,7 +333,7 @@ static int helper_get_line(enum adapter_gpio_config_index idx) #endif break; case ADAPTER_GPIO_PULL_DOWN: -#ifdef GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; #else LOG_WARNING("linuxgpiod: ignoring request for pull-down on %s: not supported by gpiod v%s", ----------------------------------------------------------------------- Summary of changes: configure.ac | 6 +++++- src/jtag/drivers/linuxgpiod.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-04-07 19:35:50
|
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 74e7fcb2dd96c09f946bc8b0f59bfdf6215d8873 (commit) from 329e983ee9bb24bfa49c59c949d5da250506b7f4 (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 74e7fcb2dd96c09f946bc8b0f59bfdf6215d8873 Author: Antonio Borneo <bor...@gm...> Date: Sun Mar 24 15:53:33 2024 +0100 configure: prevent build of linuxgpiod with libgpiod v2 The API in libgpiod v2 have changed, and current driver code for linuxgpiod does not build anymore. Prevent building the current driver linuxgpiod with the new library. Change-Id: Ie673db786dc50ae18a263d2c0a2b46b106866450 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8185 Reviewed-by: Michael Heimpold <mic...@gm...> Tested-by: jenkins Reviewed-by: Tomas Vanek <va...@fb...> diff --git a/configure.ac b/configure.ac index c9cf0214e..fd7b64d15 100644 --- a/configure.ac +++ b/configure.ac @@ -669,7 +669,7 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [use_libgpiod=yes], [use_libgpiod=no]) +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [use_libgpiod=yes], [use_libgpiod=no]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) ----------------------------------------------------------------------- Summary of changes: configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-04-07 13:46:43
|
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 329e983ee9bb24bfa49c59c949d5da250506b7f4 (commit) from dd1758272276e20d5b60c16146a820ec8b5bfaa1 (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 329e983ee9bb24bfa49c59c949d5da250506b7f4 Author: Dominik Wernberger <dom...@gm...> Date: Tue Mar 26 20:32:22 2024 +0100 zynq_7000.cfg: Fix issue 'Error: can't read "zynq_pl": no such variable' Change-Id: Ic79ce114b60d0707a6e082a81743b378b164b4e2 Signed-off-by: Dominik Wernberger <dom...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8190 Reviewed-by: Daniel Anselmi <dan...@gm...> Reviewed-by: Tomas Vanek <va...@fb...> Tested-by: jenkins diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg index f5b4478ff..5a88b6e9d 100644 --- a/tcl/target/zynq_7000.cfg +++ b/tcl/target/zynq_7000.cfg @@ -47,7 +47,7 @@ ${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit" ${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit" pld create zynq_pl.pld virtex2 -chain-position zynq_pl.bs -no_jstart -virtex2 set_user_codes $zynq_pl.pld 0x02 0x03 0x22 0x23 +virtex2 set_user_codes zynq_pl.pld 0x02 0x03 0x22 0x23 set XC7_JSHUTDOWN 0x0d set XC7_JPROGRAM 0x0b ----------------------------------------------------------------------- Summary of changes: tcl/target/zynq_7000.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-04-01 05:52: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 dd1758272276e20d5b60c16146a820ec8b5bfaa1 (commit) from a35e254c5383008cdacf7838a777f7f17af5eeb1 (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 dd1758272276e20d5b60c16146a820ec8b5bfaa1 Author: Steven Chang <st...@en...> Date: Sun Feb 11 21:34:50 2024 +0800 flash/nor/eneispif: support ENE KB1200 ispi flash Change-Id: I03bccceb1956ee121e6a3728b7d647ef1262fa23 Signed-off-by: Steven Chang <st...@en...> Reviewed-on: https://review.openocd.org/c/openocd/+/8136 Tested-by: jenkins Reviewed-by: Tomas Vanek <va...@fb...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 6b71fe869..52a51c196 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6776,6 +6776,24 @@ Note that in order for this command to take effect, the target needs to be reset supported.} @end deffn +@deffn {Flash Driver} {eneispif} +All versions of the KB1200 microcontrollers from ENE include internal +flash. The eneispif flash driver supports the KB1200 family of devices. The driver +automatically recognizes the specific version's flash parameters and +autoconfigures itself. The flash bank starts at address 0x60000000. An optional additional +parameter sets the address of eneispif controller, with the default address is 0x50101000. + +@example + +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME \ + 0x50101000 + +# Address defaults to 0x50101000 +flash bank $_FLASHNAME eneispif 0x60000000 0 0 0 $_TARGETNAME + +@end example +@end deffn + @deffn {Flash Driver} {esirisc} Members of the eSi-RISC family may optionally include internal flash programmed via the eSi-TSMC Flash interface. Additional parameters are required to diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 534a7a804..afa11e7d4 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -28,6 +28,7 @@ NOR_DRIVERS = \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ + %D%/eneispif.c \ %D%/esirisc_flash.c \ %D%/faux.c \ %D%/fespi.c \ diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index a63b72c8f..7d6f8c5cc 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -256,6 +256,7 @@ extern const struct flash_driver cfi_flash; extern const struct flash_driver dsp5680xx_flash; extern const struct flash_driver efm32_flash; extern const struct flash_driver em357_flash; +extern const struct flash_driver eneispif_flash; extern const struct flash_driver esirisc_flash; extern const struct flash_driver faux_flash; extern const struct flash_driver fespi_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3157bd329..34359889a 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -33,6 +33,7 @@ static const struct flash_driver * const flash_drivers[] = { &dsp5680xx_flash, &efm32_flash, &em357_flash, + &eneispif_flash, &esirisc_flash, &faux_flash, &fm3_flash, diff --git a/src/flash/nor/eneispif.c b/src/flash/nor/eneispif.c new file mode 100644 index 000000000..6572b8c25 --- /dev/null +++ b/src/flash/nor/eneispif.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (c) 2024 ENE Technology Inc. + * st...@en... +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/time_support.h> +#include <helper/bits.h> +#include <target/target.h> +#include <flash/nor/core.h> +#include <flash/nor/driver.h> +#include <flash/nor/spi.h> + +#define ISPICFG 0x0000 +#define ISPISTS 0x0004 +#define ISPIADDR 0x0008 +#define ISPICMD 0x000C +#define ISPIDAT 0x0100 + +#define ISPISTS_BUSY BIT(0) +#define STATUS1_QE BIT(1) + +#define CFG_READ 0x372 +#define CFG_WRITE 0x371 + +#define ISPI_CTRL_BASE 0x50101000 + +/* name read qread page erase chip device_id page erase flash + * _cmd _cmd _prog _cmd* _erase size size* size + * _cmd _cmd + */ +struct flash_device ene_flash_device = + FLASH_ID("ISPI flash", 0x03, 0x00, 0x02, 0x20, 0x60, 0x00132085, 0x100, 0x1000, 0x80000); + +struct eneispif_flash_bank { + bool probed; + target_addr_t ctrl_base; + uint32_t dev_id; + const struct flash_device *dev; +}; + +FLASH_BANK_COMMAND_HANDLER(eneispif_flash_bank_command) +{ + struct eneispif_flash_bank *eneispif_info; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + eneispif_info = malloc(sizeof(struct eneispif_flash_bank)); + if (!eneispif_info) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + bank->driver_priv = eneispif_info; + eneispif_info->probed = false; + eneispif_info->ctrl_base = ISPI_CTRL_BASE; + if (CMD_ARGC >= 7) { + COMMAND_PARSE_ADDRESS(CMD_ARGV[6], eneispif_info->ctrl_base); + LOG_INFO("ASSUMING ISPI device at ctrl_base = " TARGET_ADDR_FMT, + eneispif_info->ctrl_base); + } + + return ERROR_OK; +} + +static int eneispif_read_reg(struct flash_bank *bank, uint32_t *value, target_addr_t address) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + int result = target_read_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error at " TARGET_ADDR_FMT, __func__, + eneispif_info->ctrl_base + address); + return result; + } + LOG_DEBUG("Read address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, *value); + return ERROR_OK; +} + +static int eneispif_write_reg(struct flash_bank *bank, target_addr_t address, uint32_t value) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + LOG_DEBUG("Write address " TARGET_ADDR_FMT " = 0x%" PRIx32, + eneispif_info->ctrl_base + address, value); + int result = target_write_u32(target, eneispif_info->ctrl_base + address, value); + if (result != ERROR_OK) { + LOG_ERROR("%s error writing 0x%" PRIx32 " to " TARGET_ADDR_FMT, __func__, + value, eneispif_info->ctrl_base + address); + return result; + } + return ERROR_OK; +} + +static int eneispif_wait(struct flash_bank *bank) +{ + int64_t start = timeval_ms(); + + while (1) { + uint32_t status; + + if (eneispif_read_reg(bank, &status, ISPISTS) != ERROR_OK) + return ERROR_FAIL; + + if (!(status & ISPISTS_BUSY)) + break; + + int64_t now = timeval_ms(); + if (now - start > 1000) { + LOG_ERROR("Busy more than 1000ms."); + return ERROR_TARGET_TIMEOUT; + } + } + + return ERROR_OK; +} + +static int eneispi_erase_sector(struct flash_bank *bank, int sector) +{ + int retval = ERROR_OK; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t offset; + uint32_t conf; + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + offset = bank->sectors[sector].offset; + retval = eneispif_write_reg(bank, ISPIADDR, offset); /* Address */ + if (retval != ERROR_OK) + goto done; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + retval = eneispif_write_reg(bank, ISPICMD, eneispif_info->dev->erase_cmd); /* Erase page */ + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + +done: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +static int eneispif_erase(struct flash_bank *bank, unsigned int first, unsigned int last) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + int retval = ERROR_OK; + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (last < first || last >= bank->num_sectors) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + if (!(eneispif_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + for (unsigned int sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + if (eneispif_info->dev->erase_cmd == 0x00) + return ERROR_FLASH_OPER_UNSUPPORTED; + + for (unsigned int sector = first; sector <= last; sector++) { + retval = eneispi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + } + + return retval; +} + +static int eneispif_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last) +{ + for (unsigned int sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + return ERROR_OK; +} + +static int eneispif_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, + uint32_t count) +{ + struct target *target = bank->target; + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + uint32_t page_size; + uint32_t conf; + int retval = ERROR_OK; + + LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32, bank->size, offset, + count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > eneispif_info->dev->size_in_bytes) { + LOG_WARNING("Write past end of flash. Extra data discarded."); + count = eneispif_info->dev->size_in_bytes - offset; + } + + /* Check sector protection */ + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && + ((offset + count - 1) >= bank->sectors[sector].offset) && + bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FAIL; + } + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); // Cmmmand enable + + /* If no valid page_size, use reasonable default. */ + page_size = + eneispif_info->dev->pagesize ? eneispif_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE; + uint32_t page_offset = offset % page_size; + + while (count > 0) { + uint32_t cur_count; + + /* clip block at page boundary */ + if (page_offset + count > page_size) + cur_count = page_size - page_offset; + else + cur_count = count; + + eneispif_write_reg(bank, ISPICMD, SPIFLASH_WRITE_ENABLE); /* Write enable */ + target_write_buffer(target, eneispif_info->ctrl_base + ISPIDAT, cur_count, buffer); + eneispif_write_reg(bank, ISPIADDR, offset); + retval = eneispif_write_reg(bank, ISPICMD, + (cur_count << 16) | eneispif_info->dev->pprog_cmd); + if (retval != ERROR_OK) + goto err; + + page_offset = 0; + buffer += cur_count; + offset += cur_count; + count -= cur_count; + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto err; + } + +err: + eneispif_write_reg(bank, ISPICFG, conf); /* restore */ + return retval; +} + +/* Return ID of flash device */ +/* On exit, SW mode is kept */ +static int eneispif_read_flash_id(struct flash_bank *bank, uint32_t *id) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct target *target = bank->target; + int retval; + uint32_t conf, value; + uint8_t buffer[4]; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = eneispif_read_reg(bank, &conf, ISPICFG); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("ISPCFG = (0x%08" PRIx32 ")", conf); + + /* read ID from Receive Register */ + eneispif_write_reg(bank, ISPICFG, CFG_WRITE); /* Cmmmand enable */ + retval = eneispif_write_reg(bank, ISPICMD, (3 << 16) | SPIFLASH_READ_ID); + if (retval != ERROR_OK) + goto done; + + retval = eneispif_wait(bank); + if (retval != ERROR_OK) + goto done; + + retval = target_read_buffer(target, eneispif_info->ctrl_base + ISPIDAT, 3, buffer); + if (retval != ERROR_OK) + goto done; + value = (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; + LOG_DEBUG("ISPDAT = (0x%08" PRIx32 ")", value); + + *id = value; +done: + eneispif_write_reg(bank, ISPICFG, conf); // restore + return retval; +} + +static int eneispif_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + struct flash_sector *sectors; + uint32_t id; + int retval; + uint32_t sectorsize; + + if (eneispif_info->probed) + free(bank->sectors); + + eneispif_info->probed = false; + + LOG_INFO("Assuming ISPI flash at address " TARGET_ADDR_FMT + " with controller at " TARGET_ADDR_FMT, + bank->base, eneispif_info->ctrl_base); + + eneispif_write_reg(bank, ISPICFG, CFG_READ); /* RAM map enable */ + + retval = eneispif_read_flash_id(bank, &id); + if (retval != ERROR_OK) + return retval; + + eneispif_info->dev_id = id; + eneispif_info->dev = &ene_flash_device; + + LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", eneispif_info->dev->name, + eneispif_info->dev_id); + + /* Set correct size value */ + bank->size = eneispif_info->dev->size_in_bytes; + + if (bank->size <= (1UL << 16)) + LOG_WARNING("device needs 2-byte addresses - not implemented"); + + /* if no sectors, treat whole bank as single sector */ + sectorsize = eneispif_info->dev->sectorsize ? eneispif_info->dev->sectorsize + : eneispif_info->dev->size_in_bytes; + + /* create and fill sectors array */ + bank->num_sectors = eneispif_info->dev->size_in_bytes / sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (!sectors) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * sectorsize; + sectors[sector].size = sectorsize; + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + eneispif_info->probed = true; + return ERROR_OK; +} + +static int eneispif_auto_probe(struct flash_bank *bank) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + if (eneispif_info->probed) + return ERROR_OK; + return eneispif_probe(bank); +} + +static int eneispif_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int get_eneispif_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct eneispif_flash_bank *eneispif_info = bank->driver_priv; + + if (!(eneispif_info->probed)) { + command_print(cmd, "ENE ISPI flash bank not probed yet."); + return ERROR_OK; + } + + command_print(cmd, + "ENE ISPI flash information:\n" + " Device \'%s\' (ID 0x%08" PRIx32 ")", + eneispif_info->dev->name, eneispif_info->dev_id); + + return ERROR_OK; +} + +const struct flash_driver eneispif_flash = { + .name = "eneispif", + .usage = "flash bank <name> 'eneispif' <base_address> <size> 0 0 <target> <ctrl_base>", + .flash_bank_command = eneispif_flash_bank_command, + .erase = eneispif_erase, + .protect = eneispif_protect, + .write = eneispif_write, + .read = default_flash_read, + .probe = eneispif_probe, + .auto_probe = eneispif_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = eneispif_protect_check, + .info = get_eneispif_info, + .free_driver_priv = default_flash_free_driver_priv, +}; ----------------------------------------------------------------------- Summary of changes: doc/openocd.texi | 18 ++ src/flash/nor/Makefile.am | 1 + src/flash/nor/driver.h | 1 + src/flash/nor/drivers.c | 1 + src/flash/nor/eneispif.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 454 insertions(+) create mode 100644 src/flash/nor/eneispif.c hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-24 13:42: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 a35e254c5383008cdacf7838a777f7f17af5eeb1 (commit) from c02cf9404dc9dba2a6bc60c4db65c0287168a338 (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 a35e254c5383008cdacf7838a777f7f17af5eeb1 Author: Tomas Vanek <va...@fb...> Date: Fri Feb 16 17:17:05 2024 +0100 target/adi_v5_swd: move setting of do_reconnect one level up Move setting of do_reconnect flag from swd_run_inner() to swd_run(). Reconnect is not used at the inner level and the flag had to be cleared after swd_run_inner() to prevent recursion. Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: Ib1de80bbdf10d1cbfb1dd351c6a5658e50d12af2 Reviewed-on: https://review.openocd.org/c/openocd/+/8155 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 67706f35b..123100588 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -84,16 +84,8 @@ static void swd_clear_sticky_errors(struct adiv5_dap *dap) static int swd_run_inner(struct adiv5_dap *dap) { const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - int retval; - - retval = swd->run(); - - if (retval != ERROR_OK) { - /* fault response */ - dap->do_reconnect = true; - } - return retval; + return swd->run(); } static inline int check_sync(struct adiv5_dap *dap) @@ -288,15 +280,15 @@ static int swd_multidrop_select(struct adiv5_dap *dap) swd_multidrop_selected_dap = NULL; if (retry > 3) { LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap)); + dap->do_reconnect = true; return retval; } LOG_DEBUG("Failed to select multidrop %s, retrying...", adiv5_dap_name(dap)); - /* we going to retry localy, do not ask for full reconnect */ - dap->do_reconnect = false; } + dap->do_reconnect = false; return retval; } @@ -635,7 +627,13 @@ static int swd_run(struct adiv5_dap *dap) swd_finish_read(dap); - return swd_run_inner(dap); + retval = swd_run_inner(dap); + if (retval != ERROR_OK) { + /* fault response */ + dap->do_reconnect = true; + } + + return retval; } /** Put the SWJ-DP back to JTAG mode */ ----------------------------------------------------------------------- Summary of changes: src/target/adi_v5_swd.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-24 13:41:32
|
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 c02cf9404dc9dba2a6bc60c4db65c0287168a338 (commit) via a213afad09e50402be8d02298f48757ff4e2e1cf (commit) from 35e4c4616f5a924313e85290f56f84f7a8534801 (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 c02cf9404dc9dba2a6bc60c4db65c0287168a338 Author: Antonio Borneo <bor...@gm...> Date: Sat Mar 9 18:12:36 2024 +0100 helper/list: include the correct header file The file 'list.h', copied from FreeBSD, does not depend from any OpenOCD specific include file, but only needs 'stddef.h' for the type 'size_t'. Let 'list.h' to include the correct header file, then fix the now broken dependencies in the other files that were incorrectly relying on 'list.h' to include 'helper/types.h' Change-Id: Idd31b5bf607e226cac44ef41b2aa335ae4dbf519 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8173 Tested-by: jenkins diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h index a8a5ef8f3..344629681 100644 --- a/src/helper/binarybuffer.h +++ b/src/helper/binarybuffer.h @@ -11,7 +11,8 @@ #ifndef OPENOCD_HELPER_BINARYBUFFER_H #define OPENOCD_HELPER_BINARYBUFFER_H -#include "list.h" +#include <helper/list.h> +#include <helper/types.h> /** @file * Support functions to access arbitrary bits in a byte array diff --git a/src/helper/list.h b/src/helper/list.h index eb8858e74..47290c260 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -35,7 +35,7 @@ /* begin OpenOCD changes */ -#include <helper/types.h> +#include <stddef.h> struct list_head { struct list_head *next; diff --git a/src/target/target.h b/src/target/target.h index 1713448ce..d5c0e0e8c 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -23,6 +23,7 @@ #include <helper/list.h> #include "helper/replacements.h" #include "helper/system.h" +#include <helper/types.h> #include <jim.h> struct reg; commit a213afad09e50402be8d02298f48757ff4e2e1cf Author: Antonio Borneo <bor...@gm...> Date: Sat Mar 9 17:53:16 2024 +0100 helper/list: Replace Linux code with FreeBSD one The file list.h was originally taken from the Linux kernel code, thus under license GPL-2.0-only. This locks OpenOCD to follow the same license, even if the majority of OpenOCD files are licensed as GPL-2.0-or-later. A similar file is also present in FreeBSD code base under the more permissive license BSD-2-Clause. Drop the code from Linux kernel and replace it with the code from FreeBSD 13.3.0. Adapt the code to OpenOCD coding style by fixing the majority of issues identified by checkpatch. Add the OpenOCD specific macros and comments. Unfortunately this causes the lost of all the doxygen comments. Checkpatch-ignore: MACRO_ARG_REUSE, MACRO_ARG_PRECEDENCE Change-Id: I6d86752c50158f3174c4e8c4add81e9998d01e0e Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8172 Tested-by: jenkins diff --git a/src/helper/list.h b/src/helper/list.h index c9de0569b..eb8858e74 100644 --- a/src/helper/list.h +++ b/src/helper/list.h @@ -1,15 +1,31 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-License-Identifier: BSD-2-Clause */ /* - * The content of this file is mainly copied/inspired from Linux kernel - * code in include/linux/list.h, include/linux/types.h - * Last aligned with kernel v5.12: - * - skip the functions hlist_unhashed_lockless() and __list_del_clearprev() - * that are relevant only in kernel; - * - Remove non-standard GCC extension "omitted conditional operand" from - * list_prepare_entry; - * - expand READ_ONCE, WRITE_ONCE, smp_load_acquire, smp_store_release; - * - make comments compatible with doxygen. + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. + * Copyright (c) 2021-2024 by Antonio Borneo <bor...@gm...> + * All rights reserved. + */ + +/* + * Circular doubly linked list implementation. + * + * The content of this file is mainly copied/inspired from FreeBSD code in: + * https://cgit.freebsd.org/src/tree/ + * files: + * sys/compat/linuxkpi/common/include/linux/list.h + * sys/compat/linuxkpi/common/include/linux/types.h + * + * Last aligned with release/13.3.0: + * + * - Skip 'hlist_*' double linked lists with a single pointer list head. + * - Expand WRITE_ONCE(). + * - Use TAB for indentation. + * - Put macro arguments within parenthesis. + * - Remove blank lines after an open brace '{'. + * - Remove multiple assignment. * * There is an example of using this file in contrib/list_example.c. */ @@ -17,155 +33,64 @@ #ifndef OPENOCD_HELPER_LIST_H #define OPENOCD_HELPER_LIST_H -/* begin local changes */ -#include <helper/types.h> +/* begin OpenOCD changes */ -#define LIST_POISON1 NULL -#define LIST_POISON2 NULL +#include <helper/types.h> struct list_head { - struct list_head *next, *prev; + struct list_head *next; + struct list_head *prev; }; -/* end local changes */ - -/* - * Circular doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ +/* end OpenOCD changes */ #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) -/** - * INIT_LIST_HEAD - Initialize a list_head structure - * @param list list_head structure to be initialized. - * - * Initializes the list_head to point to itself. If it is a list header, - * the result is an empty list. - */ -static inline void INIT_LIST_HEAD(struct list_head *list) +static inline void +INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } -#ifdef CONFIG_DEBUG_LIST -extern bool __list_add_valid(struct list_head *new, - struct list_head *prev, - struct list_head *next); -extern bool __list_del_entry_valid(struct list_head *entry); -#else -static inline bool __list_add_valid(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - return true; -} -static inline bool __list_del_entry_valid(struct list_head *entry) +static inline int +list_empty(const struct list_head *head) { - return true; + return (head->next == head); } -#endif -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - if (!__list_add_valid(new, prev, next)) - return; - - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @param new new entry to be added - * @param head list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) +static inline int +list_empty_careful(const struct list_head *head) { - __list_add(new, head, head->next); -} - + struct list_head *next = head->next; -/** - * list_add_tail - add a new entry - * @param new new entry to be added - * @param head list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); + return ((next == head) && (next == head->prev)); } -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) +static inline void +__list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } -/* Ignore kernel __list_del_clearprev() */ - -static inline void __list_del_entry(struct list_head *entry) +static inline void +__list_del_entry(struct list_head *entry) { - if (!__list_del_entry_valid(entry)) - return; - __list_del(entry->prev, entry->next); } -/** - * list_del - deletes entry from list. - * @param entry the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) +static inline void +list_del(struct list_head *entry) { - __list_del_entry(entry); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; + __list_del(entry->prev, entry->next); } -/** - * list_replace - replace old entry by new one - * @param old the element to be replaced - * @param new the new element to insert - * - * If @a old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) +static inline void +list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; @@ -173,205 +98,189 @@ static inline void list_replace(struct list_head *old, new->prev->next = new; } -/** - * list_replace_init - replace old entry by new one and initialize the old one - * @param old the element to be replaced - * @param new the new element to insert - * - * If @a old was empty, it will be overwritten. - */ -static inline void list_replace_init(struct list_head *old, - struct list_head *new) +static inline void +list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } -/** - * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position - * @param entry1 the location to place entry2 - * @param entry2 the location to place entry1 - */ -static inline void list_swap(struct list_head *entry1, - struct list_head *entry2) +static inline void +linux_list_add(struct list_head *new, struct list_head *prev, + struct list_head *next) { - struct list_head *pos = entry2->prev; - - list_del(entry2); - list_replace(entry1, entry2); - if (pos == entry1) - pos = entry2; - list_add(entry1, pos); + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } -/** - * list_del_init - deletes entry from list and reinitialize it. - * @param entry the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) +static inline void +list_del_init(struct list_head *entry) { - __list_del_entry(entry); + list_del(entry); INIT_LIST_HEAD(entry); } -/** - * list_move - delete from one list and add as another's head - * @param list the entry to move - * @param head the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) +#define list_entry(ptr, type, field) container_of(ptr, type, field) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +#define list_next_entry(ptr, member) \ + list_entry(((ptr)->member.next), typeof(*(ptr)), member) + +#define list_safe_reset_next(ptr, n, member) \ + (n) = list_next_entry(ptr, member) + +#define list_prev_entry(ptr, member) \ + list_entry(((ptr)->member.prev), typeof(*(ptr)), member) + +#define list_for_each(p, head) \ + for (p = (head)->next; p != (head); p = (p)->next) + +#define list_for_each_safe(p, n, head) \ + for (p = (head)->next, n = (p)->next; p != (head); p = n, n = (p)->next) + +#define list_for_each_entry(p, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.next, typeof(*p), field)) + +#define list_for_each_entry_safe(p, n, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field), \ + n = list_entry((p)->field.next, typeof(*p), field); &(p)->field != (h);\ + p = n, n = list_entry(n->field.next, typeof(*n), field)) + +#define list_for_each_entry_from(p, h, field) \ + for ( ; &(p)->field != (h); \ + p = list_entry((p)->field.next, typeof(*p), field)) + +#define list_for_each_entry_continue(p, h, field) \ + for (p = list_next_entry((p), field); &(p)->field != (h); \ + p = list_next_entry((p), field)) + +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_entry((pos)->member.next, typeof(*pos), member); \ + &(pos)->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#define list_for_each_entry_reverse(p, h, field) \ + for (p = list_entry((h)->prev, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.prev, typeof(*p), field)) + +#define list_for_each_entry_safe_reverse(p, n, h, field) \ + for (p = list_entry((h)->prev, typeof(*p), field), \ + n = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \ + p = n, n = list_entry(n->field.prev, typeof(*n), field)) + +#define list_for_each_entry_continue_reverse(p, h, field) \ + for (p = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \ + p = list_entry((p)->field.prev, typeof(*p), field)) + +#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev) + +#define list_for_each_entry_from_reverse(p, h, field) \ + for (; &p->field != (h); \ + p = list_prev_entry(p, field)) + +static inline void +list_add(struct list_head *new, struct list_head *head) { - __list_del_entry(list); - list_add(list, head); + linux_list_add(new, head, head->next); } -/** - * list_move_tail - delete from one list and add as another's tail - * @param list the entry to move - * @param head the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) +static inline void +list_add_tail(struct list_head *new, struct list_head *head) { - __list_del_entry(list); - list_add_tail(list, head); + linux_list_add(new, head->prev, head); } -/** - * list_bulk_move_tail - move a subsection of a list to its tail - * @param head the head that will follow our entry - * @param first the first entry to move - * @param last the last entry to move, can be the same as first - * - * Move all entries between @a first and including @a last before @a head. - * All three entries must belong to the same linked list. - */ -static inline void list_bulk_move_tail(struct list_head *head, - struct list_head *first, - struct list_head *last) +static inline void +list_move(struct list_head *list, struct list_head *head) { - first->prev->next = last->next; - last->next->prev = first->prev; - - head->prev->next = first; - first->prev = head->prev; - - last->next = head; - head->prev = last; + list_del(list); + list_add(list, head); } -/** - * list_is_first -- tests whether @a list is the first entry in list @a 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 void +list_move_tail(struct list_head *entry, struct list_head *head) { - return list->prev == head; + list_del(entry); + list_add_tail(entry, head); } -/** - * list_is_last - tests whether @a list is the last entry in list @a head - * @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 void +list_rotate_to_front(struct list_head *entry, struct list_head *head) { - return list->next == head; + list_move_tail(entry, 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) +static inline void +list_bulk_move_tail(struct list_head *head, struct list_head *first, + struct list_head *last) { - return list == head; + first->prev->next = last->next; + last->next->prev = first->prev; + head->prev->next = first; + first->prev = head->prev; + last->next = head; + head->prev = last; } -/** - * list_empty - tests whether a list is empty - * @param head the list to test. - */ -static inline int list_empty(const struct list_head *head) +static inline void +linux_list_splice(const struct list_head *list, struct list_head *prev, + struct list_head *next) { - return head->next == head; + struct list_head *first; + struct list_head *last; + + if (list_empty(list)) + return; + first = list->next; + last = list->prev; + first->prev = prev; + prev->next = first; + last->next = next; + next->prev = last; } -/** - * list_del_init_careful - deletes entry from list and reinitialize it. - * @param entry the element to delete from the list. - * - * This is the same as list_del_init(), except designed to be used - * together with list_empty_careful() in a way to guarantee ordering - * of other memory operations. - * - * Any memory operations done before a list_del_init_careful() are - * guaranteed to be visible after a list_empty_careful() test. - */ -static inline void list_del_init_careful(struct list_head *entry) +static inline void +list_splice(const struct list_head *list, struct list_head *head) { - __list_del_entry(entry); - entry->prev = entry; - entry->next = entry; + linux_list_splice(list, head, head->next); } -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @param head the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) +static inline void +list_splice_tail(struct list_head *list, struct list_head *head) { - struct list_head *next = head->next; - return (next == head) && (next == head->prev); + linux_list_splice(list, head->prev, head); } -/** - * list_rotate_left - rotate the list to the left - * @param head the head of the list - */ -static inline void list_rotate_left(struct list_head *head) +static inline void +list_splice_init(struct list_head *list, struct list_head *head) { - struct list_head *first; - - if (!list_empty(head)) { - first = head->next; - list_move_tail(first, head); - } + linux_list_splice(list, head, head->next); + INIT_LIST_HEAD(list); } -/** - * list_rotate_to_front() - Rotate list to specific item. - * @param list The desired new front of the list. - * @param head The head of the list. - * - * Rotates list so that @a list becomes the new front of the list. - */ -static inline void list_rotate_to_front(struct list_head *list, - struct list_head *head) +static inline void +list_splice_tail_init(struct list_head *list, struct list_head *head) { - /* - * Deletes the list head from the list denoted by @a head and - * places it as the tail of @a list, this effectively rotates the - * list so that @a list is at the front. - */ - list_move_tail(head, list); + linux_list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); } -/** - * list_is_singular - tests whether a list has just one entry. - * @param head the list to test. +/* + * Double linked lists with a single pointer list head. + * IGNORED */ + static inline int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); @@ -389,472 +298,79 @@ static inline void __list_cut_position(struct list_head *list, new_first->prev = head; } -/** - * list_cut_position - cut a list into two - * @param list a new list to add all removed entries - * @param head a list with entries - * @param entry an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @a head, up to and - * including @a entry, from @a head to @a list. You should - * pass on @a entry an element you know is on @a head. @a list - * should be an empty list or a list you do not care about - * losing its data. - * - */ static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { if (list_empty(head)) return; - if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next)) + if (list_is_singular(head) && + (head->next != entry && head != entry)) return; - if (list_is_head(entry, head)) + if (entry == head) INIT_LIST_HEAD(list); else __list_cut_position(list, head, entry); } -/** - * list_cut_before - cut a list into two, before given entry - * @param list a new list to add all removed entries - * @param head a list with entries - * @param entry an entry within head, could be the head itself - * - * This helper moves the initial part of @a head, up to but - * excluding @a entry, from @a head to @a list. You should pass - * in @a entry an element you know is on @a head. @a list should - * be an empty list or a list you do not care about losing - * its data. - * If @a entry == @a head, all entries on @a head are moved to - * @a list. - */ -static inline void list_cut_before(struct list_head *list, - struct list_head *head, - struct list_head *entry) +static inline int list_is_first(const struct list_head *list, + const struct list_head *head) { - if (head->next == entry) { - INIT_LIST_HEAD(list); - return; - } - list->next = head->next; - list->next->prev = list; - list->prev = entry->prev; - list->prev->next = list; - head->next = entry; - entry->prev = head; + return (list->prev == head); } -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) { - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @param list the new list to add. - * @param head the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); + return list->next == head; } -/** - * list_splice_tail - join two lists, each list being a queue - * @param list the new list to add. - * @param head the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) +static inline size_t +list_count_nodes(const struct list_head *list) { - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} + const struct list_head *lh; + size_t count; -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @param list the new list to add. - * @param head the place to add it in the first list. - * - * The list at @a list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); + count = 0; + list_for_each(lh, list) { + count++; } -} -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @param list the new list to add. - * @param head the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @a list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } + return (count); } -/** - * list_entry - get the struct for this entry - * @param ptr the &struct list_head pointer. - * @param type the type of the struct this is embedded in. - * @param member the name of the list_head within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @param ptr the list head to take the element from. - * @param type the type of the struct this is embedded in. - * @param member the name of the list_head within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_last_entry - get the last element from a list - * @param ptr the list head to take the element from. - * @param type the type of the struct this is embedded in. - * @param member the name of the list_head within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_last_entry(ptr, type, member) \ - list_entry((ptr)->prev, type, member) - -/** - * list_first_entry_or_null - get the first element from a list - * @param ptr the list head to take the element from. - * @param type the type of the struct this is embedded in. - * @param member the name of the list_head within the struct. - * - * Note that if the list is empty, it returns NULL. - */ -#define list_first_entry_or_null(ptr, type, member) ({ \ - struct list_head *head__ = (ptr); \ - struct list_head *pos__ = head__->next; \ - pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ -}) - -/** - * list_next_entry - get the next element in list - * @param pos the type * to cursor - * @param member the name of the list_head within the struct. - */ -#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 - * @param member the name of the list_head within the struct. - */ -#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; !list_is_head(pos, (head)); pos = pos->next) - -/* Ignore kernel list_for_each_rcu() */ - -/** - * list_for_each_continue - continue iteration over a list - * @param pos the &struct list_head to use as a loop cursor. - * @param head the head for your list. - * - * Continue to iterate over a list, continuing after the current position. +/* + * Double linked lists with a single pointer list head. + * IGNORED */ -#define list_for_each_continue(pos, head) \ - for (pos = pos->next; pos != (head); pos = pos->next) -/** - * list_for_each_prev - iterate over a list backwards - * @param pos the &struct list_head to use as a loop cursor. - * @param head the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); pos = pos->prev) +/* begin OpenOCD extensions */ /** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @param pos the &struct list_head to use as a loop cursor. - * @param n another &struct list_head to use as temporary storage - * @param head the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @param pos the &struct list_head to use as a loop cursor. - * @param n another &struct list_head to use as temporary storage - * @param head the head for your list. + * list_for_each_entry_direction - iterate forward/backward over list of given type + * @param is_fwd the iterate direction, true for forward, false for backward. + * @param p the type * to use as a loop cursor. + * @param h the head of the list. + * @param field the name of the list_head within the struct. */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) +#define list_for_each_entry_direction(is_fwd, p, h, field) \ + for (p = list_entry(is_fwd ? (h)->next : (h)->prev, typeof(*p), field); \ + &(p)->field != (h); \ + p = list_entry(is_fwd ? (p)->field.next : (p)->field.prev, typeof(*p), field)) /** - * list_count_nodes - count nodes in the list - * @param head the head for your list. + * list_rotate_left - rotate the list to the left + * @param h the head of the list */ -static inline size_t list_count_nodes(struct list_head *head) +static inline void list_rotate_left(struct list_head *h) { - struct list_head *pos; - size_t count = 0; - - list_for_each(pos, head) - count++; + struct list_head *first; - return count; + if (!list_empty(h)) { + first = h->next; + list_move_tail(first, h); + } } -/** - * list_entry_is_head - test if the entry points to the head of the list - * @param pos the type * to cursor - * @param head the head for your list. - * @param member the name of the list_head within the struct. - */ -#define list_entry_is_head(pos, head, member) \ - (&pos->member == (head)) - -/** - * list_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 list_head within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member); \ - !list_entry_is_head(pos, head, member); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_reverse - iterate backwards 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 list_head within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_last_entry(head, typeof(*pos), member); \ - !list_entry_is_head(pos, head, member); \ - pos = list_prev_entry(pos, member)) - -/** - * list_for_each_entry_direction - iterate forward/backward over list of given type - * @param forward the iterate direction, true for forward, false for backward. - * @param pos the type * to use as a loop cursor. - * @param head the head for your list. - * @param member the name of the list_head within the struct. - */ -#define list_for_each_entry_direction(forward, pos, head, member) \ - for (pos = forward ? list_first_entry(head, typeof(*pos), member) \ - : list_last_entry(head, typeof(*pos), member); \ - !list_entry_is_head(pos, head, member); \ - pos = forward ? list_next_entry(pos, member) \ - : list_prev_entry(pos, member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @param pos the type * to use as a start point - * @param head the head of the list - * @param member the name of the list_head within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? (pos) : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration 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 list_head within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_next_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @param pos the type * to use as a loop cursor. - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_prev_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = list_prev_entry(pos, member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @param pos the type * to use as a loop cursor. - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; !list_entry_is_head(pos, head, member); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_from_reverse - iterate backwards over list of given type - * from the current point - * @param pos the type * to use as a loop cursor. - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Iterate backwards over list of given type, continuing from current position. - */ -#define list_for_each_entry_from_reverse(pos, head, member) \ - for (; !list_entry_is_head(pos, head, member); \ - pos = list_prev_entry(pos, member)) - -/** - * list_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 another type * to use as temporary storage - * @param head the head for your list. - * @param member the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member), \ - n = list_next_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_continue - continue list iteration safe against removal - * @param pos the type * to use as a loop cursor. - * @param n another type * to use as temporary storage - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_next_entry(pos, member), \ - n = list_next_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_from - iterate over list from current point safe against removal - * @param pos the type * to use as a loop cursor. - * @param n another type * to use as temporary storage - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_next_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal - * @param pos the type * to use as a loop cursor. - * @param n another type * to use as temporary storage - * @param head the head for your list. - * @param member the name of the list_head within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_last_entry(head, typeof(*pos), member), \ - n = list_prev_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = n, n = list_prev_entry(n, member)) - -/** - * list_safe_reset_next - reset a stale list_for_each_entry_safe loop - * @param pos the loop cursor used in the list_for_each_entry_safe loop - * @param n temporary storage used in list_for_each_entry_safe - * @param member the name of the list_head within the struct. - * - * list_safe_reset_next is not safe to use in general if the list may be - * modified concurrently (eg. the lock is dropped in the loop body). An - * exception to this is if the cursor element (pos) is pinned in the list, - * and list_safe_reset_next is called after re-taking the lock and before - * completing the current iteration of the loop body. - */ -#define list_safe_reset_next(pos, n, member) \ - n = list_next_entry(pos, member) - -/* - * Double linked lists with a single pointer list head. - * IGNORED - */ +/* end OpenOCD extensions */ #endif /* OPENOCD_HELPER_LIST_H */ ----------------------------------------------------------------------- Summary of changes: src/helper/binarybuffer.h | 3 +- src/helper/list.h | 934 +++++++++++----------------------------------- src/target/target.h | 1 + 3 files changed, 228 insertions(+), 710 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-24 13:40:44
|
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 35e4c4616f5a924313e85290f56f84f7a8534801 (commit) via 0c0243228cb958b7c12c2e5a81c84d35734fce25 (commit) from 01a797af143398c6f3aa1eb6f8949deff4ccf044 (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 35e4c4616f5a924313e85290f56f84f7a8534801 Author: Antonio Borneo <bor...@gm...> Date: Sun Feb 25 23:03:27 2024 +0100 gdb_server: drop useless check in gdb_keep_client_alive() OpenOCD can send it's log to gdb, and gdb replies with 'OK'. Calls to LOG_XXX() are also present in the code that communicates with gdb. This can cause infinite nested calls. OpenOCD uses the flag 'gdb_con->busy' to protect the communication with gdb and prevent nested calls. There is no reason to check for 'gdb_con->busy' in the code for keep-alive, as keep_alive() is never called in this gdb server; the flag would eventually be set if the current keep_alive() will send something to gdb. Drop the flag 'gdb_con->busy' in gdb_keep_client_alive(). While there, document the use of 'gdb_con->busy'. Change-Id: I1ea20bf96abb5d2f1fcdba1e3861df257c396bb6 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8166 Tested-by: jenkins diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 00e43cfe9..c1ee4aa2a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -73,6 +73,8 @@ struct gdb_connection { enum target_state frontend_state; struct image *vflash_image; bool closed; + /* set to prevent re-entrance from log messages during gdb_get_packet() + * and gdb_put_packet(). */ bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. @@ -3794,11 +3796,6 @@ static void gdb_keep_client_alive(struct connection *connection) { struct gdb_connection *gdb_con = connection->priv; - if (gdb_con->busy) { - /* do not send packets, retry asap */ - return; - } - switch (gdb_con->output_flag) { case GDB_OUTPUT_NO: /* no need for keep-alive */ commit 0c0243228cb958b7c12c2e5a81c84d35734fce25 Author: Antonio Borneo <bor...@gm...> Date: Sun Feb 25 22:55:35 2024 +0100 gdb_server: add async-notif keep-alive during memory read/write To avoid gdb to timeout, OpenOCD implements a keep-alive mechanism that consists in sending periodically to gdb empty strings embedded in the "O" remote reply packet. The main purpose of "O" packets is to forward in the gdb console the output of the remote execution; the gdb-remote puts in the "O" packet the string that gdb will print. It's use is restricted to few "running/execution" contexts listed in http://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html and this currently limits the keep-alive capabilities of OpenOCD. Long data transfer (memory R/W) can also cause gdb to timeout if the interface is too slow. In this case the usual keep-alive based on "O" packet cannot be used and, if used, would trigger a protocol error that causes the transfer to be dropped. The slow transfer rate can be simulated by adding some delay in the main loop of mem_ap_write() and mem_ap_read(), then using the gdb commands "dump" and "restore". In the wait loop during a memory R/W, gdb drops any extra character received from the gdb-remote that is not recognized as a valid reply to the memory command. Every dropped character re-initializes the timeout counter and could be used as keep-alive. From gdb 7.0 (released 2009-10-06), an asynchronous notification can also be received from gdb-remote during a memory R/W and has the effect to reset the timeout counter, thus can be used as keep-alive. The notification would be treated as "junk" extra characters by any gdb older than 7.0, being still valid as keep-alive. Check putpkt_binary() and getpkt_sane() in gdb commit 74531fed1f2d662debc2c209b8b3faddceb55960 Currently, only one notification packet ("Stop") is recognized by gdb, and gdb documentation reports that notification packets that are not recognized should be silently dropped. Use 'set debug remote 1' in gdb to dump the received notifications and the junk extra characters. Add a new level in enum gdb_output_flag for using the asynchronous notifications. Activate this new level during memory transfers. Send a custom "oocd_keepalive" notification packet as keep_alive. While there, drop a useless return in the switch/case, already managed in case of break. After this commit, the proper calls to keep_alive() have to be added in the loops that code the memory transfers. Of course, the keep_alive() should be placed during the wait for JTAG flush, not while locally queuing the JTAG elementary transfers. Change-Id: I9ca8e78630611597d15984bd0e8634c8fc3c32b9 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8165 Tested-by: jenkins diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index ae288de1c..00e43cfe9 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -53,6 +53,8 @@ enum gdb_output_flag { /* GDB doesn't accept 'O' packets */ GDB_OUTPUT_NO, + /* GDB doesn't accept 'O' packets but accepts notifications */ + GDB_OUTPUT_NOTIF, /* GDB accepts 'O' packets */ GDB_OUTPUT_ALL, }; @@ -1486,9 +1488,6 @@ static int gdb_error(struct connection *connection, int retval) return ERROR_OK; } -/* We don't have to worry about the default 2 second timeout for GDB packets, - * because GDB breaks up large memory reads into smaller reads. - */ static int gdb_read_memory_packet(struct connection *connection, char const *packet, int packet_size) { @@ -3477,7 +3476,7 @@ static void gdb_log_callback(void *priv, const char *file, unsigned line, struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; - if (gdb_con->output_flag == GDB_OUTPUT_NO) + if (gdb_con->output_flag != GDB_OUTPUT_ALL) /* No out allowed */ return; @@ -3562,10 +3561,14 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_read_memory_packet(connection, packet, packet_size); + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'M': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_write_memory_packet(connection, packet, packet_size); + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'z': case 'Z': @@ -3656,9 +3659,9 @@ static int gdb_input_inner(struct connection *connection) retval = gdb_detach(connection); break; case 'X': + gdb_con->output_flag = GDB_OUTPUT_NOTIF; retval = gdb_write_memory_binary_packet(connection, packet, packet_size); - if (retval != ERROR_OK) - return retval; + gdb_con->output_flag = GDB_OUTPUT_NO; break; case 'k': if (gdb_con->extended_protocol) { @@ -3754,6 +3757,39 @@ static int gdb_input(struct connection *connection) return ERROR_OK; } +/* + * Send custom notification packet as keep-alive during memory read/write. + * + * From gdb 7.0 (released 2009-10-06) an unknown notification received during + * memory read/write would be silently dropped. + * Before gdb 7.0 any character, with exclusion of "+-$", would be considered + * as junk and ignored. + * In both cases the reception will reset the timeout counter in gdb, thus + * working as a keep-alive. + * Check putpkt_binary() and getpkt_sane() in gdb commit + * 74531fed1f2d662debc2c209b8b3faddceb55960 + * + * Enable remote debug in gdb with 'set debug remote 1' to either dump the junk + * characters in gdb pre-7.0 and the notification from gdb 7.0. + */ +static void gdb_async_notif(struct connection *connection) +{ + static unsigned char count; + unsigned char checksum = 0; + char buf[22]; + + int len = sprintf(buf, "%%oocd_keepalive:%2.2x", count++); + for (int i = 1; i < len; i++) + checksum += buf[i]; + len += sprintf(buf + len, "#%2.2x", checksum); + +#ifdef _DEBUG_GDB_IO_ + LOG_DEBUG("sending packet '%s'", buf); +#endif + + gdb_write(connection, buf, len); +} + static void gdb_keep_client_alive(struct connection *connection) { struct gdb_connection *gdb_con = connection->priv; @@ -3767,6 +3803,10 @@ static void gdb_keep_client_alive(struct connection *connection) case GDB_OUTPUT_NO: /* no need for keep-alive */ break; + case GDB_OUTPUT_NOTIF: + /* send asynchronous notification */ + gdb_async_notif(connection); + break; case GDB_OUTPUT_ALL: /* send an empty O packet */ gdb_output_con(connection, ""); ----------------------------------------------------------------------- Summary of changes: src/server/gdb_server.c | 59 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 11 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:47:43
|
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 01a797af143398c6f3aa1eb6f8949deff4ccf044 (commit) from a88db9b1211ea71b5795b91d11d94fb0f37cc905 (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 01a797af143398c6f3aa1eb6f8949deff4ccf044 Author: Walter Ji <wal...@os...> Date: Fri Nov 17 16:46:55 2023 +0800 target/mips32: add fpu access support Add access to fpr and cp1 registers. GDB can now check the FPRs with `info reg f` and change them. Checkpatch-ignore: MACRO_ARG_REUSE Change-Id: I63896ab6f6737054d8108db105a13a58e1446fbc Signed-off-by: Walter Ji <wal...@os...> Reviewed-on: https://review.openocd.org/c/openocd/+/7866 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/mips32.c b/src/target/mips32.c index ec2bfb7d0..6bbf71bd8 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -262,6 +262,61 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_OK; } +/** + * mips32_set_all_fpr_width - Set the width of all floating-point registers + * @param[in] mips32: MIPS32 common structure + * @param[in] fp64: Flag indicating whether to set the width to 64 bits (double precision) + * + * @brief Sets the width of all floating-point registers based on the specified flag. + */ +static void mips32_set_all_fpr_width(struct mips32_common *mips32, bool fp64) +{ + struct reg_cache *cache = mips32->core_cache; + struct reg *reg_list = cache->reg_list; + int i; + + for (i = MIPS32_REGLIST_FP_INDEX; i < (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT); i++) { + reg_list[i].size = fp64 ? 64 : 32; + reg_list[i].reg_data_type->type = fp64 ? REG_TYPE_IEEE_DOUBLE : REG_TYPE_IEEE_SINGLE; + } +} + +/** + * mips32_detect_fpr_mode_change - Detect changes in floating-point register mode + * @param[in] mips32: MIPS32 common structure + * @param[in] cp0_status: Value of the CP0 status register + * + * @brief Detects changes in the floating-point register mode based on the CP0 status register. + * If changes are detected, it updates the internal state + * and logs a warning message indicating the mode change. + */ +static void mips32_detect_fpr_mode_change(struct mips32_common *mips32, uint32_t cp0_status) +{ + if (!mips32->fp_imp) + return; + + /* CP0.Status.FR indicates the working mode of floating-point register. + * When FP = 0, fpr can contain any 32bit data type, + * 64bit data types are stored in even-odd register pairs. + * When FP = 1, fpr can contain any data types.*/ + bool fpu_in_64bit = ((cp0_status & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0); + + /* CP0.Status.CU1 indicated whether CoProcessor1(which is FPU) is present. */ + bool fp_enabled = ((cp0_status & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0); + + if (mips32->fpu_in_64bit != fpu_in_64bit) { + mips32->fpu_in_64bit = fpu_in_64bit; + mips32_set_all_fpr_width(mips32, fpu_in_64bit); + LOG_WARNING("** FP mode changed to %sbit, you must reconnect GDB **", fpu_in_64bit ? "64" : "32"); + } + + if (mips32->fpu_enabled != fp_enabled) { + mips32->fpu_enabled = fp_enabled; + const char *s = fp_enabled ? "enabled" : "disabled"; + LOG_WARNING("** FP is %s, register update %s **", s, s); + } +} + static int mips32_read_core_reg(struct target *target, unsigned int num) { unsigned int cnum; @@ -278,6 +333,8 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) cnum = num - MIPS32_REGLIST_C0_INDEX; reg_value = mips32->core_regs.cp0[cnum]; buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + if (cnum == MIPS32_REG_C0_STATUS_INDEX) + mips32_detect_fpr_mode_change(mips32, reg_value); } else if (num >= MIPS32_REGLIST_FPC_INDEX) { /* FPCR */ cnum = num - MIPS32_REGLIST_FPC_INDEX; @@ -319,6 +376,8 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) cnum = num - MIPS32_REGLIST_C0_INDEX; reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); mips32->core_regs.cp0[cnum] = (uint32_t)reg_value; + if (cnum == MIPS32_REG_C0_STATUS_INDEX) + mips32_detect_fpr_mode_change(mips32, reg_value); } else if (num >= MIPS32_REGLIST_FPC_INDEX) { /* FPCR */ cnum = num - MIPS32_REGLIST_FPC_INDEX; @@ -987,8 +1046,8 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta mips32->fp_imp = MIPS32_FP_IMP_NONE; return ERROR_OK; } - uint32_t status_value; - bool status_fr, status_cu1; + uint32_t fir_value, status_value; + bool fpu_in_64bit, fp_enabled; retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); if (retval != ERROR_OK) { @@ -996,20 +1055,34 @@ static int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejta return retval; } - status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; - status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; - if (status_cu1) { - /* TODO: read fpu(cp1) config register for current operating mode. - * Now its set to 32 bits by default. */ - snprintf(buf, sizeof(buf), "yes"); - fp_imp = MIPS32_FP_IMP_32; + fpu_in_64bit = (status_value & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0; + fp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0; + if (fp_enabled) { + retval = mips32_cp1_control_read(ejtag_info, &fir_value, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp1 FIR register"); + return retval; + } + + if ((fir_value >> MIPS32_CP1_FIR_F64_SHIFT) & 0x1) + fp_imp++; } else { + /* This is the only condition that writes to buf */ snprintf(buf, sizeof(buf), "yes, disabled"); fp_imp = MIPS32_FP_IMP_UNKNOWN; } - mips32->fpu_in_64bit = status_fr; - mips32->fpu_enabled = status_cu1; + mips32->fpu_in_64bit = fpu_in_64bit; + mips32->fpu_enabled = fp_enabled; + + mips32_set_all_fpr_width(mips32, fpu_in_64bit); + + /* If fpu is not disabled, print out more information */ + if (!buf[0]) + snprintf(buf, sizeof(buf), "yes, %sbit (%s, working in %sbit)", + fp_imp == MIPS32_FP_IMP_64 ? "64" : "32", + fp_enabled ? "enabled" : "disabled", + fpu_in_64bit ? "64" : "32"); LOG_USER("FPU implemented: %s", buf); mips32->fp_imp = fp_imp; diff --git a/src/target/mips32.h b/src/target/mips32.h index d512e4970..a557f3117 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -459,10 +459,13 @@ struct mips32_algorithm { #define MIPS32_OP_AND 0x24u #define MIPS32_OP_CACHE 0x2Fu #define MIPS32_OP_COP0 0x10u +#define MIPS32_OP_COP1 0x11u #define MIPS32_OP_J 0x02u #define MIPS32_OP_JR 0x08u #define MIPS32_OP_LUI 0x0Fu #define MIPS32_OP_LW 0x23u +#define MIPS32_OP_LWC1 0x31u +#define MIPS32_OP_LDC1 0x35u #define MIPS32_OP_LB 0x20u #define MIPS32_OP_LBU 0x24u #define MIPS32_OP_LHU 0x25u @@ -470,6 +473,7 @@ struct mips32_algorithm { #define MIPS32_OP_MTHI 0x11u #define MIPS32_OP_MFLO 0x12u #define MIPS32_OP_MTLO 0x13u +#define MIPS32_OP_MUL 0x02u #define MIPS32_OP_RDHWR 0x3Bu #define MIPS32_OP_SB 0x28u #define MIPS32_OP_SH 0x29u @@ -485,6 +489,8 @@ struct mips32_algorithm { #define MIPS32_OP_SLLV 0x04u #define MIPS32_OP_SLTI 0x0Au #define MIPS32_OP_MOVN 0x0Bu +#define MIPS32_OP_SWC1 0x39u +#define MIPS32_OP_SDC1 0x3Du #define MIPS32_OP_REGIMM 0x01u #define MIPS32_OP_SDBBP 0x3Fu @@ -517,6 +523,7 @@ struct mips32_algorithm { #define MIPS32_ISA_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) #define MIPS32_ISA_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) #define MIPS32_ISA_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) +#define MIPS32_ISA_CFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_CF, gpr, cpr, 0, 0) #define MIPS32_ISA_J(tar) MIPS32_J_INST(MIPS32_OP_J, (0x0FFFFFFFu & (tar)) >> 2) #define MIPS32_ISA_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) #define MIPS32_ISA_JRHB(reg) MIPS32_R_INST(0, reg, 0, 0, 0x10, MIPS32_OP_JR) @@ -526,9 +533,15 @@ struct mips32_algorithm { #define MIPS32_ISA_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) #define MIPS32_ISA_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) #define MIPS32_ISA_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) +#define MIPS32_ISA_LWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LWC1, base, reg, off) +#define MIPS32_ISA_LDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_LDC1, base, reg, off) #define MIPS32_ISA_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MF, gpr, cpr, 0, sel) #define MIPS32_ISA_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP_MT, gpr, cpr, 0, sel) +#define MIPS32_ISA_MFC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MF, gpr, cpr, 0, 0) +#define MIPS32_ISA_MFHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MFH, gpr, cpr, 0, 0) +#define MIPS32_ISA_MTC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MT, gpr, cpr, 0, 0) +#define MIPS32_ISA_MTHC1(gpr, cpr) MIPS32_R_INST(MIPS32_OP_COP1, MIPS32_COP_MTH, gpr, cpr, 0, 0) #define MIPS32_ISA_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) #define MIPS32_ISA_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) #define MIPS32_ISA_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) @@ -542,6 +555,8 @@ struct mips32_algorithm { #define MIPS32_ISA_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) #define MIPS32_ISA_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) #define MIPS32_ISA_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) +#define MIPS32_ISA_SWC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SWC1, base, reg, off) +#define MIPS32_ISA_SDC1(reg, off, base) MIPS32_I_INST(MIPS32_OP_SDC1, base, reg, off) #define MIPS32_ISA_SLL(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLL) #define MIPS32_ISA_SLLV(dst, src, sa) MIPS32_R_INST(MIPS32_OP_SPECIAL, 0, src, dst, sa, MIPS32_OP_SLLV) @@ -588,6 +603,7 @@ struct mips32_algorithm { #define MMIPS32_OP_BGTZ 0x06u #define MMIPS32_OP_BNE 0x2Du #define MMIPS32_OP_CACHE 0x06u +#define MMIPS32_OP_CFC1 0x40u #define MMIPS32_OP_J 0x35u #define MMIPS32_OP_JALR 0x03Cu #define MMIPS32_OP_JALRHB 0x07Cu @@ -596,8 +612,14 @@ struct mips32_algorithm { #define MMIPS32_OP_LHU 0x0Du #define MMIPS32_OP_LUI 0x0Du #define MMIPS32_OP_LW 0x3Fu +#define MMIPS32_OP_LWC1 0x27u +#define MMIPS32_OP_LDC1 0x2Fu #define MMIPS32_OP_MFC0 0x03u +#define MMIPS32_OP_MFC1 0x80u +#define MMIPS32_OP_MFHC1 0xC0u #define MMIPS32_OP_MTC0 0x0Bu +#define MMIPS32_OP_MTC1 0xA0u +#define MMIPS32_OP_MTHC1 0xE0u #define MMIPS32_OP_MFLO 0x075u #define MMIPS32_OP_MFHI 0x035u #define MMIPS32_OP_MTLO 0x0F5u @@ -608,6 +630,8 @@ struct mips32_algorithm { #define MMIPS32_OP_SB 0x06u #define MMIPS32_OP_SH 0x0Eu #define MMIPS32_OP_SW 0x3Eu +#define MMIPS32_OP_SWC1 0x26u +#define MMIPS32_OP_SDC1 0x2Eu #define MMIPS32_OP_SLTU 0x390u #define MMIPS32_OP_SLL 0x000u #define MMIPS32_OP_SLTI 0x24u @@ -627,6 +651,7 @@ struct mips32_algorithm { #define MMIPS32_BGTZ(reg, off) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_BGTZ, reg, off) #define MMIPS32_BNE(src, tar, off) MIPS32_I_INST(MMIPS32_OP_BNE, tar, src, off) #define MMIPS32_CACHE(op, off, base) MIPS32_R_INST(MMIPS32_POOL32B, op, base, MMIPS32_OP_CACHE << 1, 0, off) +#define MMIPS32_CFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_CFC1, MMIPS32_POOL32FXF) #define MMIPS32_J(tar) MIPS32_J_INST(MMIPS32_OP_J, ((0x07FFFFFFu & ((tar) >> 1)))) #define MMIPS32_JR(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_JALR, MMIPS32_POOL32AXF) @@ -636,13 +661,19 @@ struct mips32_algorithm { #define MMIPS32_LHU(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LHU, reg, base, off) #define MMIPS32_LUI(reg, val) MIPS32_I_INST(MMIPS32_POOL32I, MMIPS32_OP_LUI, reg, val) #define MMIPS32_LW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LW, reg, base, off) +#define MMIPS32_LWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LWC1, reg, base, off) +#define MMIPS32_LDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_LDC1, reg, base, off) #define MMIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\ MMIPS32_OP_MFC0, MMIPS32_POOL32AXF) +#define MMIPS32_MFC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFC1, MMIPS32_POOL32FXF) +#define MMIPS32_MFHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MFHC1, MMIPS32_POOL32FXF) #define MMIPS32_MFLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFLO, MMIPS32_POOL32AXF) #define MMIPS32_MFHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MFHI, MMIPS32_POOL32AXF) #define MMIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MMIPS32_POOL32A, gpr, cpr, sel,\ MMIPS32_OP_MTC0, MMIPS32_POOL32AXF) +#define MMIPS32_MTC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTC1, MMIPS32_POOL32FXF) +#define MMIPS32_MTHC1(gpr, cpr) MIPS32_R_INST(MMIPS32_POOL32F, gpr, cpr, 0, MMIPS32_OP_MTHC1, MMIPS32_POOL32FXF) #define MMIPS32_MTLO(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTLO, MMIPS32_POOL32AXF) #define MMIPS32_MTHI(reg) MIPS32_R_INST(MMIPS32_POOL32A, 0, reg, 0, MMIPS32_OP_MTHI, MMIPS32_POOL32AXF) @@ -653,6 +684,8 @@ struct mips32_algorithm { #define MMIPS32_SB(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SB, reg, base, off) #define MMIPS32_SH(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SH, reg, base, off) #define MMIPS32_SW(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SW, reg, base, off) +#define MMIPS32_SWC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SWC1, reg, base, off) +#define MMIPS32_SDC1(reg, off, base) MIPS32_I_INST(MMIPS32_OP_SDC1, reg, base, off) #define MMIPS32_SRL(reg, src, off) MIPS32_R_INST(MMIPS32_POOL32A, reg, src, off, 0, MMIPS32_OP_SRL) #define MMIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MMIPS32_POOL32A, tar, src, dst, 0, MMIPS32_OP_SLTU) @@ -686,6 +719,7 @@ struct mips32_algorithm { #define MIPS32_BGTZ(isa, reg, off) (isa ? MMIPS32_BGTZ(reg, off) : MIPS32_ISA_BGTZ(reg, off)) #define MIPS32_BNE(isa, src, tar, off) (isa ? MMIPS32_BNE(src, tar, off) : MIPS32_ISA_BNE(src, tar, off)) #define MIPS32_CACHE(isa, op, off, base) (isa ? MMIPS32_CACHE(op, off, base) : MIPS32_ISA_CACHE(op, off, base)) +#define MIPS32_CFC1(isa, gpr, cpr) (isa ? MMIPS32_CFC1(gpr, cpr) : MIPS32_ISA_CFC1(gpr, cpr)) #define MIPS32_J(isa, tar) (isa ? MMIPS32_J(tar) : MIPS32_ISA_J(tar)) #define MIPS32_JR(isa, reg) (isa ? MMIPS32_JR(reg) : MIPS32_ISA_JR(reg)) @@ -694,10 +728,15 @@ struct mips32_algorithm { #define MIPS32_LBU(isa, reg, off, base) (isa ? MMIPS32_LBU(reg, off, base) : MIPS32_ISA_LBU(reg, off, base)) #define MIPS32_LHU(isa, reg, off, base) (isa ? MMIPS32_LHU(reg, off, base) : MIPS32_ISA_LHU(reg, off, base)) #define MIPS32_LW(isa, reg, off, base) (isa ? MMIPS32_LW(reg, off, base) : MIPS32_ISA_LW(reg, off, base)) +#define MIPS32_LWC1(isa, reg, off, base) (isa ? MMIPS32_LWC1(reg, off, base) : MIPS32_ISA_LWC1(reg, off, base)) #define MIPS32_LUI(isa, reg, val) (isa ? MMIPS32_LUI(reg, val) : MIPS32_ISA_LUI(reg, val)) #define MIPS32_MFC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MFC0(gpr, cpr, sel) : MIPS32_ISA_MFC0(gpr, cpr, sel)) #define MIPS32_MTC0(isa, gpr, cpr, sel) (isa ? MMIPS32_MTC0(gpr, cpr, sel) : MIPS32_ISA_MTC0(gpr, cpr, sel)) +#define MIPS32_MFC1(isa, gpr, cpr) (isa ? MMIPS32_MFC1(gpr, cpr) : MIPS32_ISA_MFC1(gpr, cpr)) +#define MIPS32_MFHC1(isa, gpr, cpr) (isa ? MMIPS32_MFHC1(gpr, cpr) : MIPS32_ISA_MFHC1(gpr, cpr)) +#define MIPS32_MTC1(isa, gpr, cpr) (isa ? MMIPS32_MTC1(gpr, cpr) : MIPS32_ISA_MTC1(gpr, cpr)) +#define MIPS32_MTHC1(isa, gpr, cpr) (isa ? MMIPS32_MTHC1(gpr, cpr) : MIPS32_ISA_MTHC1(gpr, cpr)) #define MIPS32_MFLO(isa, reg) (isa ? MMIPS32_MFLO(reg) : MIPS32_ISA_MFLO(reg)) #define MIPS32_MFHI(isa, reg) (isa ? MMIPS32_MFHI(reg) : MIPS32_ISA_MFHI(reg)) #define MIPS32_MTLO(isa, reg) (isa ? MMIPS32_MTLO(reg) : MIPS32_ISA_MTLO(reg)) @@ -710,6 +749,8 @@ struct mips32_algorithm { #define MIPS32_SB(isa, reg, off, base) (isa ? MMIPS32_SB(reg, off, base) : MIPS32_ISA_SB(reg, off, base)) #define MIPS32_SH(isa, reg, off, base) (isa ? MMIPS32_SH(reg, off, base) : MIPS32_ISA_SH(reg, off, base)) #define MIPS32_SW(isa, reg, off, base) (isa ? MMIPS32_SW(reg, off, base) : MIPS32_ISA_SW(reg, off, base)) +#define MIPS32_SWC1(isa, reg, off, base) (isa ? MMIPS32_SWC1(reg, off, base) : MIPS32_ISA_SWC1(reg, off, base)) +#define MIPS32_SDC1(isa, reg, off, base) (isa ? MMIPS32_SDC1(reg, off, base) : MIPS32_ISA_SDC1(reg, off, base)) #define MIPS32_SLL(isa, dst, src, sa) (isa ? MMIPS32_SLL(dst, src, sa) : MIPS32_ISA_SLL(dst, src, sa)) #define MIPS32_EHB(isa) (isa ? MMIPS32_SLL(0, 0, 3) : MIPS32_ISA_SLL(0, 0, 3)) diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index 22edf6a41..aaf3875fb 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -588,6 +588,26 @@ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_r return ctx.retval; } +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp1_c_reg) +{ + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + pracc_queue_init(&ctx); + + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, cp1_c_reg)); /* move cp1c reg to $8 */ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ + pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 15, 31, 0)); /* restore $15 from DeSave */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); + pracc_queue_free(&ctx); + return ctx.retval; +} + /** * \b mips32_pracc_sync_cache * @@ -856,6 +876,9 @@ int mips32_pracc_write_regs(struct mips32_common *mips32) struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; uint32_t *gprs = mips32->core_regs.gpr; uint32_t *c0rs = mips32->core_regs.cp0; + bool fpu_in_64bit = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0); + bool fp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0); + uint32_t rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; pracc_queue_init(&ctx); @@ -895,6 +918,31 @@ int mips32_pracc_write_regs(struct mips32_common *mips32) if (mips32_cpu_support_hazard_barrier(ejtag_info)) pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + + /* store FPRs */ + if (mips32->fp_imp && fp_enabled) { + uint64_t *fprs = mips32->core_regs.fpr; + if (fpu_in_64bit) { + for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) { + uint32_t fp_lo = fprs[i] & 0xffffffff; + uint32_t fp_hi = (fprs[i] >> 32) & 0xffffffff; + pracc_add_li32(&ctx, 2, fp_lo, 0); + pracc_add_li32(&ctx, 3, fp_hi, 0); + pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i)); + pracc_add(&ctx, 0, MIPS32_MTHC1(ctx.isa, 3, i)); + } + } else { + for (int i = 0; i != MIPS32_REG_FP_COUNT; i++) { + uint32_t fp_lo = fprs[i] & 0xffffffff; + pracc_add_li32(&ctx, 2, fp_lo, 0); + pracc_add(&ctx, 0, MIPS32_MTC1(ctx.isa, 2, i)); + } + } + + if (rel > MIPS32_RELEASE_1) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + } + /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) pracc_add_li32(&ctx, i, gprs[i], 1); @@ -1014,6 +1062,9 @@ int mips32_pracc_read_regs(struct mips32_common *mips32) struct mips32_core_regs *core_regs = &mips32->core_regs; unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs; unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs; + unsigned int offset_fpr = ((uint8_t *)&core_regs->fpr[0]) - (uint8_t *)core_regs; + unsigned int offset_fpcr = ((uint8_t *)&core_regs->fpcr[0]) - (uint8_t *)core_regs; + bool fp_enabled; /* * This procedure has to be in 2 distinctive steps, because we can @@ -1040,11 +1091,64 @@ int mips32_pracc_read_regs(struct mips32_common *mips32) ejtag_info->reg8 = mips32->core_regs.gpr[8]; ejtag_info->reg9 = mips32->core_regs.gpr[9]; + if (ctx.retval != ERROR_OK) + return ctx.retval; + /* we only care if FP is actually impl'd and if cp1 is enabled */ /* since we already read cp0 in the prev step */ /* now we know what's in cp0.status */ - /* TODO: Read FPRs */ + fp_enabled = (mips32->core_regs.cp0[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0; + if (mips32->fp_imp && fp_enabled) { + pracc_queue_init(&ctx); + mips32_pracc_store_regs_set_base_addr(&ctx); + + /* FCSR */ + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 31)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr, 1)); + + /* FIR */ + pracc_add(&ctx, 0, MIPS32_CFC1(ctx.isa, 8, 0)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_fpcr + 4, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_fpcr + 4, 1)); + + /* f0 to f31 */ + if (mips32->fpu_in_64bit) { + for (int i = 0; i != 32; i++) { + size_t offset = offset_fpr + (i * 8); + /* current pracc implementation (or EJTAG itself) only supports 32b access */ + /* so there is no way to use SDC1 */ + + /* lower half */ + pracc_add(&ctx, 0, MIPS32_MFC1(ctx.isa, 8, i)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset, 1)); + + /* upper half */ + pracc_add(&ctx, 0, MIPS32_MFHC1(ctx.isa, 8, i)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset + 4, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset + 4, 1)); + } + } else { + for (int i = 0; i != 32; i++) { + size_t offset = offset_fpr + (i * 8); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SWC1(ctx.isa, i, PRACC_OUT_OFFSET + offset, 1)); + } + } + + mips32_pracc_store_regs_restore(&ctx); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1); + + pracc_queue_free(&ctx); + } return ctx.retval; } diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 78d087213..f78f89153 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -103,6 +103,21 @@ int mips32_cp0_read(struct mips_ejtag *ejtag_info, int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); +/** + * mips32_cp1_control_read + * + * @brief Simulates cfc1 ASM instruction (Move Control Word From Floating Point), + * i.e. implements copro C1 Control Register read. + * + * @param[in] ejtag_info + * @param[in] val Storage to hold read value + * @param[in] cp1_c_reg Number of copro C1 control register we want to read + * + * @return ERROR_OK on Success, ERROR_FAIL otherwise + */ +int mips32_cp1_control_read(struct mips_ejtag *ejtag_info, + uint32_t *val, uint32_t cp1_c_reg); + static inline void pracc_swap16_array(struct mips_ejtag *ejtag_info, uint32_t *buf, int count) { if (ejtag_info->isa && ejtag_info->endianness) ----------------------------------------------------------------------- Summary of changes: src/target/mips32.c | 95 ++++++++++++++++++++++++++++++++++++----- src/target/mips32.h | 41 ++++++++++++++++++ src/target/mips32_pracc.c | 106 +++++++++++++++++++++++++++++++++++++++++++++- src/target/mips32_pracc.h | 15 +++++++ 4 files changed, 245 insertions(+), 12 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:45:01
|
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 a88db9b1211ea71b5795b91d11d94fb0f37cc905 (commit) from 7a77355a3ea574dc5b7fc0a6ea8be413589ef847 (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 a88db9b1211ea71b5795b91d11d94fb0f37cc905 Author: Daniel Anselmi <dan...@gm...> Date: Mon Jan 1 16:05:07 2024 +0100 ipdbg: configurable queue size used between JTAG-Host and JTAG-Hub Change-Id: I7941de02a968ccab730bfebd3483b8c3b84d7e53 Signed-off-by: Daniel Anselmi <dan...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/7980 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/doc/openocd.texi b/doc/openocd.texi index 651cc53bb..6b71fe869 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -12198,6 +12198,20 @@ xc7.ipdbghub ipdbg start -port 5555 -tool 0 Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). The TAP and ir value used to reach the JTAG Hub is given by the pld driver. +@deffn {Command} {$hub_name queuing} @option{-size @var{size}} +Configure the queuing between IPDBG JTAG-Host and Hub. +The maximum possible queue size is 1024 which is also the default. + +@itemize @bullet +@item @option{-size @var{size}} max number of transfers in the queue. +@end itemize +@end deffn + +@example +bitbang.ibdbghub queuing -size 32 +@end example +Send a maximum of 32 transfers to the queue before executing them. + @node Utility Commands @chapter Utility Commands diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index e218b8244..e7eb96e13 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -19,20 +19,11 @@ #define IPDBG_MAX_NUM_OF_CREATE_OPTIONS 10 #define IPDBG_NUM_OF_START_OPTIONS 4 #define IPDBG_NUM_OF_STOP_OPTIONS 2 +#define IPDBG_NUM_OF_QUEUE_OPTIONS 2 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6 #define IPDBG_SCRATCH_MEMORY_SIZE 1024 -#define IPDBG_EMPTY_DOWN_TRANSFERS 1024 -#define IPDBG_CONSECUTIVE_UP_TRANSFERS 1024 - -#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_EMPTY_DOWN_TRANSFERS -#error "scratch Memory must be at least IPDBG_EMPTY_DOWN_TRANSFERS" -#endif - -#if IPDBG_SCRATCH_MEMORY_SIZE < IPDBG_CONSECUTIVE_UP_TRANSFERS -#error "scratch Memory must be at least IPDBG_CONSECUTIVE_UP_TRANSFERS" -#endif /* private connection data for IPDBG */ struct ipdbg_fifo { @@ -78,6 +69,7 @@ struct ipdbg_hub { uint32_t tool_mask; uint32_t last_dn_tool; char *name; + size_t using_queue_size; struct ipdbg_hub *next; struct jtag_tap *tap; struct connection **connections; @@ -461,7 +453,7 @@ static int ipdbg_shift_empty_data(struct ipdbg_hub *hub) const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8); memset(hub->scratch_memory.dr_out_vals, 0, dreg_buffer_size); - for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) { + for (size_t i = 0; i < hub->using_queue_size; ++i) { ipdbg_init_scan_field(hub->scratch_memory.fields + i, hub->scratch_memory.dr_in_vals + i * dreg_buffer_size, hub->data_register_length, @@ -473,7 +465,7 @@ static int ipdbg_shift_empty_data(struct ipdbg_hub *hub) if (retval == ERROR_OK) { uint32_t up_data; - for (size_t i = 0; i < IPDBG_EMPTY_DOWN_TRANSFERS; ++i) { + for (size_t i = 0; i < hub->using_queue_size; ++i) { up_data = buf_get_u32(hub->scratch_memory.dr_in_vals + i * dreg_buffer_size, 0, hub->data_register_length); @@ -522,8 +514,8 @@ static int ipdbg_jtag_transfer_bytes(struct ipdbg_hub *hub, return ERROR_FAIL; const size_t dreg_buffer_size = DIV_ROUND_UP(hub->data_register_length, 8); - size_t num_tx = (connection->dn_fifo.count < IPDBG_CONSECUTIVE_UP_TRANSFERS) ? - connection->dn_fifo.count : IPDBG_CONSECUTIVE_UP_TRANSFERS; + size_t num_tx = (connection->dn_fifo.count < hub->using_queue_size) ? + connection->dn_fifo.count : hub->using_queue_size; for (size_t i = 0; i < num_tx; ++i) { uint32_t dn_data = hub->valid_mask | ((tool & hub->tool_mask) << 8) | @@ -906,6 +898,46 @@ static const struct command_registration ipdbg_hostserver_subcommand_handlers[] COMMAND_REGISTRATION_DONE }; +static COMMAND_HELPER(ipdbg_config_queuing, struct ipdbg_hub *hub, unsigned int size) +{ + if (!hub) + return ERROR_FAIL; + + if (hub->active_connections) { + command_print(CMD, "Configuration change not allowed when hub has active connections"); + return ERROR_FAIL; + } + + if (size == 0 || size > IPDBG_SCRATCH_MEMORY_SIZE) { + command_print(CMD, "queuing size out of range! Must be 0 < size <= %d", IPDBG_SCRATCH_MEMORY_SIZE); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + hub->using_queue_size = size; + return ERROR_OK; +} + +COMMAND_HANDLER(handle_ipdbg_cfg_queuing_command) +{ + struct ipdbg_hub *hub = CMD_DATA; + + unsigned int size; + + if (CMD_ARGC != IPDBG_NUM_OF_QUEUE_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-size") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(uint, i, size, "size"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return CALL_COMMAND_HANDLER(ipdbg_config_queuing, hub, size); +} + static const struct command_registration ipdbg_hub_subcommand_handlers[] = { { .name = "ipdbg", @@ -914,6 +946,13 @@ static const struct command_registration ipdbg_hub_subcommand_handlers[] = { .usage = "", .chain = ipdbg_hostserver_subcommand_handlers }, + { + .name = "queuing", + .handler = handle_ipdbg_cfg_queuing_command, + .mode = COMMAND_ANY, + .help = "configures queuing between IPDBG Host and Hub.", + .usage = "-size size", + }, COMMAND_REGISTRATION_DONE }; @@ -960,6 +999,7 @@ static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uin new_hub->last_dn_tool = new_hub->tool_mask; new_hub->virtual_ir = virtual_ir; new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); + new_hub->using_queue_size = IPDBG_SCRATCH_MEMORY_SIZE; int retval = ipdbg_register_hub_command(new_hub, cmd); if (retval != ERROR_OK) { ----------------------------------------------------------------------- Summary of changes: doc/openocd.texi | 14 +++++++++++ src/server/ipdbg.c | 68 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 68 insertions(+), 14 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:44:05
|
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 7a77355a3ea574dc5b7fc0a6ea8be413589ef847 (commit) from 1d076d6ce1908d5c154bfc6ee2ccd8a629853ef1 (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 7a77355a3ea574dc5b7fc0a6ea8be413589ef847 Author: Daniel Anselmi <dan...@gm...> Date: Mon Jan 1 16:05:07 2024 +0100 ipdbg: split ipdbg command into multiple commands To simplify the ipdbg start/stop command and be able to add additional commands in the future, we introduce the concept of a hub which has to be created before a ipdbg server can be started. The hub was created on the fly in previous versions. Change-Id: I55f317542d01a7324990b2cacd496a41fa5ff875 Signed-off-by: Daniel Anselmi <dan...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/7979 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/doc/openocd.texi b/doc/openocd.texi index bf4e0ad65..651cc53bb 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -12116,55 +12116,84 @@ waveform generator. These are synthesize-able hardware descriptions of logic circuits in addition to software for control, visualization and further analysis. In a session using JTAG for its transport protocol, OpenOCD supports the function of a JTAG-Host. The JTAG-Host is needed to connect the circuit over JTAG to the -control-software. For more details see @url{http://ipdbg.org}. +control-software. The JTAG-Hub is the circuit which transfers the data from JTAG to the +different tools connected to the Hub. Hub implementations for most major FPGA vendors/families +are provided. For more details see @url{http://ipdbg.org}. -@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-tap @var{tapname}} @option{-hub @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] [@option{-port @var{number}}] [@option{-tool @var{number}}] -Starts or stops a IPDBG JTAG-Host server. Arguments can be specified in any order. +@deffn {Command} {ipdbg create-hub} @var{hub_name} @option{-tap @var{tapname}} @option{-ir @var{ir_value} [@var{dr_length}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +@deffnx {Command} {ipdbg create-hub} @var{hub_name} @option{-pld @var{pld_name} [@var{user}]} [@option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]}] +Creates a IPDBG JTAG Hub. The created hub is later used to start, stop and configure IPDBG JTAG Host servers. +The first argument @var{hub_name} is the name of the created hub. It can be used later as a reference. + +The pld drivers are able to provide the tap and ir_value for the IPDBG JTAG-Host server. This will be used with the second variant with option @option{-pld}. Command options: @itemize @bullet -@item @option{-start|-stop} starts or stops a IPDBG JTAG-Host server (default: start). +@item @var{hub_name} the name of the IPDBG hub. +This name is also used to create the object's command, referred to here +as @command{$hub_name}, and in other places where the Hub needs to be identified. + @item @option{-tap @var{tapname}} targeting the TAP @var{tapname}. -@item @option{-hub @var{ir_value}} states that the JTAG hub is -reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. -@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given. -@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. -@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} On some devices, the user data-register is reachable if there is a -specific value in a second dr. This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an + +@item @option{-ir @var{ir_value}} states that the JTAG hub is +reachable with dr-scans while the JTAG instruction register has the value @var{ir_value}. Also known as @verb{|USERx|} instructions. +The optional @var{dr_length} is the length of the dr. +Current JTAG-Hub implementation only supports dr_length=13, which is also the default value. + +@item @option{-vir [@var{vir_value} [@var{length} [@var{instr_code}]]]} To support more Hubs than USER registers in a single FPGA it is possible to +use a mechanism known as virtual-ir where the user data-register is reachable if there is a specific value in a second dr. +This second dr is called vir (virtual ir). With this parameter given, the IPDBG satisfies this condition prior an access to the IPDBG-Hub. The value shifted into the vir is given by the first parameter @var{vir_value} (default: 0x11). The second parameter @var{length} is the length of the vir data register (default: 5). With the @var{instr_code} (default: 0x00e) parameter the ir value to shift data through vir can be configured. + +@item @option{-pld @var{pld_name} [@var{user}]} The defined driver for the pld @var{pld_name} is used to get the tap and user instruction. +The pld devices names can be shown by the command @command{pld devices}. With [@var{user}] one can select a different @verb{|USERx|}-Instruction. +If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate. +The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor. +So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. +If your device/vendor is not supported you have to use the first variant. + @end itemize + @end deffn -or -@deffn {Command} {ipdbg} [@option{-start|-stop}] @option{-pld @var{name} [@var{user}]} [@option{-port @var{number}}] [@option{-tool @var{number}}] -Also starts or stops a IPDBG JTAG-Host server. The pld drivers are able to provide the tap and hub/IR for the IPDBG JTAG-Host server. -With the @option{-pld @var{name} [@var{user}]} the information from the pld-driver is used and the options @option{-tap} and @option{-hub} are not required. -The defined driver for the pld @var{name} gets selected. (The pld devices names can be shown by the command @command{pld devices}). -The @verb{|USERx|} instructions are vendor specific and don't change between families of the same vendor. -So if there's a pld driver for your vendor it should work with your FPGA even when the driver is not compatible with your device for the remaining features. If your device/vendor is not supported you have to use the previous command. +@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}} +Starts a IPDBG JTAG-Host server. The remaining arguments can be specified in any order. -With [@var{user}] one can select a different @verb{|USERx|}-Instruction. If the IPDBG JTAG-Hub is used without modification the default value of 1 which selects the first @verb{|USERx|} instruction is adequate. +Command options: +@itemize @bullet +@item @option{-port @var{number}} tcp port number where the JTAG-Host will listen. The default is 4242 which is used when the option is not given. +@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. +@end itemize +@end deffn -The remaining options are described in the previous command. +@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}} +Stops a IPDBG JTAG-Host server. +Command options: +@itemize @bullet +@item @option{-tool @var{number}} number of the tool/feature. These corresponds to the ports "data_(up/down)_(0..6)" at the JtagHub. The default is 1 which is used when the option is not given. +@end itemize @end deffn Examples: @example -ipdbg -start -tap xc6s.tap -hub 0x02 -port 4242 -tool 4 +ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02 +xc6s.ipdbghub ipdbg start -port 4242 -tool 4 @end example -Starts a server listening on tcp-port 4242 which connects to tool 4. +Creates a IPDBG Hub and starts a server listening on tcp-port 4242 which connects to tool 4. The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board). @example -ipdbg -start -tap 10m50.tap -hub 0x00C -vir -port 60000 -tool 1 +ipdbg create-hub max10m50.ipdbghub -tap max10m50.tap -hub 0x00C -vir +max10m50.ipdbghub ipdbg start -tool 1 -port 60000 @end example Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1). The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5). @example -ipdbg -start -pld xc7.pld -port 5555 -tool 0 +ipdbg create-hub xc7.ipdbghub -pld xc7.pld +xc7.ipdbghub ipdbg start -port 5555 -tool 0 @end example Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0). The TAP and ir value used to reach the JTAG Hub is given by the pld driver. diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 4eca67771..41db38e4a 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -1146,4 +1146,132 @@ proc "pld device" {driver tap_name {opt 0}} { } } +lappend _telnet_autocomplete_skip "ipdbg -start" +proc "ipdbg -start" {args} { + echo "DEPRECATED! use 'ipdbg create-hub' and 'chip.ipdbghub ipdbg start ...', not 'ipdbg -start ...'" + set tap_name "" + set pld_name "" + set tool_num "1" + set port_num "4242" + set idx 0 + set num_args [llength $args] + while {$idx < $num_args} { + set arg [lindex $args $idx] + switch -- $arg { + "-tap" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no TAP name given" + return + } + set tap_name [lindex $args $idx] + } + "-pld" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no PLD name given" + return + } + set pld_name [lindex $args $idx] + } + "-tool" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set tool_num [lindex $args [expr {$idx + 1}]] + set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]] + incr num_args -1 + } + set args [lreplace $args $idx $idx] + incr num_args -1 + incr idx -1 + } + "-port" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set port_num [lindex $args [expr {$idx + 1}]] + set args [lreplace $args [expr {$idx + 1}] [expr {$idx + 1}]] + incr num_args -1 + } + set args [lreplace $args $idx $idx] + incr num_args -1 + incr idx -1 + } + "-hub" { + set args [lreplace $args $idx $idx "-ir" ] + } + default { +# don't touch remaining arguments + } + } + incr idx + } + + set hub_name "" + if {$tap_name != ""} { + set hub_name [lindex [split $tap_name .] 0].ipdbghub + } elseif {$pld_name != ""} { + set hub_name [lindex [split $pld_name .] 0].ipdbghub + } else { + echo "parsing arguments failed: no tap and no pld given." + return + } + + echo "name: $hub_name" + echo "ipdbg create-hub $hub_name $args" + + catch {eval ipdbg create-hub $hub_name $args} + + eval $hub_name ipdbg start -tool $tool_num -port $port_num +} + +lappend _telnet_autocomplete_skip "ipdbg -stop" +proc "ipdbg -stop" {args} { + echo "DEPRECATED! use 'chip.ipdbghub ipdbg stop ...', not 'ipdbg -stop ...'" + set tap_name "" + set pld_name "" + set tool_num "1" + set idx 0 + set num_args [llength $args] + while {$idx < $num_args} { + set arg [lindex $args $idx] + switch -- $arg { + "-tap" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no TAP name given" + return + } + set tap_name [lindex $args $idx] + } + "-pld" { + incr idx + if {$idx >= $num_args || [string index [lindex $args $idx] 0] == "-"} { + echo "no PLD name given" + return + } + set pld_name [lindex $args $idx] + } + "-tool" { + if {[expr {$idx + 1}] < $num_args && [string index [lindex $args [expr {$idx + 1}]] 0] != "-"} { + set tool_num [lindex $args [expr {$idx + 1}]] + } + } + default { +# don't touch remaining arguments + } + } + incr idx + } + + set hub_name "" + if {$tap_name != ""} { + set hub_name [lindex [split $tap_name .] 0].ipdbghub + } elseif {$pld_name != ""} { + set hub_name [lindex [split $pld_name .] 0].ipdbghub + } else { + echo "parsing arguments failed: no tap and no pld given." + return + } + + eval $hub_name ipdbg stop -tool $tool_num +} + # END MIGRATION AIDS diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 073323032..e218b8244 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -15,8 +15,10 @@ #include "ipdbg.h" #define IPDBG_BUFFER_SIZE 16384 -#define IPDBG_MIN_NUM_OF_OPTIONS 2 -#define IPDBG_MAX_NUM_OF_OPTIONS 14 +#define IPDBG_MIN_NUM_OF_CREATE_OPTIONS 3 +#define IPDBG_MAX_NUM_OF_CREATE_OPTIONS 10 +#define IPDBG_NUM_OF_START_OPTIONS 4 +#define IPDBG_NUM_OF_STOP_OPTIONS 2 #define IPDBG_MIN_DR_LENGTH 11 #define IPDBG_MAX_DR_LENGTH 13 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6 @@ -75,6 +77,7 @@ struct ipdbg_hub { uint32_t xoff_mask; uint32_t tool_mask; uint32_t last_dn_tool; + char *name; struct ipdbg_hub *next; struct jtag_tap *tap; struct connection **connections; @@ -247,59 +250,27 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub) for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) ; ihub->next = hub; - } else + } else { ipdbg_first_hub = hub; + } } -static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, - struct ipdbg_virtual_ir_info *virtual_ir, struct ipdbg_hub **hub) +static int ipdbg_remove_hub(struct ipdbg_hub *hub) { - *hub = NULL; - struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub)); - if (!new_hub) - goto mem_err_hub; - - const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8); - new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); - - new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); - new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); - new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field)); - new_hub->connections = calloc(new_hub->max_tools, sizeof(struct connection *)); - - if (virtual_ir) - new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8)); - - if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals || - !new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) || - !new_hub->connections) - goto mem_err2; - - if (virtual_ir) - buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value); - - new_hub->tap = tap; - new_hub->user_instruction = user_instruction; - new_hub->data_register_length = data_register_length; - new_hub->valid_mask = BIT(data_register_length - 1); - new_hub->xoff_mask = BIT(data_register_length - 2); - new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8; - new_hub->last_dn_tool = new_hub->tool_mask; - new_hub->virtual_ir = virtual_ir; + if (!ipdbg_first_hub) + return ERROR_FAIL; + if (hub == ipdbg_first_hub) { + ipdbg_first_hub = ipdbg_first_hub->next; + return ERROR_OK; + } - *hub = new_hub; - return ERROR_OK; + for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) { + if (hub == ihub->next) { + ihub->next = hub->next; + return ERROR_OK; + } + } -mem_err2: - free(new_hub->scratch_memory.vir_out_val); - free(new_hub->connections); - free(new_hub->scratch_memory.fields); - free(new_hub->scratch_memory.dr_in_vals); - free(new_hub->scratch_memory.dr_out_vals); - free(new_hub); -mem_err_hub: - free(virtual_ir); - LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -309,6 +280,7 @@ static void ipdbg_free_hub(struct ipdbg_hub *hub) return; free(hub->connections); free(hub->virtual_ir); + free(hub->name); free(hub->scratch_memory.dr_out_vals); free(hub->scratch_memory.dr_in_vals); free(hub->scratch_memory.fields); @@ -316,23 +288,42 @@ static void ipdbg_free_hub(struct ipdbg_hub *hub) free(hub); } -static int ipdbg_remove_hub(struct ipdbg_hub *hub) +static struct ipdbg_hub *ipdbg_allocate_hub(uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, + const char *name) { - if (!ipdbg_first_hub) - return ERROR_FAIL; - if (hub == ipdbg_first_hub) { - ipdbg_first_hub = ipdbg_first_hub->next; - return ERROR_OK; + struct ipdbg_hub *new_hub = calloc(1, sizeof(struct ipdbg_hub)); + if (!new_hub) { + LOG_ERROR("Out of memory"); + return NULL; } - for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) { - if (hub == ihub->next) { - ihub->next = hub->next; - return ERROR_OK; - } + new_hub->name = strdup(name); + if (!new_hub->name) { + free(new_hub); + LOG_ERROR("Out of memory"); + return NULL; } - return ERROR_FAIL; + const size_t dreg_buffer_size = DIV_ROUND_UP(data_register_length, 8); + uint32_t max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); + + new_hub->scratch_memory.dr_out_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); + new_hub->scratch_memory.dr_in_vals = calloc(IPDBG_SCRATCH_MEMORY_SIZE, dreg_buffer_size); + new_hub->scratch_memory.fields = calloc(IPDBG_SCRATCH_MEMORY_SIZE, sizeof(struct scan_field)); + new_hub->connections = calloc(max_tools, sizeof(struct connection *)); + + if (virtual_ir) + new_hub->scratch_memory.vir_out_val = calloc(1, DIV_ROUND_UP(virtual_ir->length, 8)); + + if (!new_hub->scratch_memory.dr_out_vals || !new_hub->scratch_memory.dr_in_vals || + !new_hub->scratch_memory.fields || (virtual_ir && !new_hub->scratch_memory.vir_out_val) || + !new_hub->connections) { + ipdbg_free_hub(new_hub); + LOG_ERROR("Out of memory"); + return NULL; + } + + return new_hub; } static void ipdbg_init_scan_field(struct scan_field *fields, uint8_t *in_value, int num_bits, const uint8_t *out_value) @@ -760,23 +751,62 @@ static const struct service_driver ipdbg_service_driver = { .keep_client_alive_handler = NULL, }; -static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instruction, - uint8_t data_register_length, struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) +static struct ipdbg_hub *ipdbg_get_hub_by_name(const char *name) { - LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool); + struct ipdbg_hub *hub = NULL; + for (hub = ipdbg_first_hub; hub; hub = hub->next) { + if (strcmp(hub->name, name) == 0) + break; + } + return hub; +}; - struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir); - if (hub) { - free(virtual_ir); - if (hub->data_register_length != data_register_length) { - LOG_DEBUG("hub must have the same data_register_length for all tools"); - return ERROR_FAIL; +static int ipdbg_stop_service(struct ipdbg_service *service) +{ + int retval = ipdbg_remove_service(service); + if (retval != ERROR_OK) { + LOG_ERROR("BUG: ipdbg_remove_service failed"); + return retval; + } + + char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; + snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", service->port); + retval = remove_service("ipdbg", port_str_buffer); + /* The ipdbg_service structure is freed by server.c:remove_service(). + There the "priv" pointer is freed.*/ + if (retval != ERROR_OK) { + LOG_ERROR("BUG: remove_service failed"); + return retval; + } + return ERROR_OK; +} + +int ipdbg_server_free(void) +{ + int retval = ERROR_OK; + for (struct ipdbg_hub *hub = ipdbg_first_hub; hub;) { + for (uint8_t tool = 0; tool < hub->max_tools; ++tool) { + struct ipdbg_service *service = ipdbg_find_service(hub, tool); + if (service) { + int new_retval = ipdbg_stop_service(service); + if (new_retval != ERROR_OK) + retval = new_retval; + hub->active_services--; + } } - } else { - int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, &hub); - if (retval != ERROR_OK) - return retval; + struct ipdbg_hub *next_hub = hub->next; + int new_retval = ipdbg_remove_hub(hub); + if (new_retval != ERROR_OK) + retval = new_retval; + ipdbg_free_hub(hub); + hub = next_hub; } + return retval; +} + +static int ipdbg_start(struct ipdbg_hub *hub, uint16_t port, uint8_t tool) +{ + LOG_INFO("starting ipdbg service on port %d for tool %d", port, tool); struct ipdbg_service *service = NULL; int retval = ipdbg_create_service(hub, tool, &service, port); @@ -790,82 +820,181 @@ static int ipdbg_start(uint16_t port, struct jtag_tap *tap, uint32_t user_instru char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", port); retval = add_service(&ipdbg_service_driver, port_str_buffer, 1, service); - if (retval == ERROR_OK) { - ipdbg_add_service(service); - if (hub->active_services == 0 && hub->active_connections == 0) - ipdbg_add_hub(hub); - hub->active_services++; - } else { - if (hub->active_services == 0 && hub->active_connections == 0) - ipdbg_free_hub(hub); + if (retval != ERROR_OK) { free(service); + return retval; } + ipdbg_add_service(service); + hub->active_services++; + return ERROR_OK; +} +COMMAND_HANDLER(handle_ipdbg_start_command) +{ + struct ipdbg_hub *hub = CMD_DATA; + + uint16_t port = 4242; + uint8_t tool = 1; + + if (CMD_ARGC > IPDBG_NUM_OF_START_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-port") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number"); + } else if (strcmp(CMD_ARGV[i], "-tool") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return ipdbg_start(hub, port, tool); +} + +static int ipdbg_stop(struct ipdbg_hub *hub, uint8_t tool) +{ + struct ipdbg_service *service = ipdbg_find_service(hub, tool); + if (!service) { + LOG_ERROR("No service for hub '%s'/tool %d found", hub->name, tool); + return ERROR_FAIL; + } + + int retval = ipdbg_stop_service(service); + hub->active_services--; + + LOG_INFO("stopped ipdbg service for tool %d", tool); return retval; } -static int ipdbg_stop(struct jtag_tap *tap, uint32_t user_instruction, - struct ipdbg_virtual_ir_info *virtual_ir, uint8_t tool) +COMMAND_HANDLER(handle_ipdbg_stop_command) { - struct ipdbg_hub *hub = ipdbg_find_hub(tap, user_instruction, virtual_ir); - free(virtual_ir); - if (!hub) + struct ipdbg_hub *hub = CMD_DATA; + + uint8_t tool = 1; + + if (CMD_ARGC > IPDBG_NUM_OF_STOP_OPTIONS) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (unsigned int i = 0; i < CMD_ARGC; ++i) { + if (strcmp(CMD_ARGV[i], "-tool") == 0) { + COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); + } else { + command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); + return ERROR_FAIL; + } + } + + return ipdbg_stop(hub, tool); +} + +static const struct command_registration ipdbg_hostserver_subcommand_handlers[] = { + { + .name = "start", + .mode = COMMAND_EXEC, + .handler = handle_ipdbg_start_command, + .help = "Starts a IPDBG Host server.", + .usage = "-tool number -port port" + }, { + .name = "stop", + .mode = COMMAND_EXEC, + .handler = handle_ipdbg_stop_command, + .help = "Stops a IPDBG Host server.", + .usage = "-tool number" + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration ipdbg_hub_subcommand_handlers[] = { + { + .name = "ipdbg", + .mode = COMMAND_EXEC, + .help = "IPDBG Hub commands.", + .usage = "", + .chain = ipdbg_hostserver_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +static int ipdbg_register_hub_command(struct ipdbg_hub *hub, struct command_invocation *cmd) +{ + Jim_Interp *interp = CMD_CTX->interp; + + /* does this command exist? */ + Jim_Cmd *jcmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, hub->name, -1), JIM_NONE); + if (jcmd) { + LOG_ERROR("cannot create Hub because a command with name '%s' already exists", hub->name); return ERROR_FAIL; + } - struct ipdbg_service *service = ipdbg_find_service(hub, tool); - if (!service) + const struct command_registration obj_commands[] = { + { + .name = hub->name, + .mode = COMMAND_EXEC, + .help = "IPDBG Hub command group.", + .usage = "", + .chain = ipdbg_hub_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE + }; + + return register_commands_with_data(CMD_CTX, NULL, obj_commands, hub); +} + +static int ipdbg_create_hub(struct jtag_tap *tap, uint32_t user_instruction, uint8_t data_register_length, + struct ipdbg_virtual_ir_info *virtual_ir, const char *name, struct command_invocation *cmd) +{ + struct ipdbg_hub *new_hub = ipdbg_allocate_hub(data_register_length, virtual_ir, name); + if (!new_hub) return ERROR_FAIL; - int retval = ipdbg_remove_service(service); - if (retval != ERROR_OK) { - LOG_ERROR("BUG: ipdbg_remove_service failed"); - return retval; - } + if (virtual_ir) + buf_set_u32(new_hub->scratch_memory.vir_out_val, 0, virtual_ir->length, virtual_ir->value); + new_hub->tap = tap; + new_hub->user_instruction = user_instruction; + new_hub->data_register_length = data_register_length; + new_hub->valid_mask = BIT(data_register_length - 1); + new_hub->xoff_mask = BIT(data_register_length - 2); + new_hub->tool_mask = (new_hub->xoff_mask - 1) >> 8; + new_hub->last_dn_tool = new_hub->tool_mask; + new_hub->virtual_ir = virtual_ir; + new_hub->max_tools = ipdbg_max_tools_from_data_register_length(data_register_length); - char port_str_buffer[IPDBG_TCP_PORT_STR_MAX_LENGTH]; - snprintf(port_str_buffer, IPDBG_TCP_PORT_STR_MAX_LENGTH, "%u", service->port); - retval = remove_service("ipdbg", port_str_buffer); - /* The ipdbg_service structure is freed by server.c:remove_service(). - There the "priv" pointer is freed.*/ + int retval = ipdbg_register_hub_command(new_hub, cmd); if (retval != ERROR_OK) { - LOG_ERROR("BUG: remove_service failed"); - return retval; - } - hub->active_services--; - if (hub->active_connections == 0 && hub->active_services == 0) { - retval = ipdbg_remove_hub(hub); - if (retval != ERROR_OK) { - LOG_ERROR("BUG: ipdbg_remove_hub failed"); - return retval; - } - ipdbg_free_hub(hub); + LOG_ERROR("Creating hub failed"); + ipdbg_free_hub(new_hub); + return ERROR_FAIL; } + + ipdbg_add_hub(new_hub); + return ERROR_OK; } -COMMAND_HANDLER(handle_ipdbg_command) +COMMAND_HANDLER(handle_ipdbg_create_hub_command) { struct jtag_tap *tap = NULL; - uint16_t port = 4242; - uint8_t tool = 1; uint32_t user_instruction = 0x00; uint8_t data_register_length = IPDBG_MAX_DR_LENGTH; - bool start = true; - bool hub_configured = false; bool has_virtual_ir = false; uint32_t virtual_ir_instruction = 0x00e; uint32_t virtual_ir_length = 5; uint32_t virtual_ir_value = 0x11; struct ipdbg_virtual_ir_info *virtual_ir = NULL; int user_num = 1; + bool hub_configured = false; - if ((CMD_ARGC < IPDBG_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > IPDBG_MAX_NUM_OF_OPTIONS)) + if (CMD_ARGC < IPDBG_MIN_NUM_OF_CREATE_OPTIONS || CMD_ARGC > IPDBG_MAX_NUM_OF_CREATE_OPTIONS) return ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned int i = 0; i < CMD_ARGC; ++i) { + const char *hub_name = CMD_ARGV[0]; + + for (unsigned int i = 1; i < CMD_ARGC; ++i) { if (strcmp(CMD_ARGV[i], "-tap") == 0) { if (i + 1 >= CMD_ARGC || CMD_ARGV[i + 1][0] == '-') { - command_print(CMD, "no TAP given"); + command_print(CMD, "no TAP name given"); return ERROR_FAIL; } tap = jtag_tap_by_string(CMD_ARGV[i + 1]); @@ -874,7 +1003,7 @@ COMMAND_HANDLER(handle_ipdbg_command) return ERROR_FAIL; } ++i; - } else if (strcmp(CMD_ARGV[i], "-hub") == 0) { + } else if (strcmp(CMD_ARGV[i], "-ir") == 0) { COMMAND_PARSE_ADDITIONAL_NUMBER(u32, i, user_instruction, "ir_value to select hub"); hub_configured = true; COMMAND_PARSE_OPTIONAL_NUMBER(u8, i, data_register_length); @@ -917,20 +1046,11 @@ COMMAND_HANDLER(handle_ipdbg_command) COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_length); COMMAND_PARSE_OPTIONAL_NUMBER(u32, i, virtual_ir_instruction); has_virtual_ir = true; - } else if (strcmp(CMD_ARGV[i], "-port") == 0) { - COMMAND_PARSE_ADDITIONAL_NUMBER(u16, i, port, "port number"); - } else if (strcmp(CMD_ARGV[i], "-tool") == 0) { - COMMAND_PARSE_ADDITIONAL_NUMBER(u8, i, tool, "tool"); - } else if (strcmp(CMD_ARGV[i], "-stop") == 0) { - start = false; - } else if (strcmp(CMD_ARGV[i], "-start") == 0) { - start = true; } else { command_print(CMD, "Unknown argument: %s", CMD_ARGV[i]); return ERROR_FAIL; } } - if (!tap) { command_print(CMD, "no valid tap selected"); return ERROR_FAIL; @@ -941,8 +1061,8 @@ COMMAND_HANDLER(handle_ipdbg_command) return ERROR_FAIL; } - if (tool >= ipdbg_max_tools_from_data_register_length(data_register_length)) { - command_print(CMD, "Tool: %d is invalid", tool); + if (ipdbg_get_hub_by_name(hub_name)) { + LOG_ERROR("IPDBG hub with name '%s' already exists", hub_name); return ERROR_FAIL; } @@ -957,20 +1077,38 @@ COMMAND_HANDLER(handle_ipdbg_command) virtual_ir->value = virtual_ir_value; } - if (start) - return ipdbg_start(port, tap, user_instruction, data_register_length, virtual_ir, tool); - else - return ipdbg_stop(tap, user_instruction, virtual_ir, tool); + if (ipdbg_find_hub(tap, user_instruction, virtual_ir)) { + LOG_ERROR("IPDBG hub for given TAP and user-instruction already exists"); + free(virtual_ir); + return ERROR_FAIL; + } + + int retval = ipdbg_create_hub(tap, user_instruction, data_register_length, virtual_ir, hub_name, cmd); + if (retval != ERROR_OK) + free(virtual_ir); + + return retval; } +static const struct command_registration ipdbg_config_command_handlers[] = { + { + .name = "create-hub", + .mode = COMMAND_ANY, + .handler = handle_ipdbg_create_hub_command, + .help = "create a IPDBG Hub", + .usage = "name.ipdbghub (-tap device.tap -ir ir_value [dr_length] |" + " -pld name.pld [user]) [-vir [vir_value [length [instr_code]]]]", + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration ipdbg_command_handlers[] = { { .name = "ipdbg", - .handler = handle_ipdbg_command, - .mode = COMMAND_EXEC, - .help = "Starts or stops an IPDBG JTAG-Host server.", - .usage = "[-start|-stop] -tap device.tap -hub ir_value [dr_length]" - " [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]", + .mode = COMMAND_ANY, + .help = "IPDBG Hub/Host commands.", + .usage = "", + .chain = ipdbg_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; diff --git a/src/server/ipdbg.h b/src/server/ipdbg.h index 6b7054584..1f4156b7a 100644 --- a/src/server/ipdbg.h +++ b/src/server/ipdbg.h @@ -7,5 +7,6 @@ #include <helper/command.h> int ipdbg_register_commands(struct command_context *cmd_ctx); +int ipdbg_server_free(void); #endif /* OPENOCD_IPDBG_IPDBG_H */ diff --git a/src/server/server.c b/src/server/server.c index 2be90451f..0649ec942 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -23,6 +23,7 @@ #include "openocd.h" #include "tcl_server.h" #include "telnet_server.h" +#include "ipdbg.h" #include <signal.h> @@ -714,6 +715,7 @@ void server_free(void) tcl_service_free(); telnet_service_free(); jsp_service_free(); + ipdbg_server_free(); free(bindto_name); } diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg index bd1459adc..3c92b500c 100644 --- a/tcl/board/bemicro_cycloneiii.cfg +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -17,7 +17,8 @@ source [find fpga/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 cycloneiii.pld cycloneiii_blinker.rbf" -# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555" +# "ipdbg create-hub cycloneiii.ipdbghub -tap cycloneiii.tap -ir 0x00e" +# "cycloneiii.ipdbghub ipdbg start -tool 0 -port 5555" set JTAGSPI_CHAIN_ID cycloneiii.pld diff --git a/tcl/board/digilent_cmod_s7.cfg b/tcl/board/digilent_cmod_s7.cfg index c52ee9505..4fa45a17a 100644 --- a/tcl/board/digilent_cmod_s7.cfg +++ b/tcl/board/digilent_cmod_s7.cfg @@ -15,7 +15,8 @@ adapter speed 10000 source [find cpld/xilinx-xc7.cfg] -# "ipdbg -start -tap xc7.tap -hub 0x02 -tool 0 -port 5555" +# "ipdbg create-hub xc7.ipdbghub -tap xc7.tap -ir 0x02" +# "xc7.ipdbghub ipdbg start -tool 0 -port 5555" #openocd -f board/digilent_cmod_s7.cfg -c "init" -c "pld load xc7.pld shared_folder/cmod_s7_fast.bit" set JTAGSPI_CHAIN_ID xc7.pld diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg index dd663f79d..71769f607 100644 --- a/tcl/board/ecp5_evaluation.cfg +++ b/tcl/board/ecp5_evaluation.cfg @@ -16,7 +16,8 @@ adapter speed 6000 source [find fpga/lattice_ecp5.cfg] #openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load ecp5.pld shared_folder/ecp5_blinker_impl1.bit" -#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0 +#ipdbg create-hub ecp5.ipdbghub -tap ecp5.tap -ir 0x32 +#ecp5.ipdbghub ipdbg start -tool 0 -port 5555 set JTAGSPI_CHAIN_ID ecp5.pld source [find cpld/jtagspi.cfg] diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg index 9496c6f00..6cb07362b 100644 --- a/tcl/board/gowin_runber.cfg +++ b/tcl/board/gowin_runber.cfg @@ -16,4 +16,5 @@ 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 +#ipdbg create-hub gw1n.ipdbghub -tap gw1n.tap -ir 0x42 +#gw1n.ipdbghubipdbg start -tool 0 -port 5555 diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg index dc76d3910..ca44f0b8c 100644 --- a/tcl/board/trion_t20_bga256.cfg +++ b/tcl/board/trion_t20_bga256.cfg @@ -20,7 +20,8 @@ adapter speed 6000 source [find fpga/efinix_trion.cfg] #openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load trion.pld outflow/trion_blinker.bit" -#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0 +#ipdbg create-hub trion.ipdbghub -tap trion.tap -ir 0x8 +#trion.ipdbghub ipdbg start -tool 0 -port 5555 set JTAGSPI_CHAIN_ID trion.pld source [find cpld/jtagspi.cfg] ----------------------------------------------------------------------- Summary of changes: doc/openocd.texi | 75 ++++--- src/jtag/startup.tcl | 128 ++++++++++++ src/server/ipdbg.c | 416 ++++++++++++++++++++++++++------------- src/server/ipdbg.h | 1 + src/server/server.c | 2 + tcl/board/bemicro_cycloneiii.cfg | 3 +- tcl/board/digilent_cmod_s7.cfg | 3 +- tcl/board/ecp5_evaluation.cfg | 3 +- tcl/board/gowin_runber.cfg | 3 +- tcl/board/trion_t20_bga256.cfg | 3 +- 10 files changed, 470 insertions(+), 167 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:42:53
|
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 1d076d6ce1908d5c154bfc6ee2ccd8a629853ef1 (commit) from e9df8a5102106de5a13956759ae52eb72ff68113 (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 1d076d6ce1908d5c154bfc6ee2ccd8a629853ef1 Author: Antonio Borneo <bor...@gm...> Date: Sat Mar 2 14:01:07 2024 +0100 openocd: dump full command line in the debug log When receiving an OpenOCD debug log to investigate about errors or issues, the first question is often about providing the complete command line to better understand the use context. Plus, when OpenOCD is lunched by an IDE, its command line is kept hidden inside the IDE, adding troubles to the user to recover it. Add the full command line directly inside the debug log. It could have been useful to also search and add in the log the full path of the OpenOCD executable, but this is not an immediate task due to portability among OS's. See, for example: https://stackoverflow.com/questions/933850 This part could be handled in a future change, if really needed. Change-Id: Ia6c5b838b9b7208bf1ecac7f95b5efc319aeabf5 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8170 Tested-by: jenkins Reviewed-by: Paul Fertser <fer...@gm...> diff --git a/src/helper/options.c b/src/helper/options.c index 05cde6709..61a101469 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -341,6 +341,10 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) exit(0); } + /* dump full command line */ + for (int i = 0; i < argc; i++) + LOG_DEBUG("ARGV[%d] = \"%s\"", i, argv[i]); + /* paths specified on the command line take precedence over these * built-in paths */ ----------------------------------------------------------------------- Summary of changes: src/helper/options.c | 4 ++++ 1 file changed, 4 insertions(+) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:42:25
|
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 e9df8a5102106de5a13956759ae52eb72ff68113 (commit) from 4c0a2cf42ea0a0b48a948be1ff825629265bbf21 (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 e9df8a5102106de5a13956759ae52eb72ff68113 Author: Antonio Borneo <bor...@gm...> Date: Wed Feb 28 13:41:34 2024 +0100 target: aarch64: add support for 32 bit MON mode Extend the existing code to support Monitor mode in AArch32. Change-Id: Ia43df98d1497baac48aea67b92d81344c24f0635 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8169 Tested-by: jenkins diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 36bcddc31..2e4d0b5c0 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -93,6 +93,7 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -172,6 +173,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; @@ -1043,6 +1045,7 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_HYP: case ARM_MODE_UND: case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; ----------------------------------------------------------------------- Summary of changes: src/target/aarch64.c | 3 +++ 1 file changed, 3 insertions(+) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:38:51
|
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 4c0a2cf42ea0a0b48a948be1ff825629265bbf21 (commit) from 31af18e9d1807d442885d0254ff5b13a66ea3a65 (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 4c0a2cf42ea0a0b48a948be1ff825629265bbf21 Author: Tomas Vanek <va...@fb...> Date: Thu Feb 15 10:05:21 2024 +0100 target/adi_v5_swd: fix DP registers banking ADIv6 brought more complicated rules for DP reg 0 banking. Neither the original implementation [1] nor the later modification [2] respected that the DP reg 0 is banked for read only, not for write. Enforcing of an useless SELECT write before a write to ABORT register may trigger FAULT (CTRL/STAT bits ORUNDETECT and STICKYORUN are set) or WAIT (DP is stalled by an outstanding previous operation) and therefore make ABORT register virtually unusable on some adapters (bitbang, CMSIS-DAP). There are DP ABORT specific functions swd_queue_ap_abort() and swd_clear_sticky_errors() which worked around the problem using the lowest level swd->write_reg(). Using a specific write procedure for a single DP register was error prone (there are other DP_ABORT writes using swd_queue_dp_write_inner()) and also the Tcl command 'xx.dap dpreg 0 value' suffered from unwanted SELECT write. Other smaller discords in DP banking probably do not influence normal DP operation however they may complicate debugging in corner cases. Adhere strictly to the DP banking rules for both ADI versions. Fixes: [1] commit 72fb88613f02 ("adiv6: add low level swd transport") Fixes: [2] commit ee3fb5a0eacb ("target/arm_adi_v5: fix DP SELECT logic") Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: I3328748c1c3e0661c5ecd6eb070ac519b190ace2 Reviewed-on: https://review.openocd.org/c/openocd/+/8154 Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 6d6f287b0..67706f35b 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -105,14 +105,13 @@ static inline int check_sync(struct adiv5_dap *dap) static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg) { /* Only register address 0 (ADIv6 only) and 4 are banked. */ - if ((reg & 0xf) > 4) + if (is_adiv6(dap) ? (reg & 0xf) > 4 : (reg & 0xf) != 4) return ERROR_OK; uint32_t sel = (reg >> 4) & DP_SELECT_DPBANK; - /* DP register 0 is not mapped according to ADIv5 - * whereas ADIv6 ensures DPBANKSEL = 0 after line reset */ - if ((dap->select_valid || ((reg & 0xf) == 0 && dap->select_dpbanksel_valid)) + /* ADIv6 ensures DPBANKSEL = 0 after line reset */ + if ((dap->select_valid || (is_adiv6(dap) && dap->select_dpbanksel_valid)) && (sel == (dap->select & DP_SELECT_DPBANK))) return ERROR_OK; @@ -146,7 +145,7 @@ static int swd_queue_dp_read_inner(struct adiv5_dap *dap, unsigned int reg, static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { - int retval; + int retval = ERROR_OK; const struct swd_driver *swd = adiv5_dap_swd_driver(dap); assert(swd); @@ -167,7 +166,11 @@ static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg, if (reg == DP_SELECT1) dap->select = ((uint64_t)data << 32) | (dap->select & 0xffffffffull); - retval = swd_queue_dp_bankselect(dap, reg); + /* DP_ABORT write is not banked. + * Prevent writing DP_SELECT before as it would fail on locked up DP */ + if (reg != DP_ABORT) + retval = swd_queue_dp_bankselect(dap, reg); + if (retval == ERROR_OK) { swd->write_reg(swd_cmd(false, false, reg), data, 0); ----------------------------------------------------------------------- Summary of changes: src/target/adi_v5_swd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:37: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 31af18e9d1807d442885d0254ff5b13a66ea3a65 (commit) from f7f4fa84f1466036ebec80b3143fdd32ce181344 (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 31af18e9d1807d442885d0254ff5b13a66ea3a65 Author: Tomas Vanek <va...@fb...> Date: Sat Feb 17 13:14:01 2024 +0100 jtag/drivers/bitbang: limit SWD WAIT retries by timeout The bitbang driver kept retrying a SWD command as long as the debugged device had been responding by SWD WAIT. If the DP stalled in WAIT permanently, OpenOCD hanged. Check 0.5 sec timeout in WAIT retry loop. While on it insert a short alive_sleep() if the command is retried 20 or more times. Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: I744e56e21a5a2dc2c4494cc0d7bbcb4be14ddb23 Reviewed-on: https://review.openocd.org/c/openocd/+/8153 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index f0236848b..3d839e65d 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -20,6 +20,11 @@ #include <jtag/interface.h> #include <jtag/commands.h> +#include <helper/time_support.h> + +/* Timeout for retrying on SWD WAIT in msec */ +#define SWD_WAIT_TIMEOUT 500 + /** * Function bitbang_stableclocks * issues a number of clock cycles while staying in a stable state. @@ -474,6 +479,7 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay return; } + int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT; for (unsigned int retry = 0;; retry++) { uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; @@ -496,8 +502,11 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay (cmd & SWD_CMD_A32) >> 1, data); - if (ack == SWD_ACK_WAIT) { + if (ack == SWD_ACK_WAIT && timeval_ms() <= timeout) { swd_clear_sticky_errors(); + if (retry > 20) + alive_sleep(1); + continue; } if (retry > 1) @@ -530,6 +539,8 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay return; } + int64_t timeout = timeval_ms() + SWD_WAIT_TIMEOUT; + /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(cmd); @@ -569,8 +580,11 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay (cmd & SWD_CMD_A32) >> 1, buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); - if (check_ack && ack == SWD_ACK_WAIT) { + if (check_ack && ack == SWD_ACK_WAIT && timeval_ms() <= timeout) { swd_clear_sticky_errors(); + if (retry > 20) + alive_sleep(1); + continue; } ----------------------------------------------------------------------- Summary of changes: src/jtag/drivers/bitbang.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:37: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 f7f4fa84f1466036ebec80b3143fdd32ce181344 (commit) from b63e065f23807cdf6da44d03def4c416686695f5 (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 f7f4fa84f1466036ebec80b3143fdd32ce181344 Author: Tomas Vanek <va...@fb...> Date: Sat Feb 17 12:48:46 2024 +0100 jtag/drivers/bitbang: use LOG_CUSTOM_LEVEL() macro for SWD Log SWD commands with not OK response but WAIT retries at debug level. For commands responded OK and WAIT retries use debug io level not to flood the log. Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: Idf658e82ed970061c155945df55d06908ed25e09 Reviewed-on: https://review.openocd.org/c/openocd/+/8152 Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index 8df51764b..f0236848b 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -474,7 +474,7 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay return; } - for (;;) { + for (unsigned int retry = 0;; retry++) { uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)]; cmd |= SWD_CMD_START | SWD_CMD_PARK; @@ -488,16 +488,22 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32); int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1); - LOG_DEBUG_IO("%s %s read reg %X = %08" PRIx32, - ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", - cmd & SWD_CMD_APNDP ? "AP" : "DP", - (cmd & SWD_CMD_A32) >> 1, - data); + LOG_CUSTOM_LEVEL((ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT)) + ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s %s read reg %X = %08" PRIx32, + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + (cmd & SWD_CMD_A32) >> 1, + data); if (ack == SWD_ACK_WAIT) { swd_clear_sticky_errors(); continue; - } else if (ack != SWD_ACK_OK) { + } + if (retry > 1) + LOG_DEBUG("SWD WAIT: retried %u times", retry); + + if (ack != SWD_ACK_OK) { queued_retval = swd_ack_to_error_code(ack); return; } @@ -529,7 +535,7 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay /* init the array to silence scan-build */ uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0}; - for (;;) { + for (unsigned int retry = 0;; retry++) { buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value); buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value)); @@ -554,22 +560,26 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1); int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3); + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK && (retry == 0 || ack != SWD_ACK_WAIT)) + ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s write reg %X = %08" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + cmd & SWD_CMD_APNDP ? "AP" : "DP", + (cmd & SWD_CMD_A32) >> 1, + buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); + + if (check_ack && ack == SWD_ACK_WAIT) { + swd_clear_sticky_errors(); + continue; + } - LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32, - check_ack ? "" : "ack ignored ", - ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", - cmd & SWD_CMD_APNDP ? "AP" : "DP", - (cmd & SWD_CMD_A32) >> 1, - buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32)); - - if (check_ack) { - if (ack == SWD_ACK_WAIT) { - swd_clear_sticky_errors(); - continue; - } else if (ack != SWD_ACK_OK) { - queued_retval = swd_ack_to_error_code(ack); - return; - } + if (retry > 1) + LOG_DEBUG("SWD WAIT: retried %u times", retry); + + if (check_ack && ack != SWD_ACK_OK) { + queued_retval = swd_ack_to_error_code(ack); + return; } if (cmd & SWD_CMD_APNDP) ----------------------------------------------------------------------- Summary of changes: src/jtag/drivers/bitbang.c | 56 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 23 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:37:24
|
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 b63e065f23807cdf6da44d03def4c416686695f5 (commit) from 263dbc1472efa5f24e636e95f8c71a6f83b4097a (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 b63e065f23807cdf6da44d03def4c416686695f5 Author: Tomas Vanek <va...@fb...> Date: Fri Feb 16 17:40:22 2024 +0100 helper/log: add LOG_CUSTOM_LEVEL() macro Allow logging at a changeable level. Add an example of usage in ftdi driver. Log SWD commands with not OK response at debug level (3). For commands which responded OK use debug io level (4) not to flood the log. Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: I67a472b293f7ed9ee84cadb7c081803e9eeb1ad0 Reviewed-on: https://review.openocd.org/c/openocd/+/8151 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/src/helper/log.h b/src/helper/log.h index ee71bf03f..818716a9d 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -114,6 +114,15 @@ extern int debug_level; expr); \ } while (0) +#define LOG_CUSTOM_LEVEL(level, expr ...) \ + do { \ + enum log_levels _level = level; \ + if (debug_level >= _level) \ + log_printf_lf(_level, \ + __FILE__, __LINE__, __func__, \ + expr); \ + } while (0) + #define LOG_INFO(expr ...) \ log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 2bde93169..58f83af59 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1088,7 +1088,8 @@ static int ftdi_swd_run_queue(void) /* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */ bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd); - LOG_DEBUG_IO("%s%s %s %s reg %X = %08"PRIx32, + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s %s reg %X = %08" PRIx32, check_ack ? "" : "ack ignored ", ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP", ----------------------------------------------------------------------- Summary of changes: src/helper/log.h | 9 +++++++++ src/jtag/drivers/ftdi.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:35: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 263dbc1472efa5f24e636e95f8c71a6f83b4097a (commit) from 348b79aafe6826734921167397190c9032a6039e (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 263dbc1472efa5f24e636e95f8c71a6f83b4097a Author: Tomas Vanek <va...@fb...> Date: Sun Feb 11 17:22:38 2024 +0100 target/arm_adi_v5: introduce adiv5_jim_configure_ext() Allow direct pointer to struct adiv5_private_config for targets with adiv5_private_config inside of a bigger private config container. Use it instead of the private_config pointer toggling hack in aarch64.c Allow optional use of -dap parameter and use it instead of the static variable hack in xtensa_chip.c Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: I7260c79332940adfa49d57b45cae39325cdaf432 Reviewed-on: https://review.openocd.org/c/openocd/+/8138 Tested-by: jenkins Reviewed-by: Ian Thompson <ia...@ca...> Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 1c056a015..36bcddc31 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -2891,13 +2891,8 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info * * options, JIM_OK if it correctly parsed the topmost option * and JIM_ERR if an error occurred during parameter evaluation. * For JIM_CONTINUE, we check our own params. - * - * adiv5_jim_configure() assumes 'private_config' to point to - * 'struct adiv5_private_config'. Override 'private_config'! */ - target->private_config = &pc->adiv5_config; - e = adiv5_jim_configure(target, goi); - target->private_config = pc; + e = adiv5_jim_configure_ext(target, goi, &pc->adiv5_config, ADI_CONFIGURE_DAP_COMPULSORY); if (e != JIM_CONTINUE) return e; diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index ff12658c8..9129acecf 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -2424,23 +2424,26 @@ err_no_param: return JIM_ERR; } -int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) +int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, + struct adiv5_private_config *pc, enum adiv5_configure_dap_optional optional) { - struct adiv5_private_config *pc; int e; - pc = (struct adiv5_private_config *)target->private_config; if (!pc) { - pc = calloc(1, sizeof(struct adiv5_private_config)); + pc = (struct adiv5_private_config *)target->private_config; if (!pc) { - LOG_ERROR("Out of memory"); - return JIM_ERR; + pc = calloc(1, sizeof(struct adiv5_private_config)); + if (!pc) { + LOG_ERROR("Out of memory"); + return JIM_ERR; + } + pc->ap_num = DP_APSEL_INVALID; + target->private_config = pc; } - pc->ap_num = DP_APSEL_INVALID; - target->private_config = pc; } - target->has_dap = true; + if (optional == ADI_CONFIGURE_DAP_COMPULSORY) + target->has_dap = true; e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL); if (e != JIM_OK) @@ -2455,11 +2458,17 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) } target->tap = pc->dap->tap; target->dap_configured = true; + target->has_dap = true; } return JIM_OK; } +int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi) +{ + return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_COMPULSORY); +} + int adiv5_verify_config(struct adiv5_private_config *pc) { if (!pc) diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 60c161f3c..92c3dbc3a 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -788,6 +788,15 @@ struct adiv5_private_config { }; extern int adiv5_verify_config(struct adiv5_private_config *pc); + +enum adiv5_configure_dap_optional { + ADI_CONFIGURE_DAP_COMPULSORY = false, + ADI_CONFIGURE_DAP_OPTIONAL = true +}; + +extern int adiv5_jim_configure_ext(struct target *target, struct jim_getopt_info *goi, + struct adiv5_private_config *pc, + enum adiv5_configure_dap_optional optional); extern int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi); struct adiv5_mem_ap_spot { diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c index ac758ed83..ac4a49ccf 100644 --- a/src/target/xtensa/xtensa_chip.c +++ b/src/target/xtensa/xtensa_chip.c @@ -144,17 +144,7 @@ static int xtensa_chip_examine(struct target *target) static int xtensa_chip_jim_configure(struct target *target, struct jim_getopt_info *goi) { - static bool dap_configured; - int ret = adiv5_jim_configure(target, goi); - if (ret == JIM_OK) { - LOG_DEBUG("xtensa '-dap' target option found"); - dap_configured = true; - } - if (!dap_configured) { - LOG_DEBUG("xtensa '-dap' target option not yet found, assuming JTAG..."); - target->has_dap = false; - } - return ret; + return adiv5_jim_configure_ext(target, goi, NULL, ADI_CONFIGURE_DAP_OPTIONAL); } /** Methods for generic example of Xtensa-based chip-level targets. */ ----------------------------------------------------------------------- Summary of changes: src/target/aarch64.c | 7 +------ src/target/arm_adi_v5.c | 27 ++++++++++++++++++--------- src/target/arm_adi_v5.h | 9 +++++++++ src/target/xtensa/xtensa_chip.c | 12 +----------- 4 files changed, 29 insertions(+), 26 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-16 14:35: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 348b79aafe6826734921167397190c9032a6039e (commit) from 12ff36bd19e4f25dd7505c46a77d9f2c47dc350a (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 348b79aafe6826734921167397190c9032a6039e Author: Tomas Vanek <va...@fb...> Date: Fri Feb 9 07:35:42 2024 +0100 drivers/cmsis_dap, kitprog: use helper to derive err code from ack Unify the error codes returned by adapter drivers in the case of the received SWD ACK field differs from OK. Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: I29e478390b4b30408054a090ac6a7fac3415ae71 Reviewed-on: https://review.openocd.org/c/openocd/+/8137 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 341d35cdf..d7367d813 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -944,7 +944,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo if (ack != SWD_ACK_OK) { LOG_DEBUG("SWD ack not OK @ %d %s", transfer_count, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + queued_retval = swd_ack_to_error_code(ack); /* TODO: use results of transfers completed before the error occurred? */ goto skip; } diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index c0d2adc10..98b0d1668 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -782,7 +782,7 @@ static int kitprog_swd_run_queue(void) if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) { LOG_DEBUG("SWD ack not OK: %d %s", i, ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK"); - queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL; + queued_retval = swd_ack_to_error_code(ack); break; } read_index++; ----------------------------------------------------------------------- Summary of changes: src/jtag/drivers/cmsis_dap.c | 2 +- src/jtag/drivers/kitprog.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-10 17:55: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 12ff36bd19e4f25dd7505c46a77d9f2c47dc350a (commit) from 561ea48d83ae4b83ff823888a80cbcc282b61333 (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 12ff36bd19e4f25dd7505c46a77d9f2c47dc350a Author: Tomas Vanek <va...@fb...> Date: Sun Mar 10 12:12:55 2024 +0100 flash/nor/nrf5: drop useless for cycle condition Commit [1] added a break on error to the nrf5_erase() sector loop and the checking of the res value became useless in the for loop condition. Removing nrf5_get_probed_chip_if_halted() later in [2] dropped res initialization and clang static analyser complains "The left operand of '==' is a garbage value" Drop the useless test! Fixes: [1] commit 491636c8b832 ("flash/nor/nrf5: check protection before flash erase/write on nRF51") Fixes: [2] commit 2db325f5395f ("flash/nor/nrf5: drop nrf5_get_probed_chip_if_halted()") Signed-off-by: Tomas Vanek <va...@fb...> Change-Id: Ife6071c509719f8d7dc312fe9a780bdcf2575f69 Reviewed-on: https://review.openocd.org/c/openocd/+/8174 Tested-by: jenkins Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 3f451a76c..bf8c9da5f 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -1071,7 +1071,7 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, } /* For each sector to be erased */ - for (unsigned int s = first; s <= last && res == ERROR_OK; s++) { + for (unsigned int s = first; s <= last; s++) { if (chip->features & NRF5_FEATURE_SERIES_51 && bank->sectors[s].is_protected == 1) { ----------------------------------------------------------------------- Summary of changes: src/flash/nor/nrf5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-09 11:09:03
|
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 561ea48d83ae4b83ff823888a80cbcc282b61333 (commit) from fcda9f1561bfc413e3723e5b4552bc7e91eb4a8d (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 561ea48d83ae4b83ff823888a80cbcc282b61333 Author: Walter Ji <wal...@os...> Date: Fri Nov 17 11:27:56 2023 +0800 target/mips32: add dsp access support Add access to dsp registers and a command for dsp related operations. Checkpatch-ignore: MACRO_ARG_REUSE Change-Id: I30aec0b9e4984896965edb1663f74216ad41101e Signed-off-by: Walter Ji <wal...@os...> Reviewed-on: https://review.openocd.org/c/openocd/+/7867 Tested-by: jenkins Reviewed-by: Oleksij Rempel <li...@re...> Reviewed-by: Antonio Borneo <bor...@gm...> diff --git a/doc/openocd.texi b/doc/openocd.texi index 4297258d9..bf4e0ad65 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11070,6 +11070,11 @@ EJTAG Register Specification could be found in MIPS Document MD00047F, for core specific EJTAG Register definition, please check Core Specific SUM manual. @end deffn +@deffn {Command} {mips32 dsp} [[register_name] [value]] +Displays all DSP registers' contents or get/set value by register name. Will display +an error if current CPU does not support DSP. +@end deffn + @section RISC-V Architecture @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG diff --git a/src/target/mips32.c b/src/target/mips32.c index 5b94e6c89..ec2bfb7d0 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -161,6 +161,67 @@ static const struct { #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) + +#define zero 0 + +#define AT 1 + +#define v0 2 +#define v1 3 + +#define a0 4 +#define a1 5 +#define a2 6 +#define a3 7 +#define t0 8 +#define t1 9 +#define t2 10 +#define t3 11 +#define t4 12 +#define t5 13 +#define t6 14 +#define t7 15 +#define ta0 12 /* alias for $t4 */ +#define ta1 13 /* alias for $t5 */ +#define ta2 14 /* alias for $t6 */ +#define ta3 15 /* alias for $t7 */ + +#define s0 16 +#define s1 17 +#define s2 18 +#define s3 19 +#define s4 20 +#define s5 21 +#define s6 22 +#define s7 23 +#define s8 30 /* == fp */ + +#define t8 24 +#define t9 25 +#define k0 26 +#define k1 27 + +#define gp 28 + +#define sp 29 +#define fp 30 +#define ra 31 + + +static const struct { + const char *name; +} mips32_dsp_regs[MIPS32NUMDSPREGS] = { + { "hi0"}, + { "hi1"}, + { "hi2"}, + { "hi3"}, + { "lo0"}, + { "lo1"}, + { "lo2"}, + { "lo3"}, + { "control"}, +}; + static int mips32_get_core_reg(struct reg *reg) { int retval; @@ -1544,6 +1605,204 @@ COMMAND_HANDLER(mips32_handle_cp0_command) return retval; } +/** + * mips32_dsp_enable - Enable access to DSP registers + * @param[in] ctx: Context information for the pracc queue + * @param[in] isa: Instruction Set Architecture identifier + * + * @brief Enables access to DSP registers by modifying the status register. + * + * This function adds instructions to the context queue for enabling + * access to DSP registers by modifying the status register. + */ +static void mips32_dsp_enable(struct pracc_queue_info *ctx, int isa) +{ + /* Save Status Register */ + /* move status to $9 (t1) 2*/ + pracc_add(ctx, 0, MIPS32_MFC0(isa, 9, 12, 0)); + + /* Read it again in order to modify it */ + /* move status to $0 (t0) 3*/ + pracc_add(ctx, 0, MIPS32_MFC0(isa, 8, 12, 0)); + + /* Enable access to DSP registers by setting MX bit in status register */ + /* $15 = MIPS32_PRACC_STACK 4/5/6*/ + pracc_add(ctx, 0, MIPS32_LUI(isa, 15, UPPER16(MIPS32_DSP_ENABLE))); + pracc_add(ctx, 0, MIPS32_ORI(isa, 15, 15, LOWER16(MIPS32_DSP_ENABLE))); + pracc_add(ctx, 0, MIPS32_ISA_OR(8, 8, 15)); + /* Enable DSP - update status registers 7*/ + pracc_add(ctx, 0, MIPS32_MTC0(isa, 8, 12, 0)); +} + +/** + * mips32_dsp_restore - Restore DSP status registers to the previous setting + * @param[in] ctx: Context information pracc queue + * @param[in] isa: isa identifier + * + * @brief Restores the DSP status registers to their previous setting. + * + * This function adds instructions to the context queue for restoring the DSP + * status registers to their values before the operation. + */ +static void mips32_dsp_restore(struct pracc_queue_info *ctx, int isa) +{ + pracc_add(ctx, 0, MIPS32_MTC0(isa, 9, 12, 0)); /* Restore status registers to previous setting */ + pracc_add(ctx, 0, MIPS32_NOP); /* nop */ +} + +/** + * mips32_pracc_read_dsp_reg - Read a value from a MIPS32 DSP register + * @param[in] ejtag_info: EJTAG information structure + * @param[out] val: Pointer to store the read value + * @param[in] reg: Index of the DSP register to read + * + * @brief Reads the value from the specified MIPS32 DSP register using EJTAG access. + * + * This function initiates a sequence of instructions to read the value from the + * specified DSP register. It will enable dsp module if its not enabled + * and restoring the status registers after the read operation. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_pracc_read_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t reg) +{ + int isa = 0; + + struct pracc_queue_info ctx = { + .max_code = 48, + .ejtag_info = ejtag_info + }; + + uint32_t dsp_read_code[] = { + MIPS32_MFHI(isa, t0), /* mfhi t0 ($ac0) - OPCODE - 0x00004010 */ + MIPS32_DSP_MFHI(t0, 1), /* mfhi t0,$ac1 - OPCODE - 0x00204010 */ + MIPS32_DSP_MFHI(t0, 2), /* mfhi t0,$ac2 - OPCODE - 0x00404010 */ + MIPS32_DSP_MFHI(t0, 3), /* mfhi t0,$ac3 - OPCODE - 0x00604010*/ + MIPS32_MFLO(isa, t0), /* mflo t0 ($ac0) - OPCODE - 0x00004012 */ + MIPS32_DSP_MFLO(t0, 1), /* mflo t0,$ac1 - OPCODE - 0x00204012 */ + MIPS32_DSP_MFLO(t0, 2), /* mflo t0,$ac2 - OPCODE - 0x00404012 */ + MIPS32_DSP_MFLO(t0, 3), /* mflo t0,$ac3 - OPCODE - 0x00604012 */ + MIPS32_DSP_RDDSP(t0, 0x3F), /* rddsp t0, 0x3f (DSPCtl) - OPCODE - 0x7c3f44b8 */ + }; + + /* Check status register to determine if dsp register access is enabled */ + /* Get status register so it can be restored later */ + + ctx.pracc_list = NULL; + + /* Init context queue */ + pracc_queue_init(&ctx); + + if (ctx.retval != ERROR_OK) + goto exit; + + /* Enables DSP whether its already enabled or not */ + mips32_dsp_enable(&ctx, isa); + + /* move AC or Control to $8 (t0) 8*/ + pracc_add(&ctx, 0, dsp_read_code[reg]); + /* Restore status registers to previous setting */ + mips32_dsp_restore(&ctx, isa); + + /* $15 = MIPS32_PRACC_BASE_ADDR 1*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 15, PRACC_UPPER_BASE_ADDR)); + /* store $8 to pracc_out 10*/ + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(isa, 8, PRACC_OUT_OFFSET, 15)); + /* move COP0 DeSave to $15 11*/ + pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0)); + /* restore upper 16 of $8 12*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8))); + /* restore lower 16 of $8 13*/ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8))); + /* restore upper 16 of $9 14*/ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9))); + pracc_add(&ctx, 0, MIPS32_SYNC(isa)); + /* jump to start 18*/ + pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1))); + /* restore lower 16 of $9 15*/ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9))); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1); +exit: + pracc_queue_free(&ctx); + return ctx.retval; +} + +/** + * mips32_pracc_write_dsp_reg - Write a value to a MIPS32 DSP register + * @param[in] ejtag_info: EJTAG information structure + * @param[in] val: Value to be written to the register + * @param[in] reg: Index of the DSP register to write + * + * @brief Writes the specified value to the specified MIPS32 DSP register. + * + * This function initiates a sequence of instructions to write the given value to the + * specified DSP register. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_pracc_write_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t reg) +{ + int isa = 0; + + struct pracc_queue_info ctx = { + .max_code = 48, + .ejtag_info = ejtag_info + }; + + uint32_t dsp_write_code[] = { + MIPS32_MTHI(isa, t0), /* mthi t0 ($ac0) - OPCODE - 0x01000011 */ + MIPS32_DSP_MTHI(t0, 1), /* mthi t0, $ac1 - OPCODE - 0x01000811 */ + MIPS32_DSP_MTHI(t0, 2), /* mthi t0, $ac2 - OPCODE - 0x01001011 */ + MIPS32_DSP_MTHI(t0, 3), /* mthi t0, $ac3 - OPCODE - 0x01001811 */ + MIPS32_MTLO(isa, t0), /* mtlo t0 ($ac0) - OPCODE - 0x01000013 */ + MIPS32_DSP_MTLO(t0, 1), /* mtlo t0, $ac1 - OPCODE - 0x01000813 */ + MIPS32_DSP_MTLO(t0, 2), /* mtlo t0, $ac2 - OPCODE - 0x01001013 */ + MIPS32_DSP_MTLO(t0, 3), /* mtlo t0, $ac3 - OPCODE - 0x01001813 */ + MIPS32_DSP_WRDSP(t0, 0x1F), /* wrdsp t0, 0x1f (DSPCtl) - OPCODE - 0x7d00fcf8*/ + }; + + /* Init context queue */ + pracc_queue_init(&ctx); + if (ctx.retval != ERROR_OK) + goto exit; + + /* Enables DSP whether its already enabled or not */ + mips32_dsp_enable(&ctx, isa); + + /* Load val to $8 (t0) */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(val))); + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(val))); + + /* move AC or Control to $8 (t0) */ + pracc_add(&ctx, 0, dsp_write_code[reg]); + + /* nop, delay in order to ensure write */ + pracc_add(&ctx, 0, MIPS32_NOP); + /* Restore status registers to previous setting */ + mips32_dsp_restore(&ctx, isa); + + /* move COP0 DeSave to $15 */ + pracc_add(&ctx, 0, MIPS32_MFC0(isa, 15, 31, 0)); + + /* restore $8 */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8))); + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8))); + + /* restore upper 16 of $9 */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 9, UPPER16(ejtag_info->reg9))); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1))); + /* restore lower 16 of $9 */ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 9, 9, LOWER16(ejtag_info->reg9))); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); +exit: + pracc_queue_free(&ctx); + return ctx.retval; +} + /** * mips32_handle_cpuinfo_command - Handles the 'cpuinfo' command. * @param[in] cmd: Command invocation context. @@ -1746,6 +2005,167 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command) return ERROR_OK; } +/** + * mips32_dsp_find_register_by_name - Find DSP register index by name + * @param[in] reg_name: Name of the DSP register to find + * + * @brief Searches for a DSP register by name and returns its index. + * If no match is found, it returns MIPS32NUMDSPREGS. + * + * @return Index of the found register or MIPS32NUMDSPREGS if not found. + */ +static int mips32_dsp_find_register_by_name(const char *reg_name) +{ + if (reg_name) + for (int i = 0; i < MIPS32NUMDSPREGS; i++) { + if (strcmp(mips32_dsp_regs[i].name, reg_name) == 0) + return i; + } + return MIPS32NUMDSPREGS; +} + +/** + * mips32_dsp_get_all_regs - Get values of all MIPS32 DSP registers + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief This function iterates through all DSP registers, reads their values, + * and prints each register name along with its corresponding value. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value; + for (int i = 0; i < MIPS32NUMDSPREGS; i++) { + int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i); + if (retval != ERROR_OK) { + command_print(CMD, "couldn't access reg %s", mips32_dsp_regs[i].name); + return retval; + } + command_print(CMD, "%*s: 0x%8.8x", 7, mips32_dsp_regs[i].name, value); + } + return ERROR_OK; +} + +/** + * mips32_dsp_get_register - Get the value of a MIPS32 DSP register + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief Retrieves the value of a specified MIPS32 DSP register. + * If the register is found, it reads the register value and prints the result. + * If the register is not found, it prints an error message. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value; + int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); + if (index == MIPS32NUMDSPREGS) { + command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, index); + if (retval != ERROR_OK) + command_print(CMD, "ERROR: Could not access dsp register %s", CMD_ARGV[0]); + else + command_print(CMD, "0x%8.8x", value); + + return retval; +} + +/** + * mips32_dsp_set_register - Set the value of a MIPS32 DSP register + * @param[in] cmd: Command invocation context + * @param[in] ejtag_info: EJTAG information structure + * + * @brief Sets the value of a specified MIPS32 DSP register. + * If the register is found, it writes provided value to the register. + * If the register is not found or there is an error in writing the value, + * it prints an error message. + * + * @return ERROR_OK on success; error code on failure. + */ +static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +{ + uint32_t value; + int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); + if (index == MIPS32NUMDSPREGS) { + command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + + int retval = mips32_pracc_write_dsp_reg(ejtag_info, value, index); + if (retval != ERROR_OK) + command_print(CMD, "Error: could not write to dsp register %s", CMD_ARGV[0]); + + return retval; +} + +/** + * mips32_handle_dsp_command - Handles mips dsp related command + * @param[in] cmd: Command invocation context + * + * @brief Reads or sets the content of each dsp register. + * + * @return ERROR_OK on success; error code on failure. +*/ +COMMAND_HANDLER(mips32_handle_dsp_command) +{ + int retval, tmp; + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + + retval = mips32_verify_pointer(CMD, mips32); + if (retval != ERROR_OK) + return retval; + + if (target->state != TARGET_HALTED) { + command_print(CMD, "target must be stopped for \"%s\" command", CMD_NAME); + return ERROR_OK; + } + + /* Check for too many command args */ + if (CMD_ARGC >= 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Check if DSP access supported or not */ + if (!mips32->dsp_imp) { + /* Issue Error Message */ + command_print(CMD, "DSP not implemented by this processor"); + return ERROR_OK; + } + + switch (CMD_ARGC) { + case 0: + retval = mips32_dsp_get_all_regs(CMD, ejtag_info); + break; + case 1: + retval = mips32_dsp_get_register(CMD, ejtag_info); + break; + case 2: + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) { + command_print(CMD, "Error: invalid dsp command format"); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + } else { + retval = mips32_dsp_set_register(CMD, ejtag_info); + } + break; + default: + command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + break; + } + return retval; +} + /** * mips32_handle_ejtag_reg_command - Handler commands related to EJTAG * @param[in] cmd: Command invocation context @@ -1847,6 +2267,14 @@ static const struct command_registration mips32_exec_command_handlers[] = { .help = "display CPU information", .usage = "", }, + { + .name = "dsp", + .handler = mips32_handle_dsp_command, + .mode = COMMAND_EXEC, + .help = "display or set DSP register; " + "with no arguments, displays all registers and their values", + .usage = "[[register_name] [value]]", + }, { .name = "scan_delay", .handler = mips32_handle_scan_delay_command, diff --git a/src/target/mips32.h b/src/target/mips32.h index 208c9da17..d512e4970 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -69,7 +69,7 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 -#define MIPS32_NUM_DSPREGS 9 +#define MIPS32NUMDSPREGS 9 /* Bit Mask indicating CP0 register supported by this core */ #define MIPS_CP0_MK4 0x0001 @@ -734,6 +734,24 @@ struct mips32_algorithm { /* ejtag specific instructions */ #define MICRO_MIPS32_SDBBP 0x000046C0 #define MICRO_MIPS_SDBBP 0x46C0 +#define MIPS32_DSP_ENABLE 0x1000000 + +#define MIPS32_S_INST(rs, rac, opcode) \ + (((rs) << 21) | ((rac) << 11) | (opcode)) + +#define MIPS32_DSP_R_INST(rt, immd, opcode, extrw) \ + ((0x1F << 26) | ((immd) << 16) | ((rt) << 11) | ((opcode) << 6) | (extrw)) +#define MIPS32_DSP_W_INST(rs, immd, opcode, extrw) \ + ((0x1F << 26) | ((rs) << 21) | ((immd) << 11) | ((opcode) << 6) | (extrw)) + +#define MIPS32_DSP_MFHI(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFHI) +#define MIPS32_DSP_MFLO(reg, ac) MIPS32_R_INST(0, ac, 0, reg, 0, MIPS32_OP_MFLO) +#define MIPS32_DSP_MTLO(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTLO) +#define MIPS32_DSP_MTHI(reg, ac) MIPS32_S_INST(reg, ac, MIPS32_OP_MTHI) +#define MIPS32_DSP_RDDSP(rt, mask) MIPS32_DSP_R_INST(rt, mask, 0x12, 0x38) +#define MIPS32_DSP_WRDSP(rs, mask) MIPS32_DSP_W_INST(rs, mask, 0x13, 0x38) + + /* * MIPS32 Config1 Register (CP0 Register 16, Select 1) */ ----------------------------------------------------------------------- Summary of changes: doc/openocd.texi | 5 + src/target/mips32.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/target/mips32.h | 20 ++- 3 files changed, 452 insertions(+), 1 deletion(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-09 11:04:57
|
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 fcda9f1561bfc413e3723e5b4552bc7e91eb4a8d (commit) from 5c395fdef42a5750852ea0fc0abd944cf303a39b (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 fcda9f1561bfc413e3723e5b4552bc7e91eb4a8d Author: Antonio Borneo <bor...@gm...> Date: Sun Feb 25 18:36:47 2024 +0100 gdb_server: fix segfault with GDB command 'flash-erase' Running the GDB command 'flash-erase' triggers sending the remote GDB commands 'vFlashErase' (one per flash bank) followed by one single 'vFlashDone', with no 'vFlashWrite' commands in between. This causes the field 'gdb_connection->vflash_image' to be NULL during the execution of 'vFlashDone', triggering a segmentation fault in OpenOCD. While parsing 'vFlashDone', check if any image to flash has been received. Change-Id: I443021c7a531255b60f2c44c2685e52e3c34b5c8 Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8164 Tested-by: jenkins diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b14068941..ae288de1c 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3376,6 +3376,13 @@ static int gdb_v_packet(struct connection *connection, if (strncmp(packet, "vFlashDone", 10) == 0) { uint32_t written; + /* GDB command 'flash-erase' does not send a vFlashWrite, + * so nothing to write here. */ + if (!gdb_connection->vflash_image) { + gdb_put_packet(connection, "OK", 2); + return ERROR_OK; + } + /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ target_call_event_callbacks(target, ----------------------------------------------------------------------- Summary of changes: src/server/gdb_server.c | 7 +++++++ 1 file changed, 7 insertions(+) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-09 11:04:19
|
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 5c395fdef42a5750852ea0fc0abd944cf303a39b (commit) from 61e19349b2b83f844e9729a76ad5698e6c77c686 (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 5c395fdef42a5750852ea0fc0abd944cf303a39b Author: Antonio Borneo <bor...@gm...> Date: Sun Feb 25 12:22:44 2024 +0100 mem_ap: fix GDB connections After commit d9b2607ca094 ("gdb_server: support sparse register maps"), GDB crashes while requesting the value of 'cpsr' because the fake register is tagged as not existing. Change the logic and set all register as existing, while still limiting the list for the initial GDB request at connect. Change-Id: I1c4e274c06147683db2a59a8920ae5ccd863e15c Signed-off-by: Antonio Borneo <bor...@gm...> Reviewed-on: https://review.openocd.org/c/openocd/+/8163 Tested-by: jenkins diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 5c81e3a75..61a9475e6 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -194,11 +194,11 @@ static const char *mem_ap_get_gdb_arch(const struct target *target) * reg[24]: 32 bits, fps * reg[25]: 32 bits, cpsr * - * Set 'exist' only to reg[0..15], so initial response to GDB is correct + * GDB requires only reg[0..15] */ #define NUM_REGS 26 +#define NUM_GDB_REGS 16 #define MAX_REG_SIZE 96 -#define REG_EXIST(n) ((n) < 16) #define REG_SIZE(n) ((((n) >= 16) && ((n) < 24)) ? 96 : 32) struct mem_ap_alloc_reg_list { @@ -218,14 +218,14 @@ static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[ } *reg_list = mem_ap_alloc->reg_list; - *reg_list_size = NUM_REGS; + *reg_list_size = (reg_class == REG_CLASS_ALL) ? NUM_REGS : NUM_GDB_REGS; struct reg *regs = mem_ap_alloc->regs; for (int i = 0; i < NUM_REGS; i++) { regs[i].number = i; regs[i].value = mem_ap_alloc->regs_value; regs[i].size = REG_SIZE(i); - regs[i].exist = REG_EXIST(i); + regs[i].exist = true; regs[i].type = &mem_ap_reg_arch_type; (*reg_list)[i] = ®s[i]; } ----------------------------------------------------------------------- Summary of changes: src/target/mem_ap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) hooks/post-receive -- Main OpenOCD repository |
From: openocd-gerrit <ope...@us...> - 2024-03-09 11:03: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 61e19349b2b83f844e9729a76ad5698e6c77c686 (commit) from cdc569ce3a0d76a638378b7d97ae9f5f1bcbd3c6 (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 61e19349b2b83f844e9729a76ad5698e6c77c686 Author: Tomas Vanek <va...@fb...> Date: Mon Jan 22 12:13:46 2024 +0100 flash/nor/nrf5: use BIT() instead of << operator for features flags. Change-Id: I8bff0f5fac41c50180c847f36c6d2a075eca32ca Signed-off-by: Tomas Vanek <va...@fb...> Reviewed-on: https://review.openocd.org/c/openocd/+/8109 Reviewed-by: Antonio Borneo <bor...@gm...> Tested-by: jenkins diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 35fa6d142..3f451a76c 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -17,6 +17,7 @@ #include <target/armv7m.h> #include <helper/types.h> #include <helper/time_support.h> +#include <helper/bits.h> /* Both those values are constant across the current spectrum ofr nRF5 devices */ #define WATCHDOG_REFRESH_REGISTER 0x40010600 @@ -94,10 +95,10 @@ struct nrf52_ficr_info { }; enum nrf5_features { - NRF5_FEATURE_SERIES_51 = 1 << 0, - NRF5_FEATURE_SERIES_52 = 1 << 1, - NRF5_FEATURE_BPROT = 1 << 2, - NRF5_FEATURE_ACL_PROT = 1 << 3, + NRF5_FEATURE_SERIES_51 = BIT(0), + NRF5_FEATURE_SERIES_52 = BIT(1), + NRF5_FEATURE_BPROT = BIT(2), + NRF5_FEATURE_ACL_PROT = BIT(3), }; struct nrf5_device_spec { ----------------------------------------------------------------------- Summary of changes: src/flash/nor/nrf5.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) hooks/post-receive -- Main OpenOCD repository |