Merge up to a510d51a78
from upstream
Changed `.github/workflows` due to internall `jimtcl` deprecation. Change-Id: I628922a843a7116955cd6b48c48b0cd104bcaf20 Signed-off-by: Evgeniy Naydanov <evgeniy.naydanov@syntacore.com>
This commit is contained in:
commit
309c25f5e2
|
@ -9,13 +9,34 @@ jobs:
|
||||||
env:
|
env:
|
||||||
CFLAGS: -m32
|
CFLAGS: -m32
|
||||||
CC: clang
|
CC: clang
|
||||||
|
PKG_CONFIG_PATH: /opt/libjim32/lib/pkgconfig
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
- name: Install required packages (apt-get)
|
- name: Install required packages (apt-get)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install clang gcc-multilib
|
sudo apt-get install clang gcc-multilib
|
||||||
|
- name: Get 32-bit JIM TCL from cache
|
||||||
|
id: cache-libjim32
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: /opt/libjim32
|
||||||
|
key: libjim32
|
||||||
|
- if: ${{ steps.cache-libjim32.outputs.cache-hit != 'true' }}
|
||||||
|
name: Checkout JIM TCL
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: msteveb/jimtcl
|
||||||
|
ref: 0.83
|
||||||
|
path: jimtcl
|
||||||
|
- if: ${{ steps.cache-libjim32.outputs.cache-hit != 'true' }}
|
||||||
|
name: Build 32-bit JIM TCL from source
|
||||||
|
run: |
|
||||||
|
cd jimtcl
|
||||||
|
./configure --prefix=/opt/libjim32 --with-ext=json --minimal --disable-ssl
|
||||||
|
make -j`nproc`
|
||||||
|
make install
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
- run: ./bootstrap
|
- run: ./bootstrap
|
||||||
- run: ./configure --enable-remote-bitbang --enable-jtag_vpi --disable-target64
|
- run: ./configure --enable-remote-bitbang --enable-jtag_vpi --disable-target64
|
||||||
- run: make -j`nproc`
|
- run: make -j`nproc`
|
||||||
|
@ -39,7 +60,7 @@ jobs:
|
||||||
- name: Install required packages (apt-get)
|
- name: Install required packages (apt-get)
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev
|
sudo apt-get install libusb-1.0-0 libusb-1.0-0-dev libjim-dev
|
||||||
- run: ./bootstrap
|
- run: ./bootstrap
|
||||||
- run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag --prefix /tmp/${{ env.NAME }}
|
- run: ./configure --enable-remote-bitbang --enable-jtag_vpi --enable-ftdi-cjtag --prefix /tmp/${{ env.NAME }}
|
||||||
- run: make -j`nproc`
|
- run: make -j`nproc`
|
||||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
- name: Install packages
|
- name: Install packages
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y device-tree-compiler build-essential
|
sudo apt-get install -y device-tree-compiler build-essential libjim-dev
|
||||||
|
|
||||||
- name: Get revisions of dependencies
|
- name: Get revisions of dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|
20
bootstrap
20
bootstrap
|
@ -15,19 +15,21 @@ else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SKIP_SUBMODULE=0
|
WITH_SUBMODULES=0
|
||||||
|
|
||||||
case "$#" in
|
case "$#" in
|
||||||
0) ;;
|
0) ;;
|
||||||
1) if [ "$1" = "nosubmodule" ]; then
|
1) if [ "$1" = "with-submodules" ]; then
|
||||||
SKIP_SUBMODULE=1
|
WITH_SUBMODULES=1
|
||||||
else
|
elif [ "$1" = "nosubmodule" ]; then
|
||||||
|
WITH_SUBMODULES=0
|
||||||
|
elif [ -n "$1" ]; then
|
||||||
echo "$0: Illegal argument $1" >&2
|
echo "$0: Illegal argument $1" >&2
|
||||||
echo "USAGE: $0 [nosubmodule]" >&2
|
echo "USAGE: $0 [with-submodules]" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi;;
|
fi;;
|
||||||
*) echo "$0: Wrong number of command-line arguments." >&2
|
*) echo "$0: Wrong number of command-line arguments." >&2
|
||||||
echo "USAGE: $0 [nosubmodule]" >&2
|
echo "USAGE: $0 [with-submodules]" >&2
|
||||||
exit 1;;
|
exit 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -42,12 +44,12 @@ autoheader --warnings=all
|
||||||
automake --warnings=all --gnu --add-missing --copy
|
automake --warnings=all --gnu --add-missing --copy
|
||||||
)
|
)
|
||||||
|
|
||||||
if [ "$SKIP_SUBMODULE" -ne 0 ]; then
|
if [ "$WITH_SUBMODULES" -ne 0 ]; then
|
||||||
echo "Skipping submodule setup"
|
|
||||||
else
|
|
||||||
echo "Setting up submodules"
|
echo "Setting up submodules"
|
||||||
git submodule sync
|
git submodule sync
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
else
|
||||||
|
echo "Skipping submodule setup"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -x src/jtag/drivers/libjaylink/autogen.sh ]; then
|
if [ -x src/jtag/drivers/libjaylink/autogen.sh ]; then
|
||||||
|
|
29
configure.ac
29
configure.ac
|
@ -52,9 +52,16 @@ AC_SEARCH_LIBS([openpty], [util])
|
||||||
|
|
||||||
AC_CHECK_HEADERS([sys/socket.h])
|
AC_CHECK_HEADERS([sys/socket.h])
|
||||||
AC_CHECK_HEADERS([elf.h])
|
AC_CHECK_HEADERS([elf.h])
|
||||||
AC_EGREP_HEADER(Elf64_Ehdr, [elf.h], [
|
|
||||||
AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type `Elf64_Ehdr'.])
|
AC_CHECK_TYPE([Elf64_Ehdr],
|
||||||
])
|
AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type 'Elf64_Ehdr'.]),
|
||||||
|
[], [[#include <elf.h>]])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for glibc])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <features.h>]], [[int v = __GLIBC__;return 0;]])],
|
||||||
|
[have_glibc=yes], [have_glibc=no])
|
||||||
|
AC_MSG_RESULT($have_glibc)
|
||||||
|
|
||||||
AC_CHECK_HEADERS([fcntl.h])
|
AC_CHECK_HEADERS([fcntl.h])
|
||||||
AC_CHECK_HEADERS([malloc.h])
|
AC_CHECK_HEADERS([malloc.h])
|
||||||
AC_CHECK_HEADERS([netdb.h])
|
AC_CHECK_HEADERS([netdb.h])
|
||||||
|
@ -164,6 +171,9 @@ m4_define([PCIE_ADAPTERS],
|
||||||
m4_define([SERIAL_PORT_ADAPTERS],
|
m4_define([SERIAL_PORT_ADAPTERS],
|
||||||
[[[buspirate], [Bus Pirate], [BUS_PIRATE]]])
|
[[[buspirate], [Bus Pirate], [BUS_PIRATE]]])
|
||||||
|
|
||||||
|
m4_define([LINUXSPIDEV_ADAPTER],
|
||||||
|
[[[linuxspidev], [Linux spidev driver], [LINUXSPIDEV]]])
|
||||||
|
|
||||||
# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter
|
# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter
|
||||||
# because there is an M4 macro called 'adapter'.
|
# because there is an M4 macro called 'adapter'.
|
||||||
m4_define([DUMMY_ADAPTER],
|
m4_define([DUMMY_ADAPTER],
|
||||||
|
@ -258,7 +268,7 @@ AC_ARG_ENABLE([malloc_logging],
|
||||||
|
|
||||||
AC_MSG_CHECKING([whether to enable malloc free space logging]);
|
AC_MSG_CHECKING([whether to enable malloc free space logging]);
|
||||||
AC_MSG_RESULT([$debug_malloc])
|
AC_MSG_RESULT([$debug_malloc])
|
||||||
AS_IF([test "x$debug_malloc" = "xyes"], [
|
AS_IF([test "x$debug_malloc" = "xyes" -a "x$have_glibc" = "xyes"], [
|
||||||
AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging])
|
AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -290,6 +300,7 @@ AC_ARG_ADAPTERS([
|
||||||
LIBFTDI_ADAPTERS,
|
LIBFTDI_ADAPTERS,
|
||||||
LIBFTDI_USB1_ADAPTERS,
|
LIBFTDI_USB1_ADAPTERS,
|
||||||
LIBGPIOD_ADAPTERS,
|
LIBGPIOD_ADAPTERS,
|
||||||
|
LINUXSPIDEV_ADAPTER,
|
||||||
SERIAL_PORT_ADAPTERS,
|
SERIAL_PORT_ADAPTERS,
|
||||||
DUMMY_ADAPTER,
|
DUMMY_ADAPTER,
|
||||||
PCIE_ADAPTERS,
|
PCIE_ADAPTERS,
|
||||||
|
@ -389,8 +400,8 @@ AS_CASE([$host_os],
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_ARG_ENABLE([internal-jimtcl],
|
AC_ARG_ENABLE([internal-jimtcl],
|
||||||
AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]),
|
AS_HELP_STRING([--enable-internal-jimtcl], [Enable building internal jimtcl (deprecated)]),
|
||||||
[use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes])
|
[use_internal_jimtcl=$enableval], [use_internal_jimtcl=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE([jimtcl-maintainer],
|
AC_ARG_ENABLE([jimtcl-maintainer],
|
||||||
AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]),
|
AS_HELP_STRING([--enable-jimtcl-maintainer], [Enable maintainer mode when building internal jimtcl]),
|
||||||
|
@ -727,6 +738,7 @@ PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o
|
||||||
PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build])
|
PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build])
|
||||||
PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"],
|
PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"],
|
||||||
[internal error: validation should happen beforehand])
|
[internal error: validation should happen beforehand])
|
||||||
|
PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev])
|
||||||
PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused])
|
PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused])
|
||||||
|
|
||||||
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
|
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
|
||||||
|
@ -867,6 +879,10 @@ AS_IF([test "x$enable_jlink" != "xno"], [
|
||||||
]])
|
]])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
|
||||||
|
AC_MSG_WARN([Using the internal jimtcl is deprecated and will not be possible in the future.])
|
||||||
|
])
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
echo OpenOCD configuration summary
|
echo OpenOCD configuration summary
|
||||||
|
@ -876,6 +892,7 @@ m4_foreach([adapter], [USB1_ADAPTERS,
|
||||||
LIBFTDI_USB1_ADAPTERS,
|
LIBFTDI_USB1_ADAPTERS,
|
||||||
LIBGPIOD_ADAPTERS,
|
LIBGPIOD_ADAPTERS,
|
||||||
LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS,
|
LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS,
|
||||||
|
LINUXSPIDEV_ADAPTER,
|
||||||
DUMMY_ADAPTER,
|
DUMMY_ADAPTER,
|
||||||
OPTIONAL_LIBRARIES,
|
OPTIONAL_LIBRARIES,
|
||||||
COVERAGE],
|
COVERAGE],
|
||||||
|
|
|
@ -614,6 +614,9 @@ emulation model of target hardware.
|
||||||
@item @b{xlnx_pcie_xvc}
|
@item @b{xlnx_pcie_xvc}
|
||||||
@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface.
|
@* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface.
|
||||||
|
|
||||||
|
@item @b{linuxspidev}
|
||||||
|
@* A SPI based SWD driver using Linux SPI devices.
|
||||||
|
|
||||||
@item @b{linuxgpiod}
|
@item @b{linuxgpiod}
|
||||||
@* A bitbang JTAG driver using Linux GPIO through library libgpiod.
|
@* A bitbang JTAG driver using Linux GPIO through library libgpiod.
|
||||||
|
|
||||||
|
@ -3430,6 +3433,70 @@ See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file.
|
||||||
|
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Interface Driver} {linuxspidev}
|
||||||
|
Linux provides userspace access to SPI through spidev. Full duplex SPI
|
||||||
|
transactions are used to simultaneously read and write to/from the target to
|
||||||
|
emulate the SWD transport.
|
||||||
|
|
||||||
|
@deffn {Config Command} {spidev path} path
|
||||||
|
Specifies the path to the spidev device.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {spidev mode} value
|
||||||
|
Set the mode of the spi port with optional bit flags (default=3).
|
||||||
|
See /usr/include/linux/spi/spidev.h for all of the SPI mode options.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {spidev queue_entries} value
|
||||||
|
Set the maximum number of queued transactions per spi exchange (default=64).
|
||||||
|
More queued transactions may offer greater performance when the target doesn't
|
||||||
|
need to wait. On the contrary higher numbers will reduce performance when the
|
||||||
|
target requests a wait as all queued transactions will need to be exchanged
|
||||||
|
before spidev can see the wait request.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
See @file{tcl/interface/spidev_example.cfg} for a sample configuration file.
|
||||||
|
|
||||||
|
Electrical connections:
|
||||||
|
@example
|
||||||
|
+--------------+ +--------------+
|
||||||
|
| | 1K | |
|
||||||
|
| MOSI|---/\/\/\---+ | |
|
||||||
|
| Host | | | Target |
|
||||||
|
| MISO|------------+---|SWDIO |
|
||||||
|
| | | |
|
||||||
|
| SCK|----------------|SWDCLK |
|
||||||
|
| | | |
|
||||||
|
+--------------+ +--------------+
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The 1K resistor works well with most MCUs up to 3 MHz. A lower resistance
|
||||||
|
could be used to achieve higher speeds granted that the target SWDIO pin has
|
||||||
|
enough drive strength to pull the signal high while being pulled low by this
|
||||||
|
resistor.
|
||||||
|
|
||||||
|
If you are having trouble here are some tips:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
|
||||||
|
@item @b{Make sure MISO and MOSI are tied together with a 1K resistor.}
|
||||||
|
MISO should be attached to the target.
|
||||||
|
|
||||||
|
@item @b{Make sure that your host and target are using the same I/O voltage}
|
||||||
|
(for example both are using 3.3 volts).
|
||||||
|
|
||||||
|
@item @b{Your host's SPI port may not idle low.}
|
||||||
|
This will lead to an additional clock edge being sent to the target, causing
|
||||||
|
the host and target being 1 clock off from each other. Try setting
|
||||||
|
SPI_MOSI_IDLE_LOW in spi_mode. Try using a different spi_mode (0 - 3).
|
||||||
|
|
||||||
|
@item @b{Your target may pull SWDIO and/or SWDCLK high.}
|
||||||
|
This will create an extra edge when the host releases control of the SPI port
|
||||||
|
at the end of a transaction. You'll need to confirm this with a scope or meter.
|
||||||
|
Try installing 10K resistors on SWDIO and SWDCLK to ground to stop this.
|
||||||
|
|
||||||
|
@end itemize
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Interface Driver} {linuxgpiod}
|
@deffn {Interface Driver} {linuxgpiod}
|
||||||
Linux provides userspace access to GPIO through libgpiod since Linux kernel
|
Linux provides userspace access to GPIO through libgpiod since Linux kernel
|
||||||
|
|
|
@ -751,9 +751,9 @@ static int fespi_probe(struct flash_bank *bank)
|
||||||
target_device->name, bank->base);
|
target_device->name, bank->base);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Assuming FESPI as specified at address " TARGET_ADDR_FMT
|
LOG_DEBUG("Assuming FESPI as specified at address " TARGET_ADDR_FMT
|
||||||
" with ctrl at " TARGET_ADDR_FMT, fespi_info->ctrl_base,
|
" with ctrl at " TARGET_ADDR_FMT, fespi_info->ctrl_base,
|
||||||
bank->base);
|
bank->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read and decode flash ID; returns in SW mode */
|
/* read and decode flash ID; returns in SW mode */
|
||||||
|
|
|
@ -1489,7 +1489,22 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
|
||||||
|
|
||||||
kinetis_auto_probe(bank_iter);
|
kinetis_auto_probe(bank_iter);
|
||||||
|
|
||||||
assert(bank_iter->prot_blocks);
|
if (bank_iter->num_prot_blocks == 0) {
|
||||||
|
if (k_bank->flash_class == FC_PFLASH) {
|
||||||
|
LOG_ERROR("BUG: PFLASH bank %u has no protection blocks",
|
||||||
|
bank_idx);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("skipping FLEX_NVM bank %u with no prot blocks (EE bkp only)",
|
||||||
|
bank_idx);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bank_iter->prot_blocks) {
|
||||||
|
LOG_ERROR("BUG: bank %u has NULL protection blocks array",
|
||||||
|
bank_idx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (k_bank->flash_class == FC_PFLASH) {
|
if (k_bank->flash_class == FC_PFLASH) {
|
||||||
for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) {
|
for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) {
|
||||||
|
|
|
@ -1005,7 +1005,7 @@ static int kinetis_ke_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
|
|
||||||
result = kinetis_ke_stop_watchdog(bank->target);
|
result = kinetis_ke_stop_watchdog(bank->target);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = kinetis_ke_prepare_flash(bank);
|
result = kinetis_ke_prepare_flash(bank);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
|
|
|
@ -311,7 +311,7 @@ static int niietcm4_uflash_page_erase(struct flash_bank *bank, int page_num, int
|
||||||
/* status check */
|
/* status check */
|
||||||
retval = niietcm4_uopstatus_check(bank);
|
retval = niietcm4_uopstatus_check(bank);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -394,7 +394,7 @@ COMMAND_HANDLER(niietcm4_handle_uflash_read_byte_command)
|
||||||
uint32_t uflash_data;
|
uint32_t uflash_data;
|
||||||
|
|
||||||
if (strcmp("info", CMD_ARGV[0]) == 0)
|
if (strcmp("info", CMD_ARGV[0]) == 0)
|
||||||
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB;
|
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ_IFB;
|
||||||
else if (strcmp("main", CMD_ARGV[0]) == 0)
|
else if (strcmp("main", CMD_ARGV[0]) == 0)
|
||||||
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ;
|
uflash_cmd = UFMC_MAGIC_KEY | UFMC_READ;
|
||||||
else
|
else
|
||||||
|
@ -539,7 +539,7 @@ COMMAND_HANDLER(niietcm4_handle_uflash_erase_command)
|
||||||
int mem_type;
|
int mem_type;
|
||||||
|
|
||||||
if (strcmp("info", CMD_ARGV[0]) == 0)
|
if (strcmp("info", CMD_ARGV[0]) == 0)
|
||||||
mem_type = 1;
|
mem_type = 1;
|
||||||
else if (strcmp("main", CMD_ARGV[0]) == 0)
|
else if (strcmp("main", CMD_ARGV[0]) == 0)
|
||||||
mem_type = 0;
|
mem_type = 0;
|
||||||
else
|
else
|
||||||
|
|
|
@ -384,15 +384,15 @@ static int psoc4_get_silicon_id(struct flash_bank *bank, uint32_t *silicon_id, u
|
||||||
* bit 7..0 family ID (lowest 8 bits)
|
* bit 7..0 family ID (lowest 8 bits)
|
||||||
*/
|
*/
|
||||||
if (silicon_id)
|
if (silicon_id)
|
||||||
*silicon_id = ((part0 & 0x0000ffff) << 16)
|
*silicon_id = ((part0 & 0x0000ffff) << 16)
|
||||||
| ((part0 & 0x00ff0000) >> 8)
|
| ((part0 & 0x00ff0000) >> 8)
|
||||||
| (part1 & 0x000000ff);
|
| (part1 & 0x000000ff);
|
||||||
|
|
||||||
if (family_id)
|
if (family_id)
|
||||||
*family_id = part1 & 0x0fff;
|
*family_id = part1 & 0x0fff;
|
||||||
|
|
||||||
if (protection)
|
if (protection)
|
||||||
*protection = (part1 >> 12) & 0x0f;
|
*protection = (part1 >> 12) & 0x0f;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,18 @@
|
||||||
#else
|
#else
|
||||||
#error "malloc.h is required to use --enable-malloc-logging"
|
#error "malloc.h is required to use --enable-malloc-logging"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
#if __GLIBC_PREREQ(2, 33)
|
||||||
|
#define FORDBLKS_FORMAT " %zu"
|
||||||
|
#else
|
||||||
|
/* glibc older than 2.33 (2021-02-01) use mallinfo(). Overwrite it */
|
||||||
|
#define mallinfo2 mallinfo
|
||||||
|
#define FORDBLKS_FORMAT " %d"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error "GNU glibc is required to use --enable-malloc-logging"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int debug_level = LOG_LVL_INFO;
|
int debug_level = LOG_LVL_INFO;
|
||||||
|
@ -105,12 +117,11 @@ static void log_puts(enum log_levels level,
|
||||||
/* print with count and time information */
|
/* print with count and time information */
|
||||||
int64_t t = timeval_ms() - start;
|
int64_t t = timeval_ms() - start;
|
||||||
#ifdef _DEBUG_FREE_SPACE_
|
#ifdef _DEBUG_FREE_SPACE_
|
||||||
struct mallinfo info;
|
struct mallinfo2 info = mallinfo2();
|
||||||
info = mallinfo();
|
|
||||||
#endif
|
#endif
|
||||||
fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()"
|
fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()"
|
||||||
#ifdef _DEBUG_FREE_SPACE_
|
#ifdef _DEBUG_FREE_SPACE_
|
||||||
" %d"
|
FORDBLKS_FORMAT
|
||||||
#endif
|
#endif
|
||||||
": %s", log_strings[level + 1], count, t, file, line, function,
|
": %s", log_strings[level + 1], count, t, file, line, function,
|
||||||
#ifdef _DEBUG_FREE_SPACE_
|
#ifdef _DEBUG_FREE_SPACE_
|
||||||
|
@ -272,10 +283,10 @@ void log_init(void)
|
||||||
if (debug_env) {
|
if (debug_env) {
|
||||||
int value;
|
int value;
|
||||||
int retval = parse_int(debug_env, &value);
|
int retval = parse_int(debug_env, &value);
|
||||||
if (retval == ERROR_OK &&
|
if (retval == ERROR_OK
|
||||||
debug_level >= LOG_LVL_SILENT &&
|
&& debug_level >= LOG_LVL_SILENT
|
||||||
debug_level <= LOG_LVL_DEBUG_IO)
|
&& debug_level <= LOG_LVL_DEBUG_IO)
|
||||||
debug_level = value;
|
debug_level = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!log_output)
|
if (!log_output)
|
||||||
|
|
|
@ -303,12 +303,14 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'l': /* --log_output | -l */
|
case 'l': /* --log_output | -l */
|
||||||
if (optarg)
|
{
|
||||||
command_run_linef(cmd_ctx, "log_output %s", optarg);
|
int retval = command_run_linef(cmd_ctx, "log_output %s", optarg);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'c': /* --command | -c */
|
case 'c': /* --command | -c */
|
||||||
if (optarg)
|
add_config_command(optarg);
|
||||||
add_config_command(optarg);
|
|
||||||
break;
|
break;
|
||||||
default: /* '?' */
|
default: /* '?' */
|
||||||
/* getopt will emit an error message, all we have to do is bail. */
|
/* getopt will emit an error message, all we have to do is bail. */
|
||||||
|
|
|
@ -176,6 +176,9 @@ endif
|
||||||
if SYSFSGPIO
|
if SYSFSGPIO
|
||||||
DRIVERFILES += %D%/sysfsgpio.c
|
DRIVERFILES += %D%/sysfsgpio.c
|
||||||
endif
|
endif
|
||||||
|
if LINUXSPIDEV
|
||||||
|
DRIVERFILES += %D%/linuxspidev.c
|
||||||
|
endif
|
||||||
if XLNX_PCIE_XVC
|
if XLNX_PCIE_XVC
|
||||||
DRIVERFILES += %D%/xlnx-pcie-xvc.c
|
DRIVERFILES += %D%/xlnx-pcie-xvc.c
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,622 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
/* Copyright (C) 2020 by Lup Yuen Lee <luppy@appkaki.com>
|
||||||
|
* Copyright (C) 2024 by Richard Pasek <rpasek@google.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Implementation of SWD protocol with a Linux SPI device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Uncomment to log SPI exchanges (very verbose, slows things down a lot)
|
||||||
|
*
|
||||||
|
* A quick note on interpreting SPI exchange messages:
|
||||||
|
*
|
||||||
|
* This implementation works by performing SPI exchanges with MOSI and MISO
|
||||||
|
* tied together with a 1K resistor. This combined signal becomes SWDIO.
|
||||||
|
*
|
||||||
|
* Since we are performing SPI exchanges, (reading and writing at the same
|
||||||
|
* time) this means when the target isn't driving SWDIO, what is written by
|
||||||
|
* the host should also be read by the host.
|
||||||
|
*
|
||||||
|
* On SWD writes:
|
||||||
|
* The TX and RX data should match except for the ACK bits from the target
|
||||||
|
* swd write reg exchange: len=6
|
||||||
|
* tx_buf=C5 02 40 00 02 2C
|
||||||
|
* rx_buf=C5 42 40 00 02 2C
|
||||||
|
* ^
|
||||||
|
* |
|
||||||
|
* ACK from target
|
||||||
|
*
|
||||||
|
* On SWD reads:
|
||||||
|
* Only the command byte should match
|
||||||
|
* swd read reg exchange: len=6
|
||||||
|
* tx_buf=B1 00 00 00 00 00
|
||||||
|
* rx_buf=B1 40 20 00 00 F8
|
||||||
|
* ^^
|
||||||
|
* ||
|
||||||
|
* Command packet from host
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// #define LOG_SPI_EXCHANGE
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/spi/spidev.h>
|
||||||
|
#include <jtag/adapter.h>
|
||||||
|
#include <jtag/swd.h>
|
||||||
|
#include <jtag/interface.h>
|
||||||
|
#include <jtag/commands.h>
|
||||||
|
|
||||||
|
// Number of bits per SPI exchange
|
||||||
|
#define SPI_BITS 8
|
||||||
|
|
||||||
|
// Time in uS after the last bit of transfer before deselecting the device
|
||||||
|
#define SPI_DESELECT_DELAY 0
|
||||||
|
|
||||||
|
// Maximum number of SWD transactions to queue together in a SPI exchange
|
||||||
|
#define MAX_QUEUE_ENTRIES 64
|
||||||
|
|
||||||
|
#define CMD_BITS 8
|
||||||
|
#define TURN_BITS 1
|
||||||
|
#define ACK_BITS 3
|
||||||
|
#define DATA_BITS 32
|
||||||
|
#define PARITY_BITS 1
|
||||||
|
|
||||||
|
#define SWD_WR_BITS (CMD_BITS + TURN_BITS + ACK_BITS + TURN_BITS + DATA_BITS + PARITY_BITS)
|
||||||
|
#define SWD_RD_BITS (CMD_BITS + TURN_BITS + ACK_BITS + DATA_BITS + PARITY_BITS + TURN_BITS)
|
||||||
|
#define SWD_OP_BITS (MAX(SWD_WR_BITS, SWD_RD_BITS))
|
||||||
|
#define SWD_OP_BYTES (DIV_ROUND_UP(SWD_OP_BITS, SPI_BITS))
|
||||||
|
|
||||||
|
#define AP_DELAY_CLOCKS 8
|
||||||
|
#define AP_DELAY_BYTES (DIV_ROUND_UP(AP_DELAY_CLOCKS, SPI_BITS))
|
||||||
|
|
||||||
|
#define END_IDLE_CLOCKS 8
|
||||||
|
#define END_IDLE_BYTES (DIV_ROUND_UP(END_IDLE_CLOCKS, SPI_BITS))
|
||||||
|
|
||||||
|
// File descriptor for SPI device
|
||||||
|
static int spi_fd = -1;
|
||||||
|
|
||||||
|
// SPI Configuration
|
||||||
|
static char *spi_path;
|
||||||
|
static uint32_t spi_mode = SPI_MODE_3; // Note: SPI in LSB mode is not often supported. We'll flip LSB to MSB ourselves.
|
||||||
|
static uint32_t spi_speed;
|
||||||
|
|
||||||
|
struct queue_info {
|
||||||
|
unsigned int buf_idx;
|
||||||
|
uint32_t *rx_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int queue_retval;
|
||||||
|
static unsigned int max_queue_entries;
|
||||||
|
static unsigned int queue_fill;
|
||||||
|
static unsigned int queue_buf_fill;
|
||||||
|
static unsigned int queue_buf_size;
|
||||||
|
static struct queue_info *queue_infos;
|
||||||
|
static uint8_t *queue_tx_buf;
|
||||||
|
static uint8_t *queue_rx_buf;
|
||||||
|
static uint8_t *tx_flip_buf;
|
||||||
|
|
||||||
|
static int spidev_swd_switch_seq(enum swd_special_seq seq);
|
||||||
|
static void spidev_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk);
|
||||||
|
|
||||||
|
static void spi_exchange(const uint8_t *tx_data, uint8_t *rx_data, unsigned int len)
|
||||||
|
{
|
||||||
|
#ifdef LOG_SPI_EXCHANGE
|
||||||
|
LOG_OUTPUT("exchange: len=%u\n", len);
|
||||||
|
#endif // LOG_SPI_EXCHANGE
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
LOG_DEBUG("exchange with no length");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tx_data && !rx_data) {
|
||||||
|
LOG_DEBUG("exchange with no valid tx or rx pointers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > queue_buf_size) {
|
||||||
|
LOG_ERROR("exchange too large len=%u ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx_data) {
|
||||||
|
// Reverse LSB to MSB
|
||||||
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
tx_flip_buf[i] = flip_u32(tx_data[i], 8);
|
||||||
|
|
||||||
|
#ifdef LOG_SPI_EXCHANGE
|
||||||
|
if (len != 0) {
|
||||||
|
LOG_OUTPUT(" tx_buf=");
|
||||||
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
LOG_OUTPUT("%.2" PRIx8 " ", tx_flip_buf[i]);
|
||||||
|
}
|
||||||
|
LOG_OUTPUT("\n");
|
||||||
|
#endif // LOG_SPI_EXCHANGE
|
||||||
|
}
|
||||||
|
// Transmit the MSB buffer to SPI device.
|
||||||
|
struct spi_ioc_transfer tr = {
|
||||||
|
/* The following must be cast to unsigned long to compile correctly on
|
||||||
|
* 32 and 64 bit machines (as is done in the spidev examples in Linux
|
||||||
|
* kernel code in tools/spi/).
|
||||||
|
*/
|
||||||
|
.tx_buf = (unsigned long)(tx_data ? tx_flip_buf : NULL),
|
||||||
|
.rx_buf = (unsigned long)rx_data,
|
||||||
|
.len = len,
|
||||||
|
.delay_usecs = SPI_DESELECT_DELAY,
|
||||||
|
.speed_hz = spi_speed,
|
||||||
|
.bits_per_word = SPI_BITS,
|
||||||
|
};
|
||||||
|
int ret = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
|
||||||
|
|
||||||
|
if (ret < 1) {
|
||||||
|
LOG_ERROR("exchange failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_data) {
|
||||||
|
#ifdef LOG_SPI_EXCHANGE
|
||||||
|
if (len != 0) {
|
||||||
|
LOG_OUTPUT(" rx_buf=");
|
||||||
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
LOG_OUTPUT("%.2" PRIx8 " ", rx_data[i]);
|
||||||
|
}
|
||||||
|
LOG_OUTPUT("\n");
|
||||||
|
#endif // LOG_SPI_EXCHANGE
|
||||||
|
|
||||||
|
// Reverse MSB to LSB
|
||||||
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
rx_data[i] = flip_u32(rx_data[i], 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_speed(int speed)
|
||||||
|
{
|
||||||
|
uint32_t tmp_speed = speed;
|
||||||
|
|
||||||
|
int ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &tmp_speed);
|
||||||
|
if (ret == -1) {
|
||||||
|
LOG_ERROR("Failed to set SPI %d speed", speed);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_speed = speed;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_speed_div(int speed, int *khz)
|
||||||
|
{
|
||||||
|
*khz = speed / 1000;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_khz(int khz, int *jtag_speed)
|
||||||
|
{
|
||||||
|
if (khz == 0) {
|
||||||
|
LOG_DEBUG("RCLK not supported");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*jtag_speed = khz * 1000;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spidev_free_queue(void)
|
||||||
|
{
|
||||||
|
max_queue_entries = 0;
|
||||||
|
queue_buf_size = 0;
|
||||||
|
|
||||||
|
free(queue_infos);
|
||||||
|
queue_infos = NULL;
|
||||||
|
|
||||||
|
free(queue_tx_buf);
|
||||||
|
queue_tx_buf = NULL;
|
||||||
|
|
||||||
|
free(queue_rx_buf);
|
||||||
|
queue_rx_buf = NULL;
|
||||||
|
|
||||||
|
free(tx_flip_buf);
|
||||||
|
tx_flip_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_alloc_queue(unsigned int new_queue_entries)
|
||||||
|
{
|
||||||
|
if (queue_fill || queue_buf_fill) {
|
||||||
|
LOG_ERROR("Can't realloc allocate queue when queue is in use");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int new_queue_buf_size =
|
||||||
|
(new_queue_entries * (SWD_OP_BYTES + AP_DELAY_BYTES)) + END_IDLE_BYTES;
|
||||||
|
|
||||||
|
queue_infos = realloc(queue_infos, sizeof(struct queue_info) * new_queue_entries);
|
||||||
|
if (!queue_infos)
|
||||||
|
goto realloc_fail;
|
||||||
|
|
||||||
|
queue_tx_buf = realloc(queue_tx_buf, new_queue_buf_size);
|
||||||
|
if (!queue_tx_buf)
|
||||||
|
goto realloc_fail;
|
||||||
|
|
||||||
|
queue_rx_buf = realloc(queue_rx_buf, new_queue_buf_size);
|
||||||
|
if (!queue_rx_buf)
|
||||||
|
goto realloc_fail;
|
||||||
|
|
||||||
|
tx_flip_buf = realloc(tx_flip_buf, new_queue_buf_size);
|
||||||
|
if (!tx_flip_buf)
|
||||||
|
goto realloc_fail;
|
||||||
|
|
||||||
|
max_queue_entries = new_queue_entries;
|
||||||
|
queue_buf_size = new_queue_buf_size;
|
||||||
|
|
||||||
|
LOG_DEBUG("Set queue entries to %u (buffers %u bytes)", max_queue_entries, queue_buf_size);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
realloc_fail:
|
||||||
|
spidev_free_queue();
|
||||||
|
|
||||||
|
LOG_ERROR("Couldn't allocate queue. Out of memory.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_init(void)
|
||||||
|
{
|
||||||
|
LOG_INFO("SPI SWD driver");
|
||||||
|
|
||||||
|
if (spi_fd >= 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
if (!spi_path) {
|
||||||
|
LOG_ERROR("Path to spidev not set");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open SPI device.
|
||||||
|
spi_fd = open(spi_path, O_RDWR);
|
||||||
|
if (spi_fd < 0) {
|
||||||
|
LOG_ERROR("Failed to open SPI port at %s", spi_path);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set SPI mode.
|
||||||
|
int ret = ioctl(spi_fd, SPI_IOC_WR_MODE32, &spi_mode);
|
||||||
|
if (ret == -1) {
|
||||||
|
LOG_ERROR("Failed to set SPI mode 0x%" PRIx32, spi_mode);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set SPI bits per word.
|
||||||
|
uint32_t spi_bits = SPI_BITS;
|
||||||
|
ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits);
|
||||||
|
if (ret == -1) {
|
||||||
|
LOG_ERROR("Failed to set SPI %" PRIu8 " bits per transfer", spi_bits);
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Opened SPI device at %s in mode 0x%" PRIx32 " with %" PRIu8 " bits ",
|
||||||
|
spi_path, spi_mode, spi_bits);
|
||||||
|
|
||||||
|
// Set SPI read and write max speed.
|
||||||
|
int speed;
|
||||||
|
ret = adapter_get_speed(&speed);
|
||||||
|
if (ret != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to get adapter speed");
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = spidev_speed(speed);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
|
||||||
|
if (max_queue_entries == 0) {
|
||||||
|
ret = spidev_alloc_queue(MAX_QUEUE_ENTRIES);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_quit(void)
|
||||||
|
{
|
||||||
|
spidev_free_queue();
|
||||||
|
|
||||||
|
if (spi_fd < 0)
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
close(spi_fd);
|
||||||
|
spi_fd = -1;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_swd_init(void)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("spidev_swd_init");
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_swd_execute_queue(unsigned int end_idle_bytes)
|
||||||
|
{
|
||||||
|
LOG_DEBUG_IO("Executing %u queued transactions", queue_fill);
|
||||||
|
|
||||||
|
if (queue_retval != ERROR_OK) {
|
||||||
|
LOG_DEBUG_IO("Skipping due to previous errors: %d", queue_retval);
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A transaction must be followed by another transaction or at least 8 idle
|
||||||
|
* cycles to ensure that data is clocked through the AP. Since the tx
|
||||||
|
* buffer is zeroed after each queue run, every byte added to the buffer
|
||||||
|
* fill will add on an additional 8 idle cycles.
|
||||||
|
*/
|
||||||
|
queue_buf_fill += end_idle_bytes;
|
||||||
|
|
||||||
|
spi_exchange(queue_tx_buf, queue_rx_buf, queue_buf_fill);
|
||||||
|
|
||||||
|
for (unsigned int queue_idx = 0; queue_idx < queue_fill; queue_idx++) {
|
||||||
|
unsigned int buf_idx = queue_infos[queue_idx].buf_idx;
|
||||||
|
uint8_t *tx_ptr = &queue_tx_buf[buf_idx];
|
||||||
|
uint8_t *rx_ptr = &queue_rx_buf[buf_idx];
|
||||||
|
uint8_t cmd = buf_get_u32(tx_ptr, 0, CMD_BITS);
|
||||||
|
bool read = cmd & SWD_CMD_RNW ? true : false;
|
||||||
|
int ack = buf_get_u32(rx_ptr, CMD_BITS + TURN_BITS, ACK_BITS);
|
||||||
|
uint32_t data = read ?
|
||||||
|
buf_get_u32(rx_ptr, CMD_BITS + TURN_BITS + ACK_BITS, DATA_BITS) :
|
||||||
|
buf_get_u32(tx_ptr, CMD_BITS + TURN_BITS + ACK_BITS + TURN_BITS, DATA_BITS);
|
||||||
|
|
||||||
|
// Devices do not reply to DP_TARGETSEL write cmd, ignore received ack
|
||||||
|
bool check_ack = swd_cmd_returns_ack(cmd);
|
||||||
|
|
||||||
|
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",
|
||||||
|
cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||||
|
read ? "read" : "write",
|
||||||
|
(cmd & SWD_CMD_A32) >> 1,
|
||||||
|
data);
|
||||||
|
|
||||||
|
if (ack != SWD_ACK_OK && check_ack) {
|
||||||
|
queue_retval = swd_ack_to_error_code(ack);
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
} else if (read) {
|
||||||
|
int parity = buf_get_u32(rx_ptr, CMD_BITS + TURN_BITS + ACK_BITS + DATA_BITS, PARITY_BITS);
|
||||||
|
|
||||||
|
if (parity != parity_u32(data)) {
|
||||||
|
LOG_ERROR("SWD Read data parity mismatch");
|
||||||
|
queue_retval = ERROR_FAIL;
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue_infos[queue_idx].rx_ptr)
|
||||||
|
*queue_infos[queue_idx].rx_ptr = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skip:
|
||||||
|
// Clear everything in the queue
|
||||||
|
queue_fill = 0;
|
||||||
|
queue_buf_fill = 0;
|
||||||
|
memset(queue_infos, 0, sizeof(queue_infos[0]) * max_queue_entries);
|
||||||
|
memset(queue_tx_buf, 0, queue_buf_size);
|
||||||
|
memset(queue_rx_buf, 0, queue_buf_size);
|
||||||
|
|
||||||
|
int retval = queue_retval;
|
||||||
|
queue_retval = ERROR_OK;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_swd_run_queue(void)
|
||||||
|
{
|
||||||
|
/* Since we are unsure if another SWD transaction will follow the
|
||||||
|
* transactions we are just about to execute, we need to add on 8 idle
|
||||||
|
* cycles.
|
||||||
|
*/
|
||||||
|
return spidev_swd_execute_queue(END_IDLE_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spidev_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
|
||||||
|
{
|
||||||
|
unsigned int swd_op_bytes = DIV_ROUND_UP(SWD_OP_BITS + ap_delay_clk, SPI_BITS);
|
||||||
|
|
||||||
|
if (queue_fill >= max_queue_entries ||
|
||||||
|
queue_buf_fill + swd_op_bytes + END_IDLE_BYTES > queue_buf_size) {
|
||||||
|
/* Not enough room in the queue. Run the queue. No idle bytes are
|
||||||
|
* needed because we are going to execute transactions right after
|
||||||
|
* the queue is emptied.
|
||||||
|
*/
|
||||||
|
queue_retval = spidev_swd_execute_queue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue_retval != ERROR_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t *tx_ptr = &queue_tx_buf[queue_buf_fill];
|
||||||
|
|
||||||
|
cmd |= SWD_CMD_START | SWD_CMD_PARK;
|
||||||
|
|
||||||
|
buf_set_u32(tx_ptr, 0, CMD_BITS, cmd);
|
||||||
|
|
||||||
|
if (cmd & SWD_CMD_RNW) {
|
||||||
|
// Queue a read transaction
|
||||||
|
queue_infos[queue_fill].rx_ptr = dst;
|
||||||
|
} else {
|
||||||
|
// Queue a write transaction
|
||||||
|
buf_set_u32(tx_ptr,
|
||||||
|
CMD_BITS + TURN_BITS + ACK_BITS + TURN_BITS, DATA_BITS, data);
|
||||||
|
buf_set_u32(tx_ptr,
|
||||||
|
CMD_BITS + TURN_BITS + ACK_BITS + TURN_BITS + DATA_BITS, PARITY_BITS, parity_u32(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_infos[queue_fill].buf_idx = queue_buf_fill;
|
||||||
|
|
||||||
|
/* Add idle cycles after AP accesses to avoid WAIT. Buffer is already
|
||||||
|
* zeroed so we just need to advance the pointer to add idle cycles.
|
||||||
|
*/
|
||||||
|
queue_buf_fill += swd_op_bytes;
|
||||||
|
|
||||||
|
queue_fill++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spidev_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
|
||||||
|
{
|
||||||
|
assert(cmd & SWD_CMD_RNW);
|
||||||
|
spidev_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spidev_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
|
||||||
|
{
|
||||||
|
assert(!(cmd & SWD_CMD_RNW));
|
||||||
|
spidev_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spidev_swd_switch_seq(enum swd_special_seq seq)
|
||||||
|
{
|
||||||
|
switch (seq) {
|
||||||
|
case LINE_RESET:
|
||||||
|
LOG_DEBUG_IO("SWD line reset");
|
||||||
|
spi_exchange(swd_seq_line_reset, NULL, swd_seq_line_reset_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case JTAG_TO_SWD:
|
||||||
|
LOG_DEBUG("JTAG-to-SWD");
|
||||||
|
spi_exchange(swd_seq_jtag_to_swd, NULL, swd_seq_jtag_to_swd_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case JTAG_TO_DORMANT:
|
||||||
|
LOG_DEBUG("JTAG-to-DORMANT");
|
||||||
|
spi_exchange(swd_seq_jtag_to_dormant, NULL, swd_seq_jtag_to_dormant_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case SWD_TO_JTAG:
|
||||||
|
LOG_DEBUG("SWD-to-JTAG");
|
||||||
|
spi_exchange(swd_seq_swd_to_jtag, NULL, swd_seq_swd_to_jtag_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case SWD_TO_DORMANT:
|
||||||
|
LOG_DEBUG("SWD-to-DORMANT");
|
||||||
|
spi_exchange(swd_seq_swd_to_dormant, NULL, swd_seq_swd_to_dormant_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case DORMANT_TO_SWD:
|
||||||
|
LOG_DEBUG("DORMANT-to-SWD");
|
||||||
|
spi_exchange(swd_seq_dormant_to_swd, NULL, swd_seq_dormant_to_swd_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
case DORMANT_TO_JTAG:
|
||||||
|
LOG_DEBUG("DORMANT-to-JTAG");
|
||||||
|
spi_exchange(swd_seq_dormant_to_jtag, NULL, swd_seq_dormant_to_jtag_len / SPI_BITS);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Sequence %d not supported", seq);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(spidev_handle_path_command)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC != 1)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
free(spi_path);
|
||||||
|
spi_path = strdup(CMD_ARGV[0]);
|
||||||
|
if (!spi_path) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(spidev_handle_mode_command)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC != 1)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], spi_mode);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(spidev_handle_queue_entries_command)
|
||||||
|
{
|
||||||
|
uint32_t new_queue_entries;
|
||||||
|
|
||||||
|
if (CMD_ARGC != 1)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_queue_entries);
|
||||||
|
|
||||||
|
return spidev_alloc_queue(new_queue_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct swd_driver spidev_swd = {
|
||||||
|
.init = spidev_swd_init,
|
||||||
|
.switch_seq = spidev_swd_switch_seq,
|
||||||
|
.read_reg = spidev_swd_read_reg,
|
||||||
|
.write_reg = spidev_swd_write_reg,
|
||||||
|
.run = spidev_swd_run_queue,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration spidev_subcommand_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "path",
|
||||||
|
.handler = &spidev_handle_path_command,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "set the path to the spidev device",
|
||||||
|
.usage = "path_to_spidev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "mode",
|
||||||
|
.handler = &spidev_handle_mode_command,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "set the mode of the spi port with optional bit flags (default=3)",
|
||||||
|
.usage = "mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "queue_entries",
|
||||||
|
.handler = &spidev_handle_queue_entries_command,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "set the queue entry size (default=64)",
|
||||||
|
.usage = "queue_entries",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct command_registration spidev_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "spidev",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "perform spidev management",
|
||||||
|
.chain = spidev_subcommand_handlers,
|
||||||
|
.usage = "",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only SWD transport supported
|
||||||
|
static const char *const spidev_transports[] = { "swd", NULL };
|
||||||
|
|
||||||
|
struct adapter_driver linuxspidev_adapter_driver = {
|
||||||
|
.name = "linuxspidev",
|
||||||
|
.transports = spidev_transports,
|
||||||
|
.commands = spidev_command_handlers,
|
||||||
|
|
||||||
|
.init = spidev_init,
|
||||||
|
.quit = spidev_quit,
|
||||||
|
.speed = spidev_speed,
|
||||||
|
.khz = spidev_khz,
|
||||||
|
.speed_div = spidev_speed_div,
|
||||||
|
|
||||||
|
.swd_ops = &spidev_swd,
|
||||||
|
};
|
|
@ -252,7 +252,7 @@ static int vdebug_socket_open(char *server_addr, uint32_t port)
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||||
if (hsock == INVALID_SOCKET)
|
if (hsock < 0)
|
||||||
rc = vdebug_socket_error();
|
rc = vdebug_socket_error();
|
||||||
#elif defined __CYGWIN__
|
#elif defined __CYGWIN__
|
||||||
/* SO_RCVLOWAT unsupported on CYGWIN */
|
/* SO_RCVLOWAT unsupported on CYGWIN */
|
||||||
|
|
|
@ -386,6 +386,7 @@ extern struct adapter_driver jtag_dpi_adapter_driver;
|
||||||
extern struct adapter_driver jtag_vpi_adapter_driver;
|
extern struct adapter_driver jtag_vpi_adapter_driver;
|
||||||
extern struct adapter_driver kitprog_adapter_driver;
|
extern struct adapter_driver kitprog_adapter_driver;
|
||||||
extern struct adapter_driver linuxgpiod_adapter_driver;
|
extern struct adapter_driver linuxgpiod_adapter_driver;
|
||||||
|
extern struct adapter_driver linuxspidev_adapter_driver;
|
||||||
extern struct adapter_driver opendous_adapter_driver;
|
extern struct adapter_driver opendous_adapter_driver;
|
||||||
extern struct adapter_driver openjtag_adapter_driver;
|
extern struct adapter_driver openjtag_adapter_driver;
|
||||||
extern struct adapter_driver osbdm_adapter_driver;
|
extern struct adapter_driver osbdm_adapter_driver;
|
||||||
|
|
|
@ -123,6 +123,9 @@ struct adapter_driver *adapter_drivers[] = {
|
||||||
#if BUILD_LINUXGPIOD == 1
|
#if BUILD_LINUXGPIOD == 1
|
||||||
&linuxgpiod_adapter_driver,
|
&linuxgpiod_adapter_driver,
|
||||||
#endif
|
#endif
|
||||||
|
#if BUILD_LINUXSPIDEV == 1
|
||||||
|
&linuxspidev_adapter_driver,
|
||||||
|
#endif
|
||||||
#if BUILD_XLNX_PCIE_XVC == 1
|
#if BUILD_XLNX_PCIE_XVC == 1
|
||||||
&xlnx_pcie_xvc_adapter_driver,
|
&xlnx_pcie_xvc_adapter_driver,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -161,9 +161,8 @@ static int hwthread_update_threads(struct rtos *rtos)
|
||||||
if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
|
if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
|
||||||
current_reason = curr->debug_reason;
|
current_reason = curr->debug_reason;
|
||||||
current_thread = tid;
|
current_thread = tid;
|
||||||
} else
|
} else if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||||
/* multiple breakpoints, prefer gdbs' threadid */
|
/* multiple breakpoints, prefer gdbs' threadid */
|
||||||
if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
|
|
||||||
if (tid == rtos->current_threadid)
|
if (tid == rtos->current_threadid)
|
||||||
current_thread = tid;
|
current_thread = tid;
|
||||||
}
|
}
|
||||||
|
@ -183,8 +182,7 @@ static int hwthread_update_threads(struct rtos *rtos)
|
||||||
curr->debug_reason == DBG_REASON_BREAKPOINT) {
|
curr->debug_reason == DBG_REASON_BREAKPOINT) {
|
||||||
current_reason = curr->debug_reason;
|
current_reason = curr->debug_reason;
|
||||||
current_thread = tid;
|
current_thread = tid;
|
||||||
} else
|
} else if (curr->debug_reason == DBG_REASON_DBGRQ) {
|
||||||
if (curr->debug_reason == DBG_REASON_DBGRQ) {
|
|
||||||
if (tid == rtos->current_threadid)
|
if (tid == rtos->current_threadid)
|
||||||
current_thread = tid;
|
current_thread = tid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -624,7 +624,7 @@ static struct threads *liste_add_task(struct threads *task_list, struct threads
|
||||||
{
|
{
|
||||||
t->next = NULL;
|
t->next = NULL;
|
||||||
|
|
||||||
if (!*last)
|
if (!*last) {
|
||||||
if (!task_list) {
|
if (!task_list) {
|
||||||
task_list = t;
|
task_list = t;
|
||||||
return task_list;
|
return task_list;
|
||||||
|
@ -637,7 +637,8 @@ static struct threads *liste_add_task(struct threads *task_list, struct threads
|
||||||
temp->next = t;
|
temp->next = t;
|
||||||
*last = t;
|
*last = t;
|
||||||
return task_list;
|
return task_list;
|
||||||
} else {
|
}
|
||||||
|
} else {
|
||||||
(*last)->next = t;
|
(*last)->next = t;
|
||||||
*last = t;
|
*last = t;
|
||||||
return task_list;
|
return task_list;
|
||||||
|
|
|
@ -2908,9 +2908,9 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info *
|
||||||
|
|
||||||
pc = (struct aarch64_private_config *)target->private_config;
|
pc = (struct aarch64_private_config *)target->private_config;
|
||||||
if (!pc) {
|
if (!pc) {
|
||||||
pc = calloc(1, sizeof(struct aarch64_private_config));
|
pc = calloc(1, sizeof(struct aarch64_private_config));
|
||||||
pc->adiv5_config.ap_num = DP_APSEL_INVALID;
|
pc->adiv5_config.ap_num = DP_APSEL_INVALID;
|
||||||
target->private_config = pc;
|
target->private_config = pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -388,7 +388,7 @@ static int arc_build_reg_cache(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) {
|
list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) {
|
||||||
CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i));
|
CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i));
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "reg n=%3li name=%3s group=%s feature=%s", i,
|
LOG_TARGET_DEBUG(target, "reg n=%3li name=%3s group=%s feature=%s", i,
|
||||||
reg_list[i].name, reg_list[i].group,
|
reg_list[i].name, reg_list[i].group,
|
||||||
|
@ -464,7 +464,7 @@ static int arc_build_bcr_reg_cache(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) {
|
list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) {
|
||||||
CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum));
|
CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum));
|
||||||
/* BCRs always semantically, they are just read-as-zero, if there is
|
/* BCRs always semantically, they are just read-as-zero, if there is
|
||||||
* not real register. */
|
* not real register. */
|
||||||
reg_list[i].exist = true;
|
reg_list[i].exist = true;
|
||||||
|
@ -719,14 +719,14 @@ static int arc_configure(struct target *target)
|
||||||
LOG_TARGET_DEBUG(target, "Configuring ARC ICCM and DCCM");
|
LOG_TARGET_DEBUG(target, "Configuring ARC ICCM and DCCM");
|
||||||
|
|
||||||
/* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */
|
/* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */
|
||||||
if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) &&
|
if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true)
|
||||||
arc_reg_get_by_name(target->reg_cache, "aux_dccm", true))
|
&& arc_reg_get_by_name(target->reg_cache, "aux_dccm", true))
|
||||||
CHECK_RETVAL(arc_configure_dccm(target));
|
CHECK_RETVAL(arc_configure_dccm(target));
|
||||||
|
|
||||||
/* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */
|
/* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */
|
||||||
if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) &&
|
if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true)
|
||||||
arc_reg_get_by_name(target->reg_cache, "aux_iccm", true))
|
&& arc_reg_get_by_name(target->reg_cache, "aux_iccm", true))
|
||||||
CHECK_RETVAL(arc_configure_iccm(target));
|
CHECK_RETVAL(arc_configure_iccm(target));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1067,9 +1067,7 @@ static int arc_poll(struct target *target)
|
||||||
LOG_TARGET_DEBUG(target, "Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, "
|
LOG_TARGET_DEBUG(target, "Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, "
|
||||||
"target is still running");
|
"target is still running");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (target->state == TARGET_DEBUG_RUNNING) {
|
} else if (target->state == TARGET_DEBUG_RUNNING) {
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
LOG_TARGET_DEBUG(target, "ARC core is in debug running mode");
|
LOG_TARGET_DEBUG(target, "ARC core is in debug running mode");
|
||||||
|
|
||||||
|
|
|
@ -1301,11 +1301,11 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
(*reg_list)[i] = arm_reg_current(arm, i);
|
(*reg_list)[i] = arm_reg_current(arm, i);
|
||||||
|
|
||||||
/* For GDB compatibility, take FPA registers size into account and zero-fill it*/
|
/* For GDB compatibility, take FPA registers size into account and zero-fill it*/
|
||||||
for (i = 16; i < 24; i++)
|
for (i = 16; i < 24; i++)
|
||||||
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
|
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
|
||||||
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
||||||
|
|
||||||
(*reg_list)[25] = arm->cpsr;
|
(*reg_list)[25] = arm->cpsr;
|
||||||
|
@ -1330,25 +1330,25 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
(*reg_list)[i] = arm_reg_current(arm, i);
|
(*reg_list)[i] = arm_reg_current(arm, i);
|
||||||
|
|
||||||
for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) {
|
for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) {
|
||||||
int reg_index = arm->core_cache->reg_list[i].number;
|
int reg_index = arm->core_cache->reg_list[i].number;
|
||||||
|
|
||||||
if (arm_core_regs[i].mode == ARM_MODE_MON
|
if (arm_core_regs[i].mode == ARM_MODE_MON
|
||||||
&& arm->core_type != ARM_CORE_TYPE_SEC_EXT
|
&& arm->core_type != ARM_CORE_TYPE_SEC_EXT
|
||||||
&& arm->core_type != ARM_CORE_TYPE_VIRT_EXT)
|
&& arm->core_type != ARM_CORE_TYPE_VIRT_EXT)
|
||||||
continue;
|
continue;
|
||||||
if (arm_core_regs[i].mode == ARM_MODE_HYP
|
if (arm_core_regs[i].mode == ARM_MODE_HYP
|
||||||
&& arm->core_type != ARM_CORE_TYPE_VIRT_EXT)
|
&& arm->core_type != ARM_CORE_TYPE_VIRT_EXT)
|
||||||
continue;
|
continue;
|
||||||
(*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]);
|
(*reg_list)[reg_index] = &arm->core_cache->reg_list[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When we supply the target description, there is no need for fake FPA */
|
/* When we supply the target description, there is no need for fake FPA */
|
||||||
for (i = 16; i < 24; i++) {
|
for (i = 16; i < 24; i++) {
|
||||||
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
|
(*reg_list)[i] = &arm_gdb_dummy_fp_reg;
|
||||||
(*reg_list)[i]->size = 0;
|
(*reg_list)[i]->size = 0;
|
||||||
}
|
}
|
||||||
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
(*reg_list)[24] = &arm_gdb_dummy_fps_reg;
|
||||||
(*reg_list)[24]->size = 0;
|
(*reg_list)[24]->size = 0;
|
||||||
|
|
|
@ -260,8 +260,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table)
|
||||||
/* skip empty entries in the first level table */
|
/* skip empty entries in the first level table */
|
||||||
if ((first_lvl_descriptor & 3) == 0) {
|
if ((first_lvl_descriptor & 3) == 0) {
|
||||||
pt_idx++;
|
pt_idx++;
|
||||||
} else
|
} else if ((first_lvl_descriptor & 0x40002) == 2) {
|
||||||
if ((first_lvl_descriptor & 0x40002) == 2) {
|
|
||||||
/* section descriptor */
|
/* section descriptor */
|
||||||
uint32_t va_range = 1024*1024-1; /* 1MB range */
|
uint32_t va_range = 1024*1024-1; /* 1MB range */
|
||||||
uint32_t va_start = pt_idx << 20;
|
uint32_t va_start = pt_idx << 20;
|
||||||
|
@ -273,8 +272,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table)
|
||||||
LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
|
LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
|
||||||
va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
|
va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
|
||||||
pt_idx++;
|
pt_idx++;
|
||||||
} else
|
} else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
|
||||||
if ((first_lvl_descriptor & 0x40002) == 0x40002) {
|
|
||||||
/* supersection descriptor */
|
/* supersection descriptor */
|
||||||
uint32_t va_range = 16*1024*1024-1; /* 16MB range */
|
uint32_t va_range = 16*1024*1024-1; /* 16MB range */
|
||||||
uint32_t va_start = pt_idx << 20;
|
uint32_t va_start = pt_idx << 20;
|
||||||
|
@ -310,8 +308,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table)
|
||||||
if ((second_lvl_descriptor & 3) == 0) {
|
if ((second_lvl_descriptor & 3) == 0) {
|
||||||
/* skip entry */
|
/* skip entry */
|
||||||
pt2_idx++;
|
pt2_idx++;
|
||||||
} else
|
} else if ((second_lvl_descriptor & 3) == 1) {
|
||||||
if ((second_lvl_descriptor & 3) == 1) {
|
|
||||||
/* large page */
|
/* large page */
|
||||||
uint32_t va_range = 64*1024-1; /* 64KB range */
|
uint32_t va_range = 64*1024-1; /* 64KB range */
|
||||||
uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
|
uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
|
||||||
|
|
|
@ -65,6 +65,28 @@ const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = {
|
||||||
ARMV7M_XPSR,
|
ARMV7M_XPSR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct reg_data_type_bitfield armv8m_vpr_bits[] = {
|
||||||
|
{ 0, 15, REG_TYPE_UINT },
|
||||||
|
{ 16, 19, REG_TYPE_UINT },
|
||||||
|
{ 20, 23, REG_TYPE_UINT },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct reg_data_type_flags_field armv8m_vpr_fields[] = {
|
||||||
|
{ "P0", armv8m_vpr_bits + 0, armv8m_vpr_fields + 1, },
|
||||||
|
{ "MASK01", armv8m_vpr_bits + 1, armv8m_vpr_fields + 2, },
|
||||||
|
{ "MASK23", armv8m_vpr_bits + 2, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct reg_data_type_flags armv8m_vpr_flags[] = {
|
||||||
|
{ 4, armv8m_vpr_fields },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct reg_data_type armv8m_flags_vpr[] = {
|
||||||
|
{ REG_TYPE_ARCH_DEFINED, "vpr_reg", REG_TYPE_CLASS_FLAGS,
|
||||||
|
{ .reg_type_flags = armv8m_vpr_flags },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These registers are not memory-mapped. The ARMv7-M profile includes
|
* These registers are not memory-mapped. The ARMv7-M profile includes
|
||||||
* memory mapped registers too, such as for the NVIC (interrupt controller)
|
* memory mapped registers too, such as for the NVIC (interrupt controller)
|
||||||
|
@ -80,30 +102,31 @@ static const struct {
|
||||||
enum reg_type type;
|
enum reg_type type;
|
||||||
const char *group;
|
const char *group;
|
||||||
const char *feature;
|
const char *feature;
|
||||||
|
struct reg_data_type *data_type;
|
||||||
} armv7m_regs[] = {
|
} armv7m_regs[] = {
|
||||||
{ ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
{ ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" },
|
{ ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, },
|
||||||
|
|
||||||
{ ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
{ ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
|
|
||||||
/* A working register for packing/unpacking special regs, hidden from gdb */
|
/* A working register for packing/unpacking special regs, hidden from gdb */
|
||||||
{ ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL },
|
{ ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL, NULL },
|
||||||
|
|
||||||
/* WARNING: If you use armv7m_write_core_reg() on one of 4 following
|
/* WARNING: If you use armv7m_write_core_reg() on one of 4 following
|
||||||
* special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL
|
* special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL
|
||||||
|
@ -111,52 +134,54 @@ static const struct {
|
||||||
* To trigger write to CPU HW register, add
|
* To trigger write to CPU HW register, add
|
||||||
* armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,);
|
* armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,);
|
||||||
*/
|
*/
|
||||||
{ ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
{ ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
{ ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
{ ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, },
|
||||||
|
|
||||||
/* ARMv8-M security extension (TrustZone) specific registers */
|
/* ARMv8-M security extension (TrustZone) specific registers */
|
||||||
{ ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
|
|
||||||
{ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL },
|
{ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL, NULL, },
|
||||||
{ ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
|
|
||||||
{ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL },
|
{ ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL, NULL, },
|
||||||
{ ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
{ ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
{ ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, },
|
||||||
|
|
||||||
/* FPU registers */
|
/* FPU registers */
|
||||||
{ ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
{ ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
|
|
||||||
{ ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" },
|
{ ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp", NULL, },
|
||||||
|
|
||||||
|
{ ARMV8M_VPR, "vpr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.m-profile-mve", armv8m_flags_vpr, },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
|
#define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs)
|
||||||
|
@ -272,6 +297,9 @@ uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
|
||||||
case ARMV7M_FPSCR:
|
case ARMV7M_FPSCR:
|
||||||
return ARMV7M_REGSEL_FPSCR;
|
return ARMV7M_REGSEL_FPSCR;
|
||||||
|
|
||||||
|
case ARMV8M_VPR:
|
||||||
|
return ARMV8M_REGSEL_VPR;
|
||||||
|
|
||||||
case ARMV7M_D0 ... ARMV7M_D15:
|
case ARMV7M_D0 ... ARMV7M_D15:
|
||||||
return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0);
|
return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0);
|
||||||
|
|
||||||
|
@ -811,10 +839,14 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target)
|
||||||
LOG_TARGET_ERROR(target, "unable to allocate feature list");
|
LOG_TARGET_ERROR(target, "unable to allocate feature list");
|
||||||
|
|
||||||
reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
|
reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type));
|
||||||
if (reg_list[i].reg_data_type)
|
if (reg_list[i].reg_data_type) {
|
||||||
reg_list[i].reg_data_type->type = armv7m_regs[i].type;
|
if (armv7m_regs[i].data_type)
|
||||||
else
|
*reg_list[i].reg_data_type = *armv7m_regs[i].data_type;
|
||||||
|
else
|
||||||
|
reg_list[i].reg_data_type->type = armv7m_regs[i].type;
|
||||||
|
} else {
|
||||||
LOG_TARGET_ERROR(target, "unable to allocate reg type list");
|
LOG_TARGET_ERROR(target, "unable to allocate reg type list");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arm->cpsr = reg_list + ARMV7M_XPSR;
|
arm->cpsr = reg_list + ARMV7M_XPSR;
|
||||||
|
|
|
@ -62,6 +62,7 @@ enum {
|
||||||
ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14,
|
ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14,
|
||||||
ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22,
|
ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22,
|
||||||
ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS = 0x23,
|
ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS = 0x23,
|
||||||
|
ARMV8M_REGSEL_VPR = 0x24,
|
||||||
ARMV7M_REGSEL_FPSCR = 0x21,
|
ARMV7M_REGSEL_FPSCR = 0x21,
|
||||||
|
|
||||||
/* 32bit Floating-point registers */
|
/* 32bit Floating-point registers */
|
||||||
|
@ -196,12 +197,15 @@ enum {
|
||||||
/* Floating-point status register */
|
/* Floating-point status register */
|
||||||
ARMV7M_FPSCR,
|
ARMV7M_FPSCR,
|
||||||
|
|
||||||
|
/* Vector Predication Status and Control Register */
|
||||||
|
ARMV8M_VPR,
|
||||||
|
|
||||||
/* for convenience add registers' block delimiters */
|
/* for convenience add registers' block delimiters */
|
||||||
ARMV7M_LAST_REG,
|
ARMV7M_LAST_REG,
|
||||||
ARMV7M_CORE_FIRST_REG = ARMV7M_R0,
|
ARMV7M_CORE_FIRST_REG = ARMV7M_R0,
|
||||||
ARMV7M_CORE_LAST_REG = ARMV7M_XPSR,
|
ARMV7M_CORE_LAST_REG = ARMV7M_XPSR,
|
||||||
ARMV7M_FPU_FIRST_REG = ARMV7M_D0,
|
ARMV7M_FPU_FIRST_REG = ARMV7M_D0,
|
||||||
ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR,
|
ARMV7M_FPU_LAST_REG = ARMV8M_VPR,
|
||||||
ARMV8M_FIRST_REG = ARMV8M_MSP_NS,
|
ARMV8M_FIRST_REG = ARMV8M_MSP_NS,
|
||||||
ARMV8M_LAST_REG = ARMV8M_CONTROL_NS,
|
ARMV8M_LAST_REG = ARMV8M_CONTROL_NS,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1966,7 +1966,7 @@ int armv8_get_gdb_reg_list(struct target *target,
|
||||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||||
|
|
||||||
for (i = 0; i < *reg_list_size; i++)
|
for (i = 0; i < *reg_list_size; i++)
|
||||||
(*reg_list)[i] = armv8_reg_current(arm, i);
|
(*reg_list)[i] = armv8_reg_current(arm, i);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
case REG_CLASS_ALL:
|
case REG_CLASS_ALL:
|
||||||
|
@ -1974,7 +1974,7 @@ int armv8_get_gdb_reg_list(struct target *target,
|
||||||
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
*reg_list = malloc(sizeof(struct reg *) * (*reg_list_size));
|
||||||
|
|
||||||
for (i = 0; i < *reg_list_size; i++)
|
for (i = 0; i < *reg_list_size; i++)
|
||||||
(*reg_list)[i] = armv8_reg_current(arm, i);
|
(*reg_list)[i] = armv8_reg_current(arm, i);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
|
|
|
@ -1324,21 +1324,21 @@ static int cortex_a_set_breakpoint(struct target *target,
|
||||||
brp_list[brp_i].value);
|
brp_list[brp_i].value);
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
} else if (breakpoint->type == BKPT_SOFT) {
|
||||||
uint8_t code[4];
|
uint8_t code[4];
|
||||||
/* length == 2: Thumb breakpoint */
|
if (breakpoint->length == 2) {
|
||||||
if (breakpoint->length == 2)
|
/* length == 2: Thumb breakpoint */
|
||||||
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
||||||
else
|
} else if (breakpoint->length == 3) {
|
||||||
/* length == 3: Thumb-2 breakpoint, actual encoding is
|
/* length == 3: Thumb-2 breakpoint, actual encoding is
|
||||||
* a regular Thumb BKPT instruction but we replace a
|
* a regular Thumb BKPT instruction but we replace a
|
||||||
* 32bit Thumb-2 instruction, so fix-up the breakpoint
|
* 32bit Thumb-2 instruction, so fix-up the breakpoint
|
||||||
* length
|
* length
|
||||||
*/
|
*/
|
||||||
if (breakpoint->length == 3) {
|
|
||||||
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11));
|
||||||
breakpoint->length = 4;
|
breakpoint->length = 4;
|
||||||
} else
|
} else {
|
||||||
/* length == 4, normal ARM breakpoint */
|
/* length == 4, normal ARM breakpoint */
|
||||||
buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11));
|
buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11));
|
||||||
|
}
|
||||||
|
|
||||||
retval = target_read_memory(target,
|
retval = target_read_memory(target,
|
||||||
breakpoint->address & 0xFFFFFFFE,
|
breakpoint->address & 0xFFFFFFFE,
|
||||||
|
@ -1348,8 +1348,7 @@ static int cortex_a_set_breakpoint(struct target *target,
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* make sure data cache is cleaned & invalidated down to PoC */
|
/* make sure data cache is cleaned & invalidated down to PoC */
|
||||||
armv7a_cache_flush_virt(target, breakpoint->address,
|
armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length);
|
||||||
breakpoint->length);
|
|
||||||
|
|
||||||
retval = target_write_memory(target,
|
retval = target_write_memory(target,
|
||||||
breakpoint->address & 0xFFFFFFFE,
|
breakpoint->address & 0xFFFFFFFE,
|
||||||
|
@ -1358,10 +1357,8 @@ static int cortex_a_set_breakpoint(struct target *target,
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* update i-cache at breakpoint location */
|
/* update i-cache at breakpoint location */
|
||||||
armv7a_l1_d_cache_inval_virt(target, breakpoint->address,
|
armv7a_l1_d_cache_inval_virt(target, breakpoint->address, breakpoint->length);
|
||||||
breakpoint->length);
|
armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length);
|
||||||
armv7a_l1_i_cache_inval_virt(target, breakpoint->address,
|
|
||||||
breakpoint->length);
|
|
||||||
|
|
||||||
breakpoint->is_set = true;
|
breakpoint->is_set = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2708,6 +2708,10 @@ int cortex_m_examine(struct target *target)
|
||||||
for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++)
|
for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++)
|
||||||
armv7m->arm.core_cache->reg_list[idx].exist = false;
|
armv7m->arm.core_cache->reg_list[idx].exist = false;
|
||||||
|
|
||||||
|
/* TODO: MVE can be present without floating points. Revisit this test */
|
||||||
|
if (armv7m->fp_feature != FPV5_MVE_F && armv7m->fp_feature != FPV5_MVE_I)
|
||||||
|
armv7m->arm.core_cache->reg_list[ARMV8M_VPR].exist = false;
|
||||||
|
|
||||||
if (!cortex_m_has_tz(target))
|
if (!cortex_m_has_tz(target))
|
||||||
for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++)
|
for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++)
|
||||||
armv7m->arm.core_cache->reg_list[idx].exist = false;
|
armv7m->arm.core_cache->reg_list[idx].exist = false;
|
||||||
|
|
|
@ -2357,7 +2357,7 @@ COMMAND_HANDLER(mips32_handle_scan_delay_command)
|
||||||
if (CMD_ARGC == 1)
|
if (CMD_ARGC == 1)
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay);
|
||||||
else if (CMD_ARGC > 1)
|
else if (CMD_ARGC > 1)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay);
|
command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay);
|
||||||
if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) {
|
if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) {
|
||||||
|
|
|
@ -1397,7 +1397,7 @@ COMMAND_HANDLER(mips_m4k_handle_scan_delay_command)
|
||||||
if (CMD_ARGC == 1)
|
if (CMD_ARGC == 1)
|
||||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay);
|
||||||
else if (CMD_ARGC > 1)
|
else if (CMD_ARGC > 1)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay);
|
command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay);
|
||||||
if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) {
|
if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) {
|
||||||
|
|
|
@ -689,15 +689,13 @@ static int stm8_write_flash(struct target *target, enum mem_type type,
|
||||||
if (stm8->flash_ncr2)
|
if (stm8->flash_ncr2)
|
||||||
stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt));
|
stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt));
|
||||||
blocksize = blocksize_param;
|
blocksize = blocksize_param;
|
||||||
} else
|
} else if ((bytecnt >= 4) && ((address & 0x3) == 0)) {
|
||||||
if ((bytecnt >= 4) && ((address & 0x3) == 0)) {
|
|
||||||
if (stm8->flash_cr2)
|
if (stm8->flash_cr2)
|
||||||
stm8_write_u8(target, stm8->flash_cr2, WPRG + opt);
|
stm8_write_u8(target, stm8->flash_cr2, WPRG + opt);
|
||||||
if (stm8->flash_ncr2)
|
if (stm8->flash_ncr2)
|
||||||
stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt));
|
stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt));
|
||||||
blocksize = 4;
|
blocksize = 4;
|
||||||
} else
|
} else if (blocksize != 1) {
|
||||||
if (blocksize != 1) {
|
|
||||||
if (stm8->flash_cr2)
|
if (stm8->flash_cr2)
|
||||||
stm8_write_u8(target, stm8->flash_cr2, opt);
|
stm8_write_u8(target, stm8->flash_cr2, opt);
|
||||||
if (stm8->flash_ncr2)
|
if (stm8->flash_ncr2)
|
||||||
|
@ -1552,8 +1550,8 @@ static int stm8_set_watchpoint(struct target *target,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (watchpoint->length != 1) {
|
if (watchpoint->length != 1) {
|
||||||
LOG_ERROR("Only watchpoints of length 1 are supported");
|
LOG_ERROR("Only watchpoints of length 1 are supported");
|
||||||
return ERROR_TARGET_UNALIGNED_ACCESS;
|
return ERROR_TARGET_UNALIGNED_ACCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum hw_break_type enable = 0;
|
enum hw_break_type enable = 0;
|
||||||
|
|
|
@ -749,10 +749,10 @@ COMMAND_HANDLER(handle_xsvf_command)
|
||||||
int delay;
|
int delay;
|
||||||
|
|
||||||
if (read(xsvf_fd, &wait_local, 1) < 0
|
if (read(xsvf_fd, &wait_local, 1) < 0
|
||||||
|| read(xsvf_fd, &end, 1) < 0
|
|| read(xsvf_fd, &end, 1) < 0
|
||||||
|| read(xsvf_fd, delay_buf, 4) < 0) {
|
|| read(xsvf_fd, delay_buf, 4) < 0) {
|
||||||
do_abort = 1;
|
do_abort = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_state = xsvf_to_tap(wait_local);
|
wait_state = xsvf_to_tap(wait_local);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Example config for using Linux spidev as a SWD adapter.
|
||||||
|
|
||||||
|
adapter driver linuxspidev
|
||||||
|
adapter speed 3000
|
||||||
|
spidev path "/dev/spidev0.0"
|
||||||
|
spidev mode 3
|
||||||
|
spidev queue_entries 64
|
Loading…
Reference in New Issue