Merge commit '228fe7300c7df7aa05ba2c0bc19edde6d0156401' into from_upstream
Conflicts: doc/openocd.texi src/jtag/aice/aice_pipe.c src/jtag/aice/aice_usb.c src/rtos/FreeRTOS.c src/rtos/hwthread.c src/rtos/rtos_standard_stackings.c src/target/riscv/riscv.c Change-Id: I0c6228c499d60274325be895fbcd8007ed1699bc
This commit is contained in:
commit
da44fb5407
99
NEWS
99
NEWS
|
@ -2,126 +2,29 @@ This file includes highlights of the changes made in the OpenOCD
|
||||||
source archive release.
|
source archive release.
|
||||||
|
|
||||||
JTAG Layer:
|
JTAG Layer:
|
||||||
* add default to adapter speed when unspecified (100 kHz)
|
|
||||||
* AM335X gpio (BeagleBones) adapter driver
|
|
||||||
* BCM2835 support for SWD
|
|
||||||
* Cadence Virtual Debug (vdebug) adapter driver
|
|
||||||
* CMSIS-DAP support for SWO and SWD multidrop
|
|
||||||
* Espressif USB JTAG Programmer adapter driver
|
|
||||||
* Remote bitbang support for Windows host
|
|
||||||
* ST-LINK add TCP server support to adapter driver
|
|
||||||
* SWD multidrop support
|
|
||||||
|
|
||||||
Boundary Scan:
|
Boundary Scan:
|
||||||
|
|
||||||
Target Layer:
|
Target Layer:
|
||||||
* aarch64: support watchpoints
|
|
||||||
* arm: support independent TPIU and SWO for trace
|
|
||||||
* arm adi v5: support Large Physical Address Extension
|
|
||||||
* arm adi v6: support added, for jtag and swd transport
|
|
||||||
* cortex_a: support watchpoints
|
|
||||||
* elf 64bit load support
|
|
||||||
* Espressif: support ESP32, ESP32-S2 and ESP32-S3 cores
|
|
||||||
* semihosting: support user defined operations
|
|
||||||
* Xtensa: support Xtensa LX architecture via JTAG and ADIv5 DAP
|
|
||||||
|
|
||||||
Flash Layer:
|
Flash Layer:
|
||||||
* Atmel/Microchip SAM E51G18A, E51G19A, R35J18B, LAN9255 support
|
|
||||||
* GigaDevice GD32E23x, GD32F1x0/3x0, GD32VF103 support
|
|
||||||
* Nuvoton NPCX series support
|
|
||||||
* onsemi RSL10 support
|
|
||||||
* Raspberry Pi Pico RP2040 support
|
|
||||||
* ST BlueNRG-LPS support
|
|
||||||
* ST STM32 G05x, G06x, G0Bx, G0Cx, U57x, U58x, WB1x, WL5x support
|
|
||||||
* ST STM32 G0, G4, L4, L4+, L5, WB, WL OTP support
|
|
||||||
|
|
||||||
Board, Target, and Interface Configuration Scripts:
|
Board, Target, and Interface Configuration Scripts:
|
||||||
* Ampere Computing eMAG8180, Altra ("Quicksilver") and Altra Max ("Mystique") board config
|
|
||||||
* Cadence KC705 FPGA (Xtensa Development Platform) via JTAG and ADIv5 DAP board config
|
|
||||||
* Digilent Nexys Video board config
|
|
||||||
* Espressif ESP32 ETHERNET-KIT and WROVER-KIT board config
|
|
||||||
* Espressif ESP32 via ESP USB Bridge generic board config
|
|
||||||
* Espressif ESP32-S2 Kaluga 1 board config
|
|
||||||
* Espressif ESP32-S2 with ESP USB Bridge board config
|
|
||||||
* Espressif ESP32-S3 example board config
|
|
||||||
* Kontron SMARC-sAL28 board config
|
|
||||||
* LambdaConcept ECPIX-5 board config
|
|
||||||
* Microchip ATSAMA5D27-SOM1-EK1 board config
|
|
||||||
* Microchip EVB-LAN9255 board config
|
|
||||||
* Microchip SAME51 Curiosity Nano board config
|
|
||||||
* NXP FRDM-K64F, LS1046ARDB and LS1088ARDB board config
|
|
||||||
* NXP RT6XX board config
|
|
||||||
* Olimex H405 board config
|
|
||||||
* Radiona ULX3S board config
|
|
||||||
* Raspberry Pi 3 and Raspberry Pi 4 model B board config
|
|
||||||
* Raspberry Pi Pico-Debug board config
|
|
||||||
* Renesas R-Car V3U Falcon board config
|
|
||||||
* ST BlueNRG-LPS steval-idb012v1 board config
|
|
||||||
* ST NUCLEO-8S208RB board config
|
|
||||||
* ST NUCLEO-G031K8, NUCLEO-G070RB, NUCLEO-G071RB board config
|
|
||||||
* ST NUCLEO-G431KB, NUCLEO-G431RB, NUCLEO-G474RE board config
|
|
||||||
* ST STM32MP13x-DK board config
|
|
||||||
* TI AM625 EVM, AM642 EVM and AM654 EVM board config
|
|
||||||
* TI J721E EVM, J721S2 EVM and J7200 EVM board config
|
|
||||||
* Ampere Computing eMAG, Altra ("Quicksilver") and Altra Max ("Mystique") target config
|
|
||||||
* Cadence Xtensa generic and Xtensa VDebug target config
|
|
||||||
* Broadcom BCM2711, BCM2835, BCM2836 and BCM2837 target config
|
|
||||||
* Espressif ESP32, ESP32-S2 and ESP32-S3 target config
|
|
||||||
* Microchip ATSAMA5D2 series target config
|
|
||||||
* NanoXplore NG-Ultra SoC target config
|
|
||||||
* NXP IMX8QM target config
|
|
||||||
* NXP LS1028A, LS1046A and LS1088A target config
|
|
||||||
* NXP RT600 (Xtensa HiFi DSP) target config
|
|
||||||
* onsemi RSL10 target config
|
|
||||||
* Raspberry Pi Pico RP2040 target config
|
|
||||||
* Renesas R8A779A0 V3U target config
|
|
||||||
* Renesas RZ/Five target config
|
|
||||||
* Renesas RZ/G2 MPU family target config
|
|
||||||
* Rockchip RK3399 target config
|
|
||||||
* ST BlueNRG-LPS target config
|
|
||||||
* ST STM32MP13x target config
|
|
||||||
* TI AM625, AM654, J721E and J721S2 target config
|
|
||||||
* Ashling Opella-LD interface config
|
|
||||||
* Aspeed AST2600 linuxgpiod based interface config
|
|
||||||
* Blinkinlabs JTAG_Hat interface config
|
|
||||||
* Cadence Virtual Debug (vdebug) interface config
|
|
||||||
* Espressif ESP32-S2 Kaluga 1 board's interface config
|
|
||||||
* Espressif USB Bridge jtag interface config
|
|
||||||
* Infineon DAP miniWiggler V3 interface config
|
|
||||||
* PLS SPC5 interface config
|
|
||||||
* Tigard interface config
|
|
||||||
* Lattice MachXO3 family FPGA config
|
|
||||||
|
|
||||||
Server Layer:
|
Server Layer:
|
||||||
* GDB: add per-target remote protocol extensions
|
|
||||||
* GDB: more 'Z' packets support
|
|
||||||
* IPDBG JtagHost server functionality
|
|
||||||
* semihosting: I/O redirection to TCP server
|
|
||||||
* telnet: support for command's autocomplete
|
|
||||||
|
|
||||||
RTOS:
|
RTOS:
|
||||||
* 'none' rtos support
|
|
||||||
* Zephyr rtos support
|
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
|
|
||||||
Build and Release:
|
Build and Release:
|
||||||
* Add json extension to jimtcl build
|
|
||||||
* Drop dependency from libusb0
|
|
||||||
* Drop repository repo.or.cz for submodules
|
|
||||||
* Move gerrit to https://review.openocd.org/
|
|
||||||
* Require autoconf 2.69 or newer
|
|
||||||
* Update jep106 to revision JEP106BE
|
|
||||||
* Update jimtcl to version 0.81
|
|
||||||
* Update libjaylink to version 0.3.1
|
|
||||||
* New configure flag '--enable-jimtcl-maintainer' for jimtcl build
|
|
||||||
|
|
||||||
|
|
||||||
This release also contains a number of other important functional and
|
This release also contains a number of other important functional and
|
||||||
cosmetic bugfixes. For more details about what has changed since the
|
cosmetic bugfixes. For more details about what has changed since the
|
||||||
last release, see the git repository history:
|
last release, see the git repository history:
|
||||||
|
|
||||||
http://sourceforge.net/p/openocd/code/ci/v0.12.0-rc1/log/?path=
|
http://sourceforge.net/p/openocd/code/ci/v0.x.0/log/?path=
|
||||||
|
|
||||||
|
|
||||||
For older NEWS, see the NEWS files associated with each release
|
For older NEWS, see the NEWS files associated with each release
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
This file includes highlights of the changes made in the OpenOCD
|
||||||
|
source archive release.
|
||||||
|
|
||||||
|
JTAG Layer:
|
||||||
|
* add default to adapter speed when unspecified (100 kHz)
|
||||||
|
* AM335X gpio (BeagleBones) adapter driver
|
||||||
|
* BCM2835 support for SWD
|
||||||
|
* Cadence Virtual Debug (vdebug) adapter driver
|
||||||
|
* CMSIS-DAP support for SWO and SWD multidrop
|
||||||
|
* Espressif USB JTAG Programmer adapter driver
|
||||||
|
* Remote bitbang support for Windows host
|
||||||
|
* ST-LINK add TCP server support to adapter driver
|
||||||
|
* SWD multidrop support
|
||||||
|
|
||||||
|
Boundary Scan:
|
||||||
|
|
||||||
|
Target Layer:
|
||||||
|
* aarch64: support watchpoints
|
||||||
|
* arm: support independent TPIU and SWO for trace
|
||||||
|
* arm adi v5: support Large Physical Address Extension
|
||||||
|
* arm adi v6: support added, for jtag and swd transport
|
||||||
|
* cortex_a: support watchpoints
|
||||||
|
* elf 64bit load support
|
||||||
|
* Espressif: support ESP32, ESP32-S2 and ESP32-S3 cores
|
||||||
|
* semihosting: support user defined operations
|
||||||
|
* Xtensa: support Xtensa LX architecture via JTAG and ADIv5 DAP
|
||||||
|
|
||||||
|
Flash Layer:
|
||||||
|
* Atmel/Microchip SAM E51G18A, E51G19A, R35J18B, LAN9255 support
|
||||||
|
* GigaDevice GD32E23x, GD32F1x0/3x0, GD32VF103 support
|
||||||
|
* Nuvoton NPCX series support
|
||||||
|
* onsemi RSL10 support
|
||||||
|
* Raspberry Pi Pico RP2040 support
|
||||||
|
* ST BlueNRG-LPS support
|
||||||
|
* ST STM32 G05x, G06x, G0Bx, G0Cx, U57x, U58x, WB1x, WL5x support
|
||||||
|
* ST STM32 G0, G4, L4, L4+, L5, WB, WL OTP support
|
||||||
|
|
||||||
|
Board, Target, and Interface Configuration Scripts:
|
||||||
|
* Ampere Computing eMAG8180, Altra ("Quicksilver") and Altra Max ("Mystique") board config
|
||||||
|
* Cadence KC705 FPGA (Xtensa Development Platform) via JTAG and ADIv5 DAP board config
|
||||||
|
* Digilent Nexys Video board config
|
||||||
|
* Espressif ESP32 ETHERNET-KIT and WROVER-KIT board config
|
||||||
|
* Espressif ESP32 via ESP USB Bridge generic board config
|
||||||
|
* Espressif ESP32-S2 Kaluga 1 board config
|
||||||
|
* Espressif ESP32-S2 with ESP USB Bridge board config
|
||||||
|
* Espressif ESP32-S3 example board config
|
||||||
|
* Kontron SMARC-sAL28 board config
|
||||||
|
* LambdaConcept ECPIX-5 board config
|
||||||
|
* Microchip ATSAMA5D27-SOM1-EK1 board config
|
||||||
|
* Microchip EVB-LAN9255 board config
|
||||||
|
* Microchip SAME51 Curiosity Nano board config
|
||||||
|
* NXP FRDM-K64F, LS1046ARDB and LS1088ARDB board config
|
||||||
|
* NXP RT6XX board config
|
||||||
|
* Olimex H405 board config
|
||||||
|
* Radiona ULX3S board config
|
||||||
|
* Raspberry Pi 3 and Raspberry Pi 4 model B board config
|
||||||
|
* Raspberry Pi Pico-Debug board config
|
||||||
|
* Renesas R-Car V3U Falcon board config
|
||||||
|
* ST BlueNRG-LPS steval-idb012v1 board config
|
||||||
|
* ST NUCLEO-8S208RB board config
|
||||||
|
* ST NUCLEO-G031K8, NUCLEO-G070RB, NUCLEO-G071RB board config
|
||||||
|
* ST NUCLEO-G431KB, NUCLEO-G431RB, NUCLEO-G474RE board config
|
||||||
|
* ST STM32MP13x-DK board config
|
||||||
|
* TI AM625 EVM, AM642 EVM and AM654 EVM board config
|
||||||
|
* TI J721E EVM, J721S2 EVM and J7200 EVM board config
|
||||||
|
* Ampere Computing eMAG, Altra ("Quicksilver") and Altra Max ("Mystique") target config
|
||||||
|
* Cadence Xtensa generic and Xtensa VDebug target config
|
||||||
|
* Broadcom BCM2711, BCM2835, BCM2836 and BCM2837 target config
|
||||||
|
* Espressif ESP32, ESP32-S2 and ESP32-S3 target config
|
||||||
|
* Microchip ATSAMA5D2 series target config
|
||||||
|
* NanoXplore NG-Ultra SoC target config
|
||||||
|
* NXP IMX8QM target config
|
||||||
|
* NXP LS1028A, LS1046A and LS1088A target config
|
||||||
|
* NXP RT600 (Xtensa HiFi DSP) target config
|
||||||
|
* onsemi RSL10 target config
|
||||||
|
* Raspberry Pi Pico RP2040 target config
|
||||||
|
* Renesas R8A779A0 V3U target config
|
||||||
|
* Renesas RZ/Five target config
|
||||||
|
* Renesas RZ/G2 MPU family target config
|
||||||
|
* Rockchip RK3399 target config
|
||||||
|
* ST BlueNRG-LPS target config
|
||||||
|
* ST STM32MP13x target config
|
||||||
|
* TI AM625, AM654, J721E and J721S2 target config
|
||||||
|
* Ashling Opella-LD interface config
|
||||||
|
* Aspeed AST2600 linuxgpiod based interface config
|
||||||
|
* Blinkinlabs JTAG_Hat interface config
|
||||||
|
* Cadence Virtual Debug (vdebug) interface config
|
||||||
|
* Espressif ESP32-S2 Kaluga 1 board's interface config
|
||||||
|
* Espressif USB Bridge jtag interface config
|
||||||
|
* Infineon DAP miniWiggler V3 interface config
|
||||||
|
* PLS SPC5 interface config
|
||||||
|
* Tigard interface config
|
||||||
|
* Lattice MachXO3 family FPGA config
|
||||||
|
|
||||||
|
Server Layer:
|
||||||
|
* GDB: add per-target remote protocol extensions
|
||||||
|
* GDB: more 'Z' packets support
|
||||||
|
* IPDBG JtagHost server functionality
|
||||||
|
* semihosting: I/O redirection to TCP server
|
||||||
|
* telnet: support for command's autocomplete
|
||||||
|
|
||||||
|
RTOS:
|
||||||
|
* 'none' rtos support
|
||||||
|
* Zephyr rtos support
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
Build and Release:
|
||||||
|
* Add json extension to jimtcl build
|
||||||
|
* Drop dependency from libusb0
|
||||||
|
* Drop repository repo.or.cz for submodules
|
||||||
|
* Move gerrit to https://review.openocd.org/
|
||||||
|
* Require autoconf 2.69 or newer
|
||||||
|
* Update jep106 to revision JEP106BF.01
|
||||||
|
* Update jimtcl to version 0.81
|
||||||
|
* Update libjaylink to version 0.3.1
|
||||||
|
* New configure flag '--enable-jimtcl-maintainer' for jimtcl build
|
||||||
|
|
||||||
|
|
||||||
|
This release also contains a number of other important functional and
|
||||||
|
cosmetic bugfixes. For more details about what has changed since the
|
||||||
|
last release, see the git repository history:
|
||||||
|
|
||||||
|
http://sourceforge.net/p/openocd/code/ci/v0.12.0/log/?path=
|
||||||
|
|
||||||
|
|
||||||
|
For older NEWS, see the NEWS files associated with each release
|
||||||
|
(i.e. NEWS-<version>).
|
||||||
|
|
||||||
|
For more information about contributing test reports, bug fixes, or new
|
||||||
|
features and device support, please read the new Developer Manual (or
|
||||||
|
the BUGS and PATCHES.txt files in the source archive).
|
29
README
29
README
|
@ -101,7 +101,7 @@ Supported hardware
|
||||||
JTAG adapters
|
JTAG adapters
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
AICE, AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835,
|
AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835,
|
||||||
Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP,
|
Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP,
|
||||||
Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H,
|
Cortino, Cypress KitProg, DENX, Digilent JTAG-SMT2, DLC 5, DLP-USB1232H,
|
||||||
embedded projects, Espressif USB JTAG Programmer,
|
embedded projects, Espressif USB JTAG Programmer,
|
||||||
|
@ -122,7 +122,7 @@ Debug targets
|
||||||
ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M),
|
ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M),
|
||||||
FA526, Feroceon/Dragonite, XScale.
|
FA526, Feroceon/Dragonite, XScale.
|
||||||
ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64),
|
ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64),
|
||||||
ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, NDS32, RISC-V, ST STM8,
|
ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8,
|
||||||
Xtensa.
|
Xtensa.
|
||||||
|
|
||||||
Flash drivers
|
Flash drivers
|
||||||
|
@ -219,7 +219,10 @@ You'll also need:
|
||||||
|
|
||||||
- make
|
- make
|
||||||
- libtool
|
- libtool
|
||||||
- pkg-config >= 0.23 (or compatible)
|
- pkg-config >= 0.23 or pkgconf
|
||||||
|
|
||||||
|
OpenOCD uses jimtcl library; build from git can retrieve jimtcl as git
|
||||||
|
submodule.
|
||||||
|
|
||||||
Additionally, for building from git:
|
Additionally, for building from git:
|
||||||
|
|
||||||
|
@ -227,14 +230,26 @@ Additionally, for building from git:
|
||||||
- automake >= 1.14
|
- automake >= 1.14
|
||||||
- texinfo >= 5.0
|
- texinfo >= 5.0
|
||||||
|
|
||||||
USB-based adapters depend on libusb-1.0. A compatible implementation, such as
|
Optional USB-based adapter drivers need libusb-1.0.
|
||||||
FreeBSD's, additionally needs the corresponding .pc files.
|
|
||||||
|
|
||||||
USB-Blaster, ASIX Presto and OpenJTAG interface adapter
|
Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter
|
||||||
drivers need:
|
drivers need:
|
||||||
- libftdi: http://www.intra2net.com/en/developer/libftdi/index.php
|
- libftdi: http://www.intra2net.com/en/developer/libftdi/index.php
|
||||||
|
|
||||||
CMSIS-DAP support needs HIDAPI library.
|
Optional CMSIS-DAP adapter driver needs HIDAPI library.
|
||||||
|
|
||||||
|
Optional linuxgpiod adapter driver needs libgpiod library.
|
||||||
|
|
||||||
|
Optional JLink adapter driver needs libjaylink; build from git can
|
||||||
|
retrieve libjaylink as git submodule.
|
||||||
|
|
||||||
|
Optional ARM disassembly needs capstone library.
|
||||||
|
|
||||||
|
Optional development script checkpatch needs:
|
||||||
|
|
||||||
|
- perl
|
||||||
|
- python
|
||||||
|
- python-ply
|
||||||
|
|
||||||
Permissions delegation
|
Permissions delegation
|
||||||
----------------------
|
----------------------
|
||||||
|
|
30
configure.ac
30
configure.ac
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([openocd], [0.12.0-rc1+dev],
|
AC_INIT([openocd], [0.12.0+dev],
|
||||||
[OpenOCD Mailing List <openocd-devel@lists.sourceforge.net>])
|
[OpenOCD Mailing List <openocd-devel@lists.sourceforge.net>])
|
||||||
AC_CONFIG_SRCDIR([src/openocd.c])
|
AC_CONFIG_SRCDIR([src/openocd.c])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
|
@ -131,9 +131,6 @@ m4_define([USB1_ADAPTERS],
|
||||||
[[usbprog], [USBProg JTAG Programmer], [USBPROG]],
|
[[usbprog], [USBProg JTAG Programmer], [USBPROG]],
|
||||||
[[esp_usb_jtag], [Espressif JTAG Programmer], [ESP_USB_JTAG]]])
|
[[esp_usb_jtag], [Espressif JTAG Programmer], [ESP_USB_JTAG]]])
|
||||||
|
|
||||||
m4_define([DEPRECATED_USB1_ADAPTERS],
|
|
||||||
[[[aice], [Andes JTAG Programmer (deprecated)], [AICE]]])
|
|
||||||
|
|
||||||
m4_define([HIDAPI_ADAPTERS],
|
m4_define([HIDAPI_ADAPTERS],
|
||||||
[[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]],
|
[[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]],
|
||||||
[[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]])
|
[[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]])
|
||||||
|
@ -265,8 +262,6 @@ AC_ARG_ADAPTERS([
|
||||||
LIBJAYLINK_ADAPTERS
|
LIBJAYLINK_ADAPTERS
|
||||||
],[auto])
|
],[auto])
|
||||||
|
|
||||||
AC_ARG_ADAPTERS([DEPRECATED_USB1_ADAPTERS],[no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([parport],
|
AC_ARG_ENABLE([parport],
|
||||||
AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]),
|
AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]),
|
||||||
[build_parport=$enableval], [build_parport=no])
|
[build_parport=$enableval], [build_parport=no])
|
||||||
|
@ -374,9 +369,9 @@ AC_ARG_ENABLE([jimtcl-maintainer],
|
||||||
[use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no])
|
[use_internal_jimtcl_maintainer=$enableval], [use_internal_jimtcl_maintainer=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE([internal-libjaylink],
|
AC_ARG_ENABLE([internal-libjaylink],
|
||||||
AS_HELP_STRING([--disable-internal-libjaylink],
|
AS_HELP_STRING([--enable-internal-libjaylink],
|
||||||
[Disable building internal libjaylink]),
|
[Enable building internal libjaylink]),
|
||||||
[use_internal_libjaylink=$enableval], [use_internal_libjaylink=yes])
|
[use_internal_libjaylink=$enableval], [use_internal_libjaylink=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE([remote-bitbang],
|
AC_ARG_ENABLE([remote-bitbang],
|
||||||
AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]),
|
AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]),
|
||||||
|
@ -575,7 +570,7 @@ AS_IF([test "x$enable_buspirate" != "xno"], [
|
||||||
])
|
])
|
||||||
|
|
||||||
AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
|
AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
|
||||||
AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [
|
AS_IF([test -f "$srcdir/jimtcl/configure"], [
|
||||||
AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [
|
AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [
|
||||||
jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer"
|
jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer"
|
||||||
], [
|
], [
|
||||||
|
@ -632,7 +627,6 @@ AS_IF([test "x$enable_capstone" != xno], [
|
||||||
PKG_CHECK_MODULES([CAPSTONE], [capstone], [
|
PKG_CHECK_MODULES([CAPSTONE], [capstone], [
|
||||||
AC_DEFINE([HAVE_CAPSTONE], [1], [1 if you have Capstone disassembly framework.])
|
AC_DEFINE([HAVE_CAPSTONE], [1], [1 if you have Capstone disassembly framework.])
|
||||||
], [
|
], [
|
||||||
AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.])
|
|
||||||
if test "x$enable_capstone" != xauto; then
|
if test "x$enable_capstone" != xauto; then
|
||||||
AC_MSG_ERROR([--with-capstone was given, but test for Capstone failed])
|
AC_MSG_ERROR([--with-capstone was given, but test for Capstone failed])
|
||||||
fi
|
fi
|
||||||
|
@ -640,6 +634,10 @@ AS_IF([test "x$enable_capstone" != xno], [
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_capstone" == xno], [
|
||||||
|
AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.])
|
||||||
|
])
|
||||||
|
|
||||||
for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
|
for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
|
||||||
PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[
|
PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[
|
||||||
use_hidapi=yes
|
use_hidapi=yes
|
||||||
|
@ -682,7 +680,6 @@ m4_define([PROCESS_ADAPTERS], [
|
||||||
])
|
])
|
||||||
|
|
||||||
PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x])
|
PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x])
|
||||||
PROCESS_ADAPTERS([DEPRECATED_USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x])
|
|
||||||
PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi])
|
PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi])
|
||||||
PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x])
|
PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x])
|
||||||
PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi])
|
PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi])
|
||||||
|
@ -711,7 +708,7 @@ AS_IF([test "x$enable_jlink" != "xno"], [
|
||||||
AX_CONFIG_SUBDIR_OPTION([src/jtag/drivers/libjaylink],
|
AX_CONFIG_SUBDIR_OPTION([src/jtag/drivers/libjaylink],
|
||||||
[--enable-subproject-build])
|
[--enable-subproject-build])
|
||||||
], [
|
], [
|
||||||
AC_MSG_ERROR([Internal libjaylink not found, run either 'git submodule init' and 'git submodule update' or disable internal libjaylink with --disable-internal-libjaylink.])
|
AC_MSG_ERROR([Internal libjaylink not found, run 'git submodule init' and 'git submodule update'.])
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
@ -821,12 +818,17 @@ AC_CONFIG_FILES([
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_jlink" != "xno"], [
|
||||||
|
AS_IF([test "x$use_internal_libjaylink" = "xyes"], [
|
||||||
|
AC_MSG_WARN([Using the internal libjaylink is deprecated and will not be possible in the future.])
|
||||||
|
]])
|
||||||
|
)
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo
|
echo
|
||||||
echo OpenOCD configuration summary
|
echo OpenOCD configuration summary
|
||||||
echo --------------------------------------------------
|
echo --------------------------------------------------
|
||||||
m4_foreach([adapter], [USB1_ADAPTERS,
|
m4_foreach([adapter], [USB1_ADAPTERS,
|
||||||
DEPRECATED_USB1_ADAPTERS,
|
|
||||||
HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS,
|
HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS,
|
||||||
LIBFTDI_USB1_ADAPTERS,
|
LIBFTDI_USB1_ADAPTERS,
|
||||||
LIBGPIOD_ADAPTERS,
|
LIBGPIOD_ADAPTERS,
|
||||||
|
|
|
@ -12,7 +12,6 @@ BR2_PACKAGE_OPENOCD_UBLASTER2=y
|
||||||
BR2_PACKAGE_OPENOCD_JLINK=y
|
BR2_PACKAGE_OPENOCD_JLINK=y
|
||||||
BR2_PACKAGE_OPENOCD_OSDBM=y
|
BR2_PACKAGE_OPENOCD_OSDBM=y
|
||||||
BR2_PACKAGE_OPENOCD_OPENDOUS=y
|
BR2_PACKAGE_OPENOCD_OPENDOUS=y
|
||||||
BR2_PACKAGE_OPENOCD_AICE=y
|
|
||||||
BR2_PACKAGE_OPENOCD_VSLLINK=y
|
BR2_PACKAGE_OPENOCD_VSLLINK=y
|
||||||
BR2_PACKAGE_OPENOCD_USBPROG=y
|
BR2_PACKAGE_OPENOCD_USBPROG=y
|
||||||
BR2_PACKAGE_OPENOCD_RLINK=y
|
BR2_PACKAGE_OPENOCD_RLINK=y
|
||||||
|
|
|
@ -1785,7 +1785,6 @@ $_TARGETNAME configure -work-area-phys 0x00200000 \
|
||||||
-work-area-size 0x4000 -work-area-backup 0
|
-work-area-size 0x4000 -work-area-backup 0
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@anchor{definecputargetsworkinginsmp}
|
|
||||||
@subsection Define CPU targets working in SMP
|
@subsection Define CPU targets working in SMP
|
||||||
@cindex SMP
|
@cindex SMP
|
||||||
After setting targets, you can define a list of targets working in SMP.
|
After setting targets, you can define a list of targets working in SMP.
|
||||||
|
@ -1939,7 +1938,6 @@ For an example of this scheme see LPC2000 target config files.
|
||||||
The @code{init_boards} procedure is a similar concept concerning board config files
|
The @code{init_boards} procedure is a similar concept concerning board config files
|
||||||
(@xref{theinitboardprocedure,,The init_board procedure}.)
|
(@xref{theinitboardprocedure,,The init_board procedure}.)
|
||||||
|
|
||||||
@anchor{theinittargeteventsprocedure}
|
|
||||||
@subsection The init_target_events procedure
|
@subsection The init_target_events procedure
|
||||||
@cindex init_target_events procedure
|
@cindex init_target_events procedure
|
||||||
|
|
||||||
|
@ -2468,7 +2466,6 @@ the generic mapping may not support all of the listed options.
|
||||||
Returns the name of the debug adapter driver being used.
|
Returns the name of the debug adapter driver being used.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@anchor{adapter_usb_location}
|
|
||||||
@deffn {Config Command} {adapter usb location} [<bus>-<port>[.<port>]...]
|
@deffn {Config Command} {adapter usb location} [<bus>-<port>[.<port>]...]
|
||||||
Displays or specifies the physical USB port of the adapter to use. The path
|
Displays or specifies the physical USB port of the adapter to use. The path
|
||||||
roots at @var{bus} and walks down the physical ports, with each
|
roots at @var{bus} and walks down the physical ports, with each
|
||||||
|
@ -2483,7 +2480,7 @@ This command is only available if your libusb1 is at least version 1.0.16.
|
||||||
Specifies the @var{serial_string} of the adapter to use.
|
Specifies the @var{serial_string} of the adapter to use.
|
||||||
If this command is not specified, serial strings are not checked.
|
If this command is not specified, serial strings are not checked.
|
||||||
Only the following adapter drivers use the serial string from this command:
|
Only the following adapter drivers use the serial string from this command:
|
||||||
aice (aice_usb), arm-jtag-ew, cmsis_dap, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus,
|
arm-jtag-ew, cmsis_dap, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus,
|
||||||
openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110.
|
openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@ -3533,11 +3530,11 @@ Espressif JTAG driver to communicate with ESP32-C3, ESP32-S3 chips and ESP USB B
|
||||||
These chips have built-in JTAG circuitry and can be debugged without any additional hardware.
|
These chips have built-in JTAG circuitry and can be debugged without any additional hardware.
|
||||||
Only an USB cable connected to the D+/D- pins is necessary.
|
Only an USB cable connected to the D+/D- pins is necessary.
|
||||||
|
|
||||||
@deffn {Config Command} {espusbjtag tdo}
|
@deffn {Command} {espusbjtag tdo}
|
||||||
Returns the current state of the TDO line
|
Returns the current state of the TDO line
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Config Command} {espusbjtag setio} setio
|
@deffn {Command} {espusbjtag setio} setio
|
||||||
Manually set the status of the output lines with the order of (tdi tms tck trst srst)
|
Manually set the status of the output lines with the order of (tdi tms tck trst srst)
|
||||||
@example
|
@example
|
||||||
espusbjtag setio 0 1 0 1 0
|
espusbjtag setio 0 1 0 1 0
|
||||||
|
@ -4859,9 +4856,6 @@ specified, @xref{gdbportoverride,,option -gdb-port}.), and a fake ARM core will
|
||||||
be emulated to comply to GDB remote protocol.
|
be emulated to comply to GDB remote protocol.
|
||||||
@item @code{mips_m4k} -- a MIPS core.
|
@item @code{mips_m4k} -- a MIPS core.
|
||||||
@item @code{mips_mips64} -- a MIPS64 core.
|
@item @code{mips_mips64} -- a MIPS64 core.
|
||||||
@item @code{nds32_v2} -- this is an Andes NDS32 v2 core (deprecated; would be removed in v0.13.0).
|
|
||||||
@item @code{nds32_v3} -- this is an Andes NDS32 v3 core (deprecated; would be removed in v0.13.0).
|
|
||||||
@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core (deprecated; would be removed in v0.13.0).
|
|
||||||
@item @code{or1k} -- this is an OpenRISC 1000 core.
|
@item @code{or1k} -- this is an OpenRISC 1000 core.
|
||||||
The current implementation supports three JTAG TAP cores:
|
The current implementation supports three JTAG TAP cores:
|
||||||
@itemize @minus
|
@itemize @minus
|
||||||
|
@ -6236,7 +6230,6 @@ the flash.
|
||||||
@end deffn
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@anchor{at91samd}
|
|
||||||
@deffn {Flash Driver} {at91samd}
|
@deffn {Flash Driver} {at91samd}
|
||||||
@cindex at91samd
|
@cindex at91samd
|
||||||
All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller
|
All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller
|
||||||
|
@ -8513,12 +8506,20 @@ that particular type of PLD.
|
||||||
|
|
||||||
@deffn {FPGA Driver} {virtex2} [no_jstart]
|
@deffn {FPGA Driver} {virtex2} [no_jstart]
|
||||||
Virtex-II is a family of FPGAs sold by Xilinx.
|
Virtex-II is a family of FPGAs sold by Xilinx.
|
||||||
|
This driver can also be used to load Series3, Series6, Series7 and Zynq 7000 devices.
|
||||||
It supports the IEEE 1532 standard for In-System Configuration (ISC).
|
It supports the IEEE 1532 standard for In-System Configuration (ISC).
|
||||||
|
|
||||||
If @var{no_jstart} is non-zero, the JSTART instruction is not used after
|
If @var{no_jstart} is non-zero, the JSTART instruction is not used after
|
||||||
loading the bitstream. While required for Series2, Series3, and Series6, it
|
loading the bitstream. While required for Series2, Series3, and Series6, it
|
||||||
breaks bitstream loading on Series7.
|
breaks bitstream loading on Series7.
|
||||||
|
|
||||||
|
@example
|
||||||
|
openocd -f board/digilent_zedboard.cfg -c "init" \
|
||||||
|
-c "pld load 0 zedboard_bitstream.bit"
|
||||||
|
@end example
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@deffn {Command} {virtex2 read_stat} num
|
@deffn {Command} {virtex2 read_stat} num
|
||||||
Reads and displays the Virtex-II status register (STAT)
|
Reads and displays the Virtex-II status register (STAT)
|
||||||
for FPGA @var{num}.
|
for FPGA @var{num}.
|
||||||
|
@ -8550,7 +8551,7 @@ command. All output is relayed through the GDB session.
|
||||||
|
|
||||||
@item @b{Machine Interface}
|
@item @b{Machine Interface}
|
||||||
The Tcl interface's intent is to be a machine interface. The default Tcl
|
The Tcl interface's intent is to be a machine interface. The default Tcl
|
||||||
port is 5555.
|
port is 6666.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
|
@ -9533,14 +9534,14 @@ requests by using a special SVC instruction that is trapped at the
|
||||||
Supervisor Call vector by OpenOCD.
|
Supervisor Call vector by OpenOCD.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} <port>
|
@deffn {Command} {arm semihosting_redirect} (@option{disable} | @option{tcp} <port> [@option{debug}|@option{stdio}|@option{all}])
|
||||||
[@option{debug}|@option{stdio}|@option{all})
|
|
||||||
@cindex ARM semihosting
|
@cindex ARM semihosting
|
||||||
Redirect semihosting messages to a specified TCP port.
|
Redirect semihosting messages to a specified TCP port.
|
||||||
|
|
||||||
This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE)
|
This command redirects debug (READC, WRITEC and WRITE0) and stdio (READ, WRITE)
|
||||||
semihosting operations to the specified TCP port.
|
semihosting operations to the specified TCP port.
|
||||||
The command allows to select which type of operations to redirect (debug, stdio, all (default)).
|
The command allows to select which type of operations to redirect (debug, stdio, all (default)).
|
||||||
|
|
||||||
Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected.
|
Note: for stdio operations, only I/O from/to ':tt' file descriptors are redirected.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@ -10327,6 +10328,16 @@ the target, the exception catch must be disabled again with @command{$target_nam
|
||||||
Issuing the command without options prints the current configuration.
|
Issuing the command without options prints the current configuration.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {$target_name pauth} [@option{off}|@option{on}]
|
||||||
|
Enable or disable pointer authentication features.
|
||||||
|
When pointer authentication is used on ARM cores, GDB asks GDB servers for an 8-bytes mask to remove signature bits added by pointer authentication.
|
||||||
|
If this feature is enabled, OpenOCD provides GDB with an 8-bytes mask.
|
||||||
|
Pointer authentication feature is broken until gdb 12.1, going to be fixed.
|
||||||
|
Consider using a newer version of gdb if you want to enable pauth feature.
|
||||||
|
The default configuration is @option{off}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
|
||||||
@section EnSilica eSi-RISC Architecture
|
@section EnSilica eSi-RISC Architecture
|
||||||
|
|
||||||
eSi-RISC is a highly configurable microprocessor architecture for embedded systems
|
eSi-RISC is a highly configurable microprocessor architecture for embedded systems
|
||||||
|
@ -10724,6 +10735,16 @@ to read out a buffer that's memory-mapped to be accessed through a single
|
||||||
address, or to sample a changing value in a memory-mapped device.
|
address, or to sample a changing value in a memory-mapped device.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {riscv info}
|
||||||
|
Displays some information OpenOCD detected about the target.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {riscv reset_delays} [wait]
|
||||||
|
OpenOCD learns how many Run-Test/Idle cycles are required between scans to avoid
|
||||||
|
encountering the target being busy. This command resets those learned values
|
||||||
|
after `wait` scans. It's only useful for testing OpenOCD itself.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {riscv set_command_timeout_sec} [seconds]
|
@deffn {Command} {riscv set_command_timeout_sec} [seconds]
|
||||||
Set the wall-clock timeout (in seconds) for individual commands. The default
|
Set the wall-clock timeout (in seconds) for individual commands. The default
|
||||||
should work fine for all but the slowest targets (eg. simulators).
|
should work fine for all but the slowest targets (eg. simulators).
|
||||||
|
@ -10739,7 +10760,7 @@ Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'.
|
||||||
This is used to access 64-bit floating point registers on 32-bit targets.
|
This is used to access 64-bit floating point registers on 32-bit targets.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_mem_access} method1 [method2] [method3]
|
@deffn {Command} {riscv set_mem_access} method1 [method2] [method3]
|
||||||
Specify which RISC-V memory access method(s) shall be used, and in which order
|
Specify which RISC-V memory access method(s) shall be used, and in which order
|
||||||
of priority. At least one method must be specified.
|
of priority. At least one method must be specified.
|
||||||
|
|
||||||
|
@ -11164,12 +11185,12 @@ NXP}.
|
||||||
|
|
||||||
@subsection Xtensa Configuration Commands
|
@subsection Xtensa Configuration Commands
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtdef} (@option{LX}|@option{NX})
|
@deffn {Config Command} {xtensa xtdef} (@option{LX}|@option{NX})
|
||||||
Configure the Xtensa target architecture. Currently, Xtensa support is limited
|
Configure the Xtensa target architecture. Currently, Xtensa support is limited
|
||||||
to LX6, LX7, and NX cores.
|
to LX6, LX7, and NX cores.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtopt} option value
|
@deffn {Config Command} {xtensa xtopt} option value
|
||||||
Configure Xtensa target options that are relevant to the debug subsystem.
|
Configure Xtensa target options that are relevant to the debug subsystem.
|
||||||
@var{option} is one of: @option{arnum}, @option{windowed},
|
@var{option} is one of: @option{arnum}, @option{windowed},
|
||||||
@option{cpenable}, @option{exceptions}, @option{intnum}, @option{hipriints},
|
@option{cpenable}, @option{exceptions}, @option{intnum}, @option{hipriints},
|
||||||
|
@ -11181,35 +11202,35 @@ NOTE: Some options are specific to Xtensa LX or Xtensa NX architecture, while
|
||||||
others may be common to both but have different valid ranges.
|
others may be common to both but have different valid ranges.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtmem} (@option{iram}|@option{dram}|@option{sram}|@option{irom}|@option{drom}|@option{srom}) baseaddr bytes
|
@deffn {Config Command} {xtensa xtmem} (@option{iram}|@option{dram}|@option{sram}|@option{irom}|@option{drom}|@option{srom}) baseaddr bytes
|
||||||
Configure Xtensa target memory. Memory type determines access rights,
|
Configure Xtensa target memory. Memory type determines access rights,
|
||||||
where RAMs are read/write while ROMs are read-only. @var{baseaddr} and
|
where RAMs are read/write while ROMs are read-only. @var{baseaddr} and
|
||||||
@var{bytes} are both integers, typically hexadecimal and decimal, respectively.
|
@var{bytes} are both integers, typically hexadecimal and decimal, respectively.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtmem} (@option{icache}|@option{dcache}) linebytes cachebytes ways [writeback]
|
@deffn {Config Command} {xtensa xtmem} (@option{icache}|@option{dcache}) linebytes cachebytes ways [writeback]
|
||||||
Configure Xtensa processor cache. All parameters are required except for
|
Configure Xtensa processor cache. All parameters are required except for
|
||||||
the optional @option{writeback} parameter; all are integers.
|
the optional @option{writeback} parameter; all are integers.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtmpu} numfgseg minsegsz lockable execonly
|
@deffn {Config Command} {xtensa xtmpu} numfgseg minsegsz lockable execonly
|
||||||
Configure an Xtensa Memory Protection Unit (MPU). MPUs can restrict access
|
Configure an Xtensa Memory Protection Unit (MPU). MPUs can restrict access
|
||||||
and/or control cacheability of specific address ranges, but are lighter-weight
|
and/or control cacheability of specific address ranges, but are lighter-weight
|
||||||
than a full traditional MMU. All parameters are required; all are integers.
|
than a full traditional MMU. All parameters are required; all are integers.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtmmu} numirefillentries numdrefillentries
|
@deffn {Config Command} {xtensa xtmmu} numirefillentries numdrefillentries
|
||||||
(Xtensa-LX only) Configure an Xtensa Memory Management Unit (MMU). Both
|
(Xtensa-LX only) Configure an Xtensa Memory Management Unit (MMU). Both
|
||||||
parameters are required; both are integers.
|
parameters are required; both are integers.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtregs} numregs
|
@deffn {Config Command} {xtensa xtregs} numregs
|
||||||
Configure the total number of registers for the Xtensa core. Configuration
|
Configure the total number of registers for the Xtensa core. Configuration
|
||||||
logic expects to subsequently process this number of @code{xtensa xtreg}
|
logic expects to subsequently process this number of @code{xtensa xtreg}
|
||||||
definitions. @var{numregs} is an integer.
|
definitions. @var{numregs} is an integer.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtregfmt} (@option{sparse}|@option{contiguous}) [general]
|
@deffn {Config Command} {xtensa xtregfmt} (@option{sparse}|@option{contiguous}) [general]
|
||||||
Configure the type of register map used by GDB to access the Xtensa core.
|
Configure the type of register map used by GDB to access the Xtensa core.
|
||||||
Generic Xtensa tools (e.g. xt-gdb) require @option{sparse} mapping (default) while
|
Generic Xtensa tools (e.g. xt-gdb) require @option{sparse} mapping (default) while
|
||||||
Espressif tools expect @option{contiguous} mapping. Contiguous mapping takes an
|
Espressif tools expect @option{contiguous} mapping. Contiguous mapping takes an
|
||||||
|
@ -11217,7 +11238,7 @@ additional, optional integer parameter @option{numgregs}, which specifies the nu
|
||||||
of general registers used in handling g/G packets.
|
of general registers used in handling g/G packets.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Command} {xtensa xtreg} name offset
|
@deffn {Config Command} {xtensa xtreg} name offset
|
||||||
Configure an Xtensa core register. All core registers are 32 bits wide,
|
Configure an Xtensa core register. All core registers are 32 bits wide,
|
||||||
while TIE and user registers may have variable widths. @var{name} is a
|
while TIE and user registers may have variable widths. @var{name} is a
|
||||||
character string identifier while @var{offset} is a hexadecimal integer.
|
character string identifier while @var{offset} is a hexadecimal integer.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "imp.h"
|
#include "imp.h"
|
||||||
#include "helper/binarybuffer.h"
|
#include "helper/binarybuffer.h"
|
||||||
|
|
||||||
|
#include <helper/time_support.h>
|
||||||
#include <jtag/jtag.h>
|
#include <jtag/jtag.h>
|
||||||
#include <target/cortex_m.h>
|
#include <target/cortex_m.h>
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
#define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */
|
#define SAMD_NVMCTRL_CTRLA 0x00 /* NVM control A register */
|
||||||
#define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */
|
#define SAMD_NVMCTRL_CTRLB 0x04 /* NVM control B register */
|
||||||
#define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */
|
#define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */
|
||||||
#define SAMD_NVMCTRL_INTFLAG 0x18 /* NVM Interrupt Flag Status & Clear */
|
#define SAMD_NVMCTRL_INTFLAG 0x14 /* NVM Interrupt Flag Status & Clear */
|
||||||
#define SAMD_NVMCTRL_STATUS 0x18 /* NVM status register */
|
#define SAMD_NVMCTRL_STATUS 0x18 /* NVM status register */
|
||||||
#define SAMD_NVMCTRL_ADDR 0x1C /* NVM address register */
|
#define SAMD_NVMCTRL_ADDR 0x1C /* NVM address register */
|
||||||
#define SAMD_NVMCTRL_LOCK 0x20 /* NVM Lock section register */
|
#define SAMD_NVMCTRL_LOCK 0x20 /* NVM Lock section register */
|
||||||
|
@ -55,6 +56,9 @@
|
||||||
/* NVMCTRL bits */
|
/* NVMCTRL bits */
|
||||||
#define SAMD_NVM_CTRLB_MANW 0x80
|
#define SAMD_NVM_CTRLB_MANW 0x80
|
||||||
|
|
||||||
|
/* NVMCTRL_INTFLAG bits */
|
||||||
|
#define SAMD_NVM_INTFLAG_READY 0x01
|
||||||
|
|
||||||
/* Known identifiers */
|
/* Known identifiers */
|
||||||
#define SAMD_PROCESSOR_M0 0x01
|
#define SAMD_PROCESSOR_M0 0x01
|
||||||
#define SAMD_FAMILY_D 0x00
|
#define SAMD_FAMILY_D 0x00
|
||||||
|
@ -497,7 +501,27 @@ static int samd_probe(struct flash_bank *bank)
|
||||||
static int samd_check_error(struct target *target)
|
static int samd_check_error(struct target *target)
|
||||||
{
|
{
|
||||||
int ret, ret2;
|
int ret, ret2;
|
||||||
|
uint8_t intflag;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
int timeout_ms = 1000;
|
||||||
|
int64_t ts_start = timeval_ms();
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = target_read_u8(target,
|
||||||
|
SAMD_NVMCTRL + SAMD_NVMCTRL_INTFLAG, &intflag);
|
||||||
|
if (ret != ERROR_OK) {
|
||||||
|
LOG_ERROR("Can't read NVM intflag");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (intflag & SAMD_NVM_INTFLAG_READY)
|
||||||
|
break;
|
||||||
|
keep_alive();
|
||||||
|
} while (timeval_ms() - ts_start < timeout_ms);
|
||||||
|
|
||||||
|
if (!(intflag & SAMD_NVM_INTFLAG_READY)) {
|
||||||
|
LOG_ERROR("SAMD: NVM programming timed out");
|
||||||
|
return ERROR_FLASH_OPERATION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
ret = target_read_u16(target,
|
ret = target_read_u16(target,
|
||||||
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
|
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
|
||||||
|
@ -543,7 +567,8 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Issue the NVM command */
|
/* Issue the NVM command */
|
||||||
res = target_write_u16(target,
|
/* 32-bit write is used to ensure atomic operation on ST-Link */
|
||||||
|
res = target_write_u32(target,
|
||||||
SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd));
|
SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd));
|
||||||
if (res != ERROR_OK)
|
if (res != ERROR_OK)
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -64,6 +64,7 @@ static const struct avrf_type avft_chips_info[] = {
|
||||||
{"atmega324pa", 0x9511, 128, 256, 4, 256},
|
{"atmega324pa", 0x9511, 128, 256, 4, 256},
|
||||||
{"atmega644p", 0x960a, 256, 256, 8, 256},
|
{"atmega644p", 0x960a, 256, 256, 8, 256},
|
||||||
{"atmega1284p", 0x9705, 256, 512, 8, 512},
|
{"atmega1284p", 0x9705, 256, 512, 8, 512},
|
||||||
|
{"atmega32u4", 0x9587, 128, 256, 4, 256},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* avr program functions */
|
/* avr program functions */
|
||||||
|
|
|
@ -1132,9 +1132,9 @@ static int lpc2900_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
* reduced size if that fails. */
|
* reduced size if that fails. */
|
||||||
struct working_area *warea;
|
struct working_area *warea;
|
||||||
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
|
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
|
||||||
while ((retval = target_alloc_working_area_try(target,
|
while (target_alloc_working_area_try(target,
|
||||||
buffer_size + target_code_size,
|
buffer_size + target_code_size,
|
||||||
&warea)) != ERROR_OK) {
|
&warea) != ERROR_OK) {
|
||||||
/* Try a smaller buffer now, and stop if it's too small. */
|
/* Try a smaller buffer now, and stop if it's too small. */
|
||||||
buffer_size -= 1 * KiB;
|
buffer_size -= 1 * KiB;
|
||||||
if (buffer_size < 2 * KiB) {
|
if (buffer_size < 2 * KiB) {
|
||||||
|
|
|
@ -50,6 +50,10 @@ struct rp2040_flash_bank {
|
||||||
const struct flash_device *dev;
|
const struct flash_device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* guessed SPI flash description if autodetection disabled (same as win w25q16jv) */
|
||||||
|
static const struct flash_device rp2040_default_spi_device =
|
||||||
|
FLASH_ID("autodetect disabled", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0, 0x100, 0x10000, 0);
|
||||||
|
|
||||||
static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol)
|
static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol)
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
@ -87,7 +91,7 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
|
static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
|
||||||
uint16_t func_offset, uint32_t argdata[], unsigned int n_args)
|
uint16_t func_offset, uint32_t argdata[], unsigned int n_args, int timeout_ms)
|
||||||
{
|
{
|
||||||
char *regnames[4] = { "r0", "r1", "r2", "r3" };
|
char *regnames[4] = { "r0", "r1", "r2", "r3" };
|
||||||
|
|
||||||
|
@ -99,8 +103,7 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
|
||||||
}
|
}
|
||||||
target_addr_t stacktop = priv->stack->address + priv->stack->size;
|
target_addr_t stacktop = priv->stack->address + priv->stack->size;
|
||||||
|
|
||||||
LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args);
|
LOG_TARGET_DEBUG(target, "Calling ROM func @0x%" PRIx16 " with %u arguments", func_offset, n_args);
|
||||||
LOG_DEBUG("Calling on core \"%s\"", target->cmd_name);
|
|
||||||
|
|
||||||
struct reg_param args[ARRAY_SIZE(regnames) + 2];
|
struct reg_param args[ARRAY_SIZE(regnames) + 2];
|
||||||
struct armv7m_algorithm alg_info;
|
struct armv7m_algorithm alg_info;
|
||||||
|
@ -112,11 +115,12 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
|
||||||
/* Pass function pointer in r7 */
|
/* Pass function pointer in r7 */
|
||||||
init_reg_param(&args[n_args], "r7", 32, PARAM_OUT);
|
init_reg_param(&args[n_args], "r7", 32, PARAM_OUT);
|
||||||
buf_set_u32(args[n_args].value, 0, 32, func_offset);
|
buf_set_u32(args[n_args].value, 0, 32, func_offset);
|
||||||
|
/* Setup stack */
|
||||||
init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
|
init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
|
||||||
buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
|
buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
|
||||||
|
unsigned int n_reg_params = n_args + 2; /* User arguments + r7 + sp */
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n_reg_params; ++i)
|
||||||
for (unsigned int i = 0; i < n_args + 2; ++i)
|
|
||||||
LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32));
|
LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32));
|
||||||
|
|
||||||
/* Actually call the function */
|
/* Actually call the function */
|
||||||
|
@ -125,42 +129,82 @@ static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank
|
||||||
int err = target_run_algorithm(
|
int err = target_run_algorithm(
|
||||||
target,
|
target,
|
||||||
0, NULL, /* No memory arguments */
|
0, NULL, /* No memory arguments */
|
||||||
n_args + 1, args, /* User arguments + r7 */
|
n_reg_params, args, /* User arguments + r7 + sp */
|
||||||
priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
|
priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
|
||||||
3000, /* 3s timeout */
|
timeout_ms,
|
||||||
&alg_info
|
&alg_info
|
||||||
);
|
);
|
||||||
for (unsigned int i = 0; i < n_args + 2; ++i)
|
|
||||||
destroy_reg_param(&args[i]);
|
|
||||||
if (err != ERROR_OK)
|
|
||||||
LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset);
|
|
||||||
return err;
|
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n_reg_params; ++i)
|
||||||
|
destroy_reg_param(&args[i]);
|
||||||
|
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16, func_offset);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stack_grab_and_prep(struct flash_bank *bank)
|
/* Finalize flash write/erase/read ID
|
||||||
|
* - flush cache
|
||||||
|
* - enters memory-mapped (XIP) mode to make flash data visible
|
||||||
|
* - deallocates target ROM func stack if previously allocated
|
||||||
|
*/
|
||||||
|
static int rp2040_finalize_stack_free(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
/* Always flush before returning to execute-in-place, to invalidate stale
|
||||||
|
* cache contents. The flush call also restores regular hardware-controlled
|
||||||
|
* chip select following a rp2040_flash_exit_xip().
|
||||||
|
*/
|
||||||
|
LOG_DEBUG("Flushing flash cache after write behind");
|
||||||
|
int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0, 1000);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to flush flash cache");
|
||||||
|
/* Intentionally continue after error and try to setup xip anyway */
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Configuring SSI for execute-in-place");
|
||||||
|
err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0, 1000);
|
||||||
|
if (err != ERROR_OK)
|
||||||
|
LOG_ERROR("Failed to set SSI to XIP mode");
|
||||||
|
|
||||||
|
target_free_working_area(target, priv->stack);
|
||||||
|
priv->stack = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare flash write/erase/read ID
|
||||||
|
* - allocates a stack for target ROM func
|
||||||
|
* - switches the SPI interface from memory-mapped mode to direct command mode
|
||||||
|
* Always pair with a call of rp2040_finalize_stack_free()
|
||||||
|
* after flash operation finishes or fails.
|
||||||
|
*/
|
||||||
|
static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
|
||||||
|
{
|
||||||
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
/* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
|
/* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
|
||||||
const int STACK_SIZE = 256;
|
const int STACK_SIZE = 256;
|
||||||
int err = target_alloc_working_area(bank->target, STACK_SIZE, &priv->stack);
|
int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Could not allocate stack for flash programming code");
|
LOG_ERROR("Could not allocate stack for flash programming code");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Connecting internal flash");
|
LOG_DEBUG("Connecting internal flash");
|
||||||
err = rp2040_call_rom_func(bank->target, priv, priv->jump_connect_internal_flash, NULL, 0);
|
err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0, 1000);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("RP2040 erase: failed to connect internal flash");
|
LOG_ERROR("Failed to connect internal flash");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Kicking flash out of XIP mode");
|
LOG_DEBUG("Kicking flash out of XIP mode");
|
||||||
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_exit_xip, NULL, 0);
|
err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0, 1000);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("RP2040 erase: failed to exit flash XIP mode");
|
LOG_ERROR("Failed to exit flash XIP mode");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,16 +217,27 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
||||||
|
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
struct working_area *bounce;
|
|
||||||
|
|
||||||
int err = stack_grab_and_prep(bank);
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct working_area *bounce = NULL;
|
||||||
|
|
||||||
|
int err = rp2040_stack_grab_and_prep(bank);
|
||||||
if (err != ERROR_OK)
|
if (err != ERROR_OK)
|
||||||
return err;
|
goto cleanup;
|
||||||
|
|
||||||
const unsigned int chunk_size = target_get_working_area_avail(target);
|
unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize;
|
||||||
if (target_alloc_working_area(target, chunk_size, &bounce) != ERROR_OK) {
|
/* We try to allocate working area rounded down to device page size,
|
||||||
|
* al least 1 page, at most the write data size
|
||||||
|
*/
|
||||||
|
unsigned int chunk_size = MIN(MAX(avail_pages, 1) * priv->dev->pagesize, count);
|
||||||
|
err = target_alloc_working_area(target, chunk_size, &bounce);
|
||||||
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
|
LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
|
LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
|
||||||
|
@ -200,7 +255,8 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
||||||
bounce->address, /* data */
|
bounce->address, /* data */
|
||||||
write_size /* count */
|
write_size /* count */
|
||||||
};
|
};
|
||||||
err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args));
|
err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program,
|
||||||
|
args, ARRAY_SIZE(args), 3000);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Failed to invoke flash programming code on target");
|
LOG_ERROR("Failed to invoke flash programming code on target");
|
||||||
break;
|
break;
|
||||||
|
@ -210,36 +266,32 @@ static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, ui
|
||||||
offset += write_size;
|
offset += write_size;
|
||||||
count -= write_size;
|
count -= write_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
target_free_working_area(target, bounce);
|
target_free_working_area(target, bounce);
|
||||||
|
|
||||||
if (err != ERROR_OK)
|
rp2040_finalize_stack_free(bank);
|
||||||
return err;
|
|
||||||
|
|
||||||
/* Flash is successfully programmed. We can now do a bit of poking to make the flash
|
|
||||||
contents visible to us via memory-mapped (XIP) interface in the 0x1... memory region */
|
|
||||||
LOG_DEBUG("Flushing flash cache after write behind");
|
|
||||||
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flush_cache, NULL, 0);
|
|
||||||
if (err != ERROR_OK) {
|
|
||||||
LOG_ERROR("RP2040 write: failed to flush flash cache");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Configuring SSI for execute-in-place");
|
|
||||||
err = rp2040_call_rom_func(bank->target, priv, priv->jump_enter_cmd_xip, NULL, 0);
|
|
||||||
if (err != ERROR_OK)
|
|
||||||
LOG_ERROR("RP2040 write: failed to flush flash cache");
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
|
static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
|
||||||
{
|
{
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t start_addr = bank->sectors[first].offset;
|
uint32_t start_addr = bank->sectors[first].offset;
|
||||||
uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
|
uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
|
||||||
LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
|
LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
|
||||||
|
|
||||||
int err = stack_grab_and_prep(bank);
|
int err = rp2040_stack_grab_and_prep(bank);
|
||||||
if (err != ERROR_OK)
|
if (err != ERROR_OK)
|
||||||
return err;
|
goto cleanup;
|
||||||
|
|
||||||
LOG_DEBUG("Remote call flash_range_erase");
|
LOG_DEBUG("Remote call flash_range_erase");
|
||||||
|
|
||||||
|
@ -257,10 +309,15 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig
|
||||||
https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
|
https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
|
||||||
|
|
||||||
In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
|
In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
|
||||||
an optional larger "block" (size and command provided in args). OpenOCD's spi.c only uses "block" sizes.
|
an optional larger "block" (size and command provided in args).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
|
int timeout_ms = 2000 * (last - first) + 1000;
|
||||||
|
err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase,
|
||||||
|
args, ARRAY_SIZE(args), timeout_ms);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
rp2040_finalize_stack_free(bank);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -289,11 +346,46 @@ static int rp2040_ssel_active(struct target *target, bool active)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
|
||||||
|
{
|
||||||
|
uint32_t device_id = 0;
|
||||||
|
const target_addr_t ssi_dr0 = 0x18000060;
|
||||||
|
|
||||||
|
int err = rp2040_ssel_active(target, true);
|
||||||
|
|
||||||
|
/* write RDID request into SPI peripheral's FIFO */
|
||||||
|
for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
|
||||||
|
err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
|
||||||
|
|
||||||
|
/* by this time, there is a receive FIFO entry for every write */
|
||||||
|
for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
|
||||||
|
uint32_t status;
|
||||||
|
err = target_read_u32(target, ssi_dr0, &status);
|
||||||
|
|
||||||
|
device_id >>= 8;
|
||||||
|
device_id |= (status & 0xFF) << 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ERROR_OK)
|
||||||
|
*devid = device_id >> 8;
|
||||||
|
|
||||||
|
int err2 = rp2040_ssel_active(target, false);
|
||||||
|
if (err2 != ERROR_OK)
|
||||||
|
LOG_ERROR("SSEL inactive failed");
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int rp2040_flash_probe(struct flash_bank *bank)
|
static int rp2040_flash_probe(struct flash_bank *bank)
|
||||||
{
|
{
|
||||||
struct rp2040_flash_bank *priv = bank->driver_priv;
|
struct rp2040_flash_bank *priv = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_ERROR("Target not halted");
|
||||||
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
|
}
|
||||||
|
|
||||||
int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
|
int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
|
||||||
if (err != ERROR_OK) {
|
if (err != ERROR_OK) {
|
||||||
LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
|
LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
|
||||||
|
@ -344,34 +436,23 @@ static int rp2040_flash_probe(struct flash_bank *bank)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = stack_grab_and_prep(bank);
|
if (bank->size) {
|
||||||
if (err != ERROR_OK)
|
/* size overridden, suppress reading SPI flash ID */
|
||||||
return err;
|
priv->dev = &rp2040_default_spi_device;
|
||||||
|
LOG_DEBUG("SPI flash autodetection disabled, using configured size");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* zero bank size in cfg, read SPI flash ID and autodetect */
|
||||||
|
err = rp2040_stack_grab_and_prep(bank);
|
||||||
|
|
||||||
uint32_t device_id = 0;
|
uint32_t device_id = 0;
|
||||||
const target_addr_t ssi_dr0 = 0x18000060;
|
if (err == ERROR_OK)
|
||||||
|
err = rp2040_spi_read_flash_id(target, &device_id);
|
||||||
|
|
||||||
err = rp2040_ssel_active(target, true);
|
rp2040_finalize_stack_free(bank);
|
||||||
|
|
||||||
/* write RDID request into SPI peripheral's FIFO */
|
if (err != ERROR_OK)
|
||||||
for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
|
|
||||||
err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
|
|
||||||
|
|
||||||
/* by this time, there is a receive FIFO entry for every write */
|
|
||||||
for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
|
|
||||||
uint32_t status;
|
|
||||||
err = target_read_u32(target, ssi_dr0, &status);
|
|
||||||
|
|
||||||
device_id >>= 8;
|
|
||||||
device_id |= (status & 0xFF) << 24;
|
|
||||||
}
|
|
||||||
device_id >>= 8;
|
|
||||||
|
|
||||||
err = rp2040_ssel_active(target, false);
|
|
||||||
if (err != ERROR_OK) {
|
|
||||||
LOG_ERROR("SSEL inactive failed");
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
/* search for a SPI flash Device ID match */
|
/* search for a SPI flash Device ID match */
|
||||||
priv->dev = NULL;
|
priv->dev = NULL;
|
||||||
|
@ -385,18 +466,18 @@ static int rp2040_flash_probe(struct flash_bank *bank)
|
||||||
LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
|
LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")",
|
||||||
LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
|
|
||||||
priv->dev->name, priv->dev->device_id);
|
priv->dev->name, priv->dev->device_id);
|
||||||
|
|
||||||
|
bank->size = priv->dev->size_in_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/* the Boot ROM flash_range_program() routine requires page alignment */
|
/* the Boot ROM flash_range_program() routine requires page alignment */
|
||||||
bank->write_start_alignment = priv->dev->pagesize;
|
bank->write_start_alignment = priv->dev->pagesize;
|
||||||
bank->write_end_alignment = priv->dev->pagesize;
|
bank->write_end_alignment = priv->dev->pagesize;
|
||||||
|
|
||||||
bank->size = priv->dev->size_in_bytes;
|
|
||||||
|
|
||||||
bank->num_sectors = bank->size / priv->dev->sectorsize;
|
bank->num_sectors = bank->size / priv->dev->sectorsize;
|
||||||
LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
|
LOG_INFO("RP2040 B0 Flash Probe: %" PRIu32 " bytes @" TARGET_ADDR_FMT ", in %u sectors\n",
|
||||||
bank->size, bank->base, bank->num_sectors);
|
bank->size, bank->base, bank->num_sectors);
|
||||||
bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
|
bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
|
||||||
if (!bank->sectors)
|
if (!bank->sectors)
|
||||||
|
|
|
@ -112,6 +112,7 @@ const struct flash_device flash_devices[] = {
|
||||||
FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
|
FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
|
||||||
FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
|
FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
|
||||||
FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
|
FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
|
||||||
|
FLASH_ID("issi is25lq040b", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000, 0x80000),
|
||||||
FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
|
FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
|
||||||
FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
|
FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
|
||||||
FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
|
FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
|
||||||
|
|
|
@ -473,7 +473,7 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff
|
||||||
|
|
||||||
/* memory buffer */
|
/* memory buffer */
|
||||||
buffer_size = target_get_working_area_avail(target);
|
buffer_size = target_get_working_area_avail(target);
|
||||||
buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256));
|
buffer_size = MIN(hwords_count * 2 + 8, MAX(buffer_size, 256));
|
||||||
/* Normally we allocate all available working area.
|
/* Normally we allocate all available working area.
|
||||||
* MIN shrinks buffer_size if the size of the written block is smaller.
|
* MIN shrinks buffer_size if the size of the written block is smaller.
|
||||||
* MAX prevents using async algo if the available working area is smaller
|
* MAX prevents using async algo if the available working area is smaller
|
||||||
|
|
|
@ -132,7 +132,7 @@ static const struct stm32lx_rev stm32_417_revs[] = {
|
||||||
{ 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" }
|
{ 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" }, { 0x1038, "X" }
|
||||||
};
|
};
|
||||||
static const struct stm32lx_rev stm32_425_revs[] = {
|
static const struct stm32lx_rev stm32_425_revs[] = {
|
||||||
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" },
|
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2008, "Y" }, { 0x2018, "1, X" },
|
||||||
};
|
};
|
||||||
static const struct stm32lx_rev stm32_427_revs[] = {
|
static const struct stm32lx_rev stm32_427_revs[] = {
|
||||||
{ 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
|
{ 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" }, { 0x10f8, "V" },
|
||||||
|
|
|
@ -616,8 +616,6 @@ COMMAND_HANDLER(stmqspi_handle_set)
|
||||||
|
|
||||||
LOG_DEBUG("%s", __func__);
|
LOG_DEBUG("%s", __func__);
|
||||||
|
|
||||||
dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0;
|
|
||||||
|
|
||||||
/* chip_erase_cmd, sectorsize and erase_cmd are optional */
|
/* chip_erase_cmd, sectorsize and erase_cmd are optional */
|
||||||
if ((CMD_ARGC < 7) || (CMD_ARGC > 10))
|
if ((CMD_ARGC < 7) || (CMD_ARGC > 10))
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
@ -628,8 +626,9 @@ COMMAND_HANDLER(stmqspi_handle_set)
|
||||||
|
|
||||||
target = bank->target;
|
target = bank->target;
|
||||||
stmqspi_info = bank->driver_priv;
|
stmqspi_info = bank->driver_priv;
|
||||||
|
dual = (stmqspi_info->saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0;
|
||||||
|
|
||||||
/* invalidate all old info */
|
/* invalidate all flash device info */
|
||||||
if (stmqspi_info->probed)
|
if (stmqspi_info->probed)
|
||||||
free(bank->sectors);
|
free(bank->sectors);
|
||||||
bank->size = 0;
|
bank->size = 0;
|
||||||
|
@ -721,10 +720,8 @@ COMMAND_HANDLER(stmqspi_handle_set)
|
||||||
|
|
||||||
uint32_t dcr;
|
uint32_t dcr;
|
||||||
retval = target_read_u32(target, io_base + SPI_DCR, &dcr);
|
retval = target_read_u32(target, io_base + SPI_DCR, &dcr);
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1);
|
fsize = (dcr >> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1);
|
||||||
|
|
||||||
LOG_DEBUG("FSIZE = 0x%04x", fsize);
|
LOG_DEBUG("FSIZE = 0x%04x", fsize);
|
||||||
|
@ -1799,7 +1796,6 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = ERROR_FAIL;
|
|
||||||
LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count);
|
LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
@ -2081,16 +2077,17 @@ static int stmqspi_probe(struct flash_bank *bank)
|
||||||
bool octal_dtr;
|
bool octal_dtr;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (stmqspi_info->probed) {
|
/* invalidate all flash device info */
|
||||||
|
if (stmqspi_info->probed)
|
||||||
|
free(bank->sectors);
|
||||||
bank->size = 0;
|
bank->size = 0;
|
||||||
bank->num_sectors = 0;
|
bank->num_sectors = 0;
|
||||||
free(bank->sectors);
|
|
||||||
bank->sectors = NULL;
|
bank->sectors = NULL;
|
||||||
memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev));
|
|
||||||
stmqspi_info->sfdp_dummy1 = 0;
|
stmqspi_info->sfdp_dummy1 = 0;
|
||||||
stmqspi_info->sfdp_dummy2 = 0;
|
stmqspi_info->sfdp_dummy2 = 0;
|
||||||
stmqspi_info->probed = false;
|
stmqspi_info->probed = false;
|
||||||
}
|
memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev));
|
||||||
|
stmqspi_info->dev.name = "unknown";
|
||||||
|
|
||||||
/* Abort any previous operation */
|
/* Abort any previous operation */
|
||||||
retval = stmqspi_abort(bank);
|
retval = stmqspi_abort(bank);
|
||||||
|
@ -2105,8 +2102,8 @@ static int stmqspi_probe(struct flash_bank *bank)
|
||||||
/* check whether QSPI_ABR is writeable and readback returns the value written */
|
/* check whether QSPI_ABR is writeable and readback returns the value written */
|
||||||
retval = target_write_u32(target, io_base + QSPI_ABR, magic);
|
retval = target_write_u32(target, io_base + QSPI_ABR, magic);
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
retval = target_read_u32(target, io_base + QSPI_ABR, &data);
|
(void)target_read_u32(target, io_base + QSPI_ABR, &data);
|
||||||
retval = target_write_u32(target, io_base + QSPI_ABR, 0);
|
(void)target_write_u32(target, io_base + QSPI_ABR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == magic) {
|
if (data == magic) {
|
||||||
|
|
|
@ -936,19 +936,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a
|
||||||
if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL)))
|
if (!command_can_run(cmd_ctx, c, Jim_GetString(argv[0], NULL)))
|
||||||
return JIM_ERR;
|
return JIM_ERR;
|
||||||
|
|
||||||
/*
|
target_call_timer_callbacks();
|
||||||
* TODO: to be removed after v0.12.0
|
|
||||||
* workaround for https://sourceforge.net/p/openocd/tickets/362/
|
|
||||||
* After syntax change of "expr" in jimtcl 0.81
|
|
||||||
* the replacement of jimtcl "expr" with openocd version in
|
|
||||||
* https://review.openocd.org/6510/
|
|
||||||
* introduces too many target polling during math expressions with
|
|
||||||
* "expr" commands.
|
|
||||||
* After v0.12.0 replace the following two lines with
|
|
||||||
* target_call_timer_callbacks();
|
|
||||||
*/
|
|
||||||
if (strcmp(c->name, "expr"))
|
|
||||||
target_call_timer_callbacks_now();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Black magic of overridden current target:
|
* Black magic of overridden current target:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* identification code list, please visit the JEDEC website at www.jedec.org .
|
* identification code list, please visit the JEDEC website at www.jedec.org .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* This file is aligned to revision JEP106BE January 2022. */
|
/* This file is aligned to revision JEP106BF.01 October 2022. */
|
||||||
|
|
||||||
[0][0x01 - 1] = "AMD",
|
[0][0x01 - 1] = "AMD",
|
||||||
[0][0x02 - 1] = "AMI",
|
[0][0x02 - 1] = "AMI",
|
||||||
|
@ -149,7 +149,7 @@
|
||||||
[1][0x0b - 1] = "Bestlink Systems",
|
[1][0x0b - 1] = "Bestlink Systems",
|
||||||
[1][0x0c - 1] = "Graychip",
|
[1][0x0c - 1] = "Graychip",
|
||||||
[1][0x0d - 1] = "GENNUM",
|
[1][0x0d - 1] = "GENNUM",
|
||||||
[1][0x0e - 1] = "VideoLogic",
|
[1][0x0e - 1] = "Imagination Technologies Limited",
|
||||||
[1][0x0f - 1] = "Robert Bosch",
|
[1][0x0f - 1] = "Robert Bosch",
|
||||||
[1][0x10 - 1] = "Chip Express",
|
[1][0x10 - 1] = "Chip Express",
|
||||||
[1][0x11 - 1] = "DATARAM",
|
[1][0x11 - 1] = "DATARAM",
|
||||||
|
@ -1501,7 +1501,7 @@
|
||||||
[11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co",
|
[11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co",
|
||||||
[11][0x68 - 1] = "Shenzhen Hangshun Chip Technology",
|
[11][0x68 - 1] = "Shenzhen Hangshun Chip Technology",
|
||||||
[11][0x69 - 1] = "Chengboliwei Electronic Business",
|
[11][0x69 - 1] = "Chengboliwei Electronic Business",
|
||||||
[11][0x6a - 1] = "Kowin Memory Technology Co Ltd",
|
[11][0x6a - 1] = "Kowin Technology HK Limited",
|
||||||
[11][0x6b - 1] = "Euronet Technology Inc",
|
[11][0x6b - 1] = "Euronet Technology Inc",
|
||||||
[11][0x6c - 1] = "SCY",
|
[11][0x6c - 1] = "SCY",
|
||||||
[11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical",
|
[11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical",
|
||||||
|
@ -1705,4 +1705,85 @@
|
||||||
[13][0x37 - 1] = "ORICO Technologies Co. Ltd.",
|
[13][0x37 - 1] = "ORICO Technologies Co. Ltd.",
|
||||||
[13][0x38 - 1] = "Space Exploration Technologies Corp",
|
[13][0x38 - 1] = "Space Exploration Technologies Corp",
|
||||||
[13][0x39 - 1] = "AONDEVICES Inc",
|
[13][0x39 - 1] = "AONDEVICES Inc",
|
||||||
|
[13][0x3a - 1] = "Shenzhen Netforward Micro Electronic",
|
||||||
|
[13][0x3b - 1] = "Syntacore Ltd",
|
||||||
|
[13][0x3c - 1] = "Shenzhen Secmem Microelectronics Co",
|
||||||
|
[13][0x3d - 1] = "ONiO As",
|
||||||
|
[13][0x3e - 1] = "Shenzhen Peladn Technology Co Ltd",
|
||||||
|
[13][0x3f - 1] = "O-Cubes Shanghai Microelectronics",
|
||||||
|
[13][0x40 - 1] = "ASTC",
|
||||||
|
[13][0x41 - 1] = "UMIS",
|
||||||
|
[13][0x42 - 1] = "Paradromics",
|
||||||
|
[13][0x43 - 1] = "Sinh Micro Co Ltd",
|
||||||
|
[13][0x44 - 1] = "Metorage Semiconductor Technology Co",
|
||||||
|
[13][0x45 - 1] = "Aeva Inc",
|
||||||
|
[13][0x46 - 1] = "HongKong Hyunion Electronics Co Ltd",
|
||||||
|
[13][0x47 - 1] = "China Flash Co Ltd",
|
||||||
|
[13][0x48 - 1] = "Sunplus Technology Co Ltd",
|
||||||
|
[13][0x49 - 1] = "Idaho Scientific",
|
||||||
|
[13][0x4a - 1] = "Suzhou SF Micro Electronics Co Ltd",
|
||||||
|
[13][0x4b - 1] = "IMEX Cap AG",
|
||||||
|
[13][0x4c - 1] = "Fitipower Integrated Technology Co Ltd",
|
||||||
|
[13][0x4d - 1] = "ShenzhenWooacme Technology Co Ltd",
|
||||||
|
[13][0x4e - 1] = "KeepData Original Chips",
|
||||||
|
[13][0x4f - 1] = "Rivos Inc",
|
||||||
|
[13][0x50 - 1] = "Big Innovation Company Limited",
|
||||||
|
[13][0x51 - 1] = "Wuhan YuXin Semiconductor Co Ltd",
|
||||||
|
[13][0x52 - 1] = "United Memory Technology (Jiangsu)",
|
||||||
|
[13][0x53 - 1] = "PQShield Ltd",
|
||||||
|
[13][0x54 - 1] = "ArchiTek Corporation",
|
||||||
|
[13][0x55 - 1] = "ShenZhen AZW Technology Co Ltd",
|
||||||
|
[13][0x56 - 1] = "Hengchi Zhixin (Dongguan) Technology",
|
||||||
|
[13][0x57 - 1] = "Eggtronic Engineering Spa",
|
||||||
|
[13][0x58 - 1] = "Fusontai Technology",
|
||||||
|
[13][0x59 - 1] = "PULP Platform",
|
||||||
|
[13][0x5a - 1] = "Koitek Electronic Technology (Shenzhen) Co",
|
||||||
|
[13][0x5b - 1] = "Shenzhen Jiteng Network Technology Co",
|
||||||
|
[13][0x5c - 1] = "Aviva Links Inc",
|
||||||
|
[13][0x5d - 1] = "Trilinear Technologies Inc",
|
||||||
|
[13][0x5e - 1] = "Shenzhen Developer Microelectronics Co",
|
||||||
|
[13][0x5f - 1] = "Guangdong OPPO Mobile Telecommunication",
|
||||||
|
[13][0x60 - 1] = "Akeana",
|
||||||
|
[13][0x61 - 1] = "Lyczar",
|
||||||
|
[13][0x62 - 1] = "Shenzhen Qiji Technology Co Ltd",
|
||||||
|
[13][0x63 - 1] = "Shenzhen Shangzhaoyuan Technology",
|
||||||
|
[13][0x64 - 1] = "Han Stor",
|
||||||
|
[13][0x65 - 1] = "China Micro Semicon Co., Ltd.",
|
||||||
|
[13][0x66 - 1] = "Shenzhen Zhuqin Technology Co Ltd",
|
||||||
|
[13][0x67 - 1] = "Shanghai Ningyuan Electronic Technology",
|
||||||
|
[13][0x68 - 1] = "Auradine",
|
||||||
|
[13][0x69 - 1] = "Suzhou Yishuo Electronics Co Ltd",
|
||||||
|
[13][0x6a - 1] = "Faurecia Clarion Electronics",
|
||||||
|
[13][0x6b - 1] = "SiMa Technologies",
|
||||||
|
[13][0x6c - 1] = "CFD Sales Inc",
|
||||||
|
[13][0x6d - 1] = "Suzhou Comay Information Co Ltd",
|
||||||
|
[13][0x6e - 1] = "Yentek",
|
||||||
|
[13][0x6f - 1] = "Qorvo Inc",
|
||||||
|
[13][0x70 - 1] = "Shenzhen Youzhi Computer Technology",
|
||||||
|
[13][0x71 - 1] = "Sychw Technology (Shenzhen) Co Ltd",
|
||||||
|
[13][0x72 - 1] = "MK Founder Technology Co Ltd",
|
||||||
|
[13][0x73 - 1] = "Siliconwaves Technologies Co Ltd",
|
||||||
|
[13][0x74 - 1] = "Hongkong Hyunion Electronics Co Ltd",
|
||||||
|
[13][0x75 - 1] = "Shenzhen Xinxinzhitao Electronics Business",
|
||||||
|
[13][0x76 - 1] = "Shenzhen HenQi Electronic Commerce Co",
|
||||||
|
[13][0x77 - 1] = "Shenzhen Jingyi Technology Co Ltd",
|
||||||
|
[13][0x78 - 1] = "Xiaohua Semiconductor Co. Ltd.",
|
||||||
|
[13][0x79 - 1] = "Shenzhen Dalu Semiconductor Technology",
|
||||||
|
[13][0x7a - 1] = "Shenzhen Ninespeed Electronics Co Ltd",
|
||||||
|
[13][0x7b - 1] = "ICYC Semiconductor Co Ltd",
|
||||||
|
[13][0x7c - 1] = "Shenzhen Jaguar Microsystems Co Ltd",
|
||||||
|
[13][0x7d - 1] = "Beijing EC-Founder Co Ltd",
|
||||||
|
[13][0x7e - 1] = "Shenzhen Taike Industrial Automation Co",
|
||||||
|
[14][0x01 - 1] = "Kalray SA",
|
||||||
|
[14][0x02 - 1] = "Shanghai Iluvatar CoreX Semiconductor Co",
|
||||||
|
[14][0x03 - 1] = "Fungible Inc",
|
||||||
|
[14][0x04 - 1] = "Song Industria E Comercio de Eletronicos",
|
||||||
|
[14][0x05 - 1] = "DreamBig Semiconductor Inc",
|
||||||
|
[14][0x06 - 1] = "ChampTek Electronics Corp",
|
||||||
|
[14][0x07 - 1] = "Fusontai Technology",
|
||||||
|
[14][0x08 - 1] = "Endress Hauser AG",
|
||||||
|
[14][0x09 - 1] = "altec ComputerSysteme GmbH",
|
||||||
|
[14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd",
|
||||||
|
[14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd",
|
||||||
|
[14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd",
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -151,7 +151,7 @@ static inline uint16_t be_to_h_u16(const uint8_t *buf)
|
||||||
return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8);
|
return (uint16_t)((uint16_t)buf[1] | (uint16_t)buf[0] << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u64_to_le(uint8_t *buf, int64_t val)
|
static inline void h_u64_to_le(uint8_t *buf, uint64_t val)
|
||||||
{
|
{
|
||||||
buf[7] = (uint8_t) (val >> 56);
|
buf[7] = (uint8_t) (val >> 56);
|
||||||
buf[6] = (uint8_t) (val >> 48);
|
buf[6] = (uint8_t) (val >> 48);
|
||||||
|
@ -163,7 +163,7 @@ static inline void h_u64_to_le(uint8_t *buf, int64_t val)
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u64_to_be(uint8_t *buf, int64_t val)
|
static inline void h_u64_to_be(uint8_t *buf, uint64_t val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 56);
|
buf[0] = (uint8_t) (val >> 56);
|
||||||
buf[1] = (uint8_t) (val >> 48);
|
buf[1] = (uint8_t) (val >> 48);
|
||||||
|
@ -175,7 +175,7 @@ static inline void h_u64_to_be(uint8_t *buf, int64_t val)
|
||||||
buf[7] = (uint8_t) (val >> 0);
|
buf[7] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u32_to_le(uint8_t *buf, int val)
|
static inline void h_u32_to_le(uint8_t *buf, uint32_t val)
|
||||||
{
|
{
|
||||||
buf[3] = (uint8_t) (val >> 24);
|
buf[3] = (uint8_t) (val >> 24);
|
||||||
buf[2] = (uint8_t) (val >> 16);
|
buf[2] = (uint8_t) (val >> 16);
|
||||||
|
@ -183,7 +183,7 @@ static inline void h_u32_to_le(uint8_t *buf, int val)
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u32_to_be(uint8_t *buf, int val)
|
static inline void h_u32_to_be(uint8_t *buf, uint32_t val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 24);
|
buf[0] = (uint8_t) (val >> 24);
|
||||||
buf[1] = (uint8_t) (val >> 16);
|
buf[1] = (uint8_t) (val >> 16);
|
||||||
|
@ -191,27 +191,27 @@ static inline void h_u32_to_be(uint8_t *buf, int val)
|
||||||
buf[3] = (uint8_t) (val >> 0);
|
buf[3] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u24_to_le(uint8_t *buf, int val)
|
static inline void h_u24_to_le(uint8_t *buf, unsigned int val)
|
||||||
{
|
{
|
||||||
buf[2] = (uint8_t) (val >> 16);
|
buf[2] = (uint8_t) (val >> 16);
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (uint8_t) (val >> 8);
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u24_to_be(uint8_t *buf, int val)
|
static inline void h_u24_to_be(uint8_t *buf, unsigned int val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 16);
|
buf[0] = (uint8_t) (val >> 16);
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (uint8_t) (val >> 8);
|
||||||
buf[2] = (uint8_t) (val >> 0);
|
buf[2] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u16_to_le(uint8_t *buf, int val)
|
static inline void h_u16_to_le(uint8_t *buf, uint16_t val)
|
||||||
{
|
{
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (uint8_t) (val >> 8);
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (uint8_t) (val >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u16_to_be(uint8_t *buf, int val)
|
static inline void h_u16_to_be(uint8_t *buf, uint16_t val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 8);
|
buf[0] = (uint8_t) (val >> 8);
|
||||||
buf[1] = (uint8_t) (val >> 0);
|
buf[1] = (uint8_t) (val >> 0);
|
||||||
|
|
|
@ -9,11 +9,6 @@ include %D%/hla/Makefile.am
|
||||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la
|
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/hla/libocdhla.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if AICE
|
|
||||||
include %D%/aice/Makefile.am
|
|
||||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/aice/libocdaice.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
include %D%/drivers/Makefile.am
|
include %D%/drivers/Makefile.am
|
||||||
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la
|
%C%_libjtag_la_LIBADD += $(top_builddir)/%D%/drivers/libocdjtagdrivers.la
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES += %D%/libocdaice.la
|
|
||||||
|
|
||||||
%C%_libocdaice_la_CPPFLAGS = -I$(top_srcdir)/src/jtag/drivers $(AM_CPPFLAGS) $(LIBUSB1_CFLAGS)
|
|
||||||
%C%_libocdaice_la_SOURCES = \
|
|
||||||
%D%/aice_transport.c \
|
|
||||||
%D%/aice_interface.c \
|
|
||||||
%D%/aice_port.c \
|
|
||||||
%D%/aice_usb.c \
|
|
||||||
%D%/aice_pipe.c \
|
|
||||||
%D%/aice_transport.h \
|
|
||||||
%D%/aice_interface.h \
|
|
||||||
%D%/aice_port.h \
|
|
||||||
%D%/aice_usb.h \
|
|
||||||
%D%/aice_pipe.h
|
|
|
@ -1,507 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <jtag/adapter.h>
|
|
||||||
#include <jtag/interface.h>
|
|
||||||
#include <jtag/commands.h>
|
|
||||||
#include <transport/transport.h>
|
|
||||||
#include <target/target.h>
|
|
||||||
#include <jtag/aice/aice_transport.h>
|
|
||||||
#include "aice_usb.h"
|
|
||||||
|
|
||||||
#define AICE_KHZ_TO_SPEED_MAP_SIZE 16
|
|
||||||
static const int aice_khz_to_speed_map[AICE_KHZ_TO_SPEED_MAP_SIZE] = {
|
|
||||||
30000,
|
|
||||||
15000,
|
|
||||||
7500,
|
|
||||||
3750,
|
|
||||||
1875,
|
|
||||||
937,
|
|
||||||
468,
|
|
||||||
234,
|
|
||||||
48000,
|
|
||||||
24000,
|
|
||||||
12000,
|
|
||||||
6000,
|
|
||||||
3000,
|
|
||||||
1500,
|
|
||||||
750,
|
|
||||||
375,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct aice_port *aice_port;
|
|
||||||
static struct aice_port_param_s param;
|
|
||||||
static uint32_t retry_times;
|
|
||||||
static uint32_t count_to_check_dbger;
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/* External interface implementation */
|
|
||||||
static uint32_t aice_target_id_codes[AICE_MAX_NUM_CORE];
|
|
||||||
static uint8_t aice_num_of_target_id_codes;
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/* AICE operations */
|
|
||||||
int aice_init_targets(void)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
struct target *target;
|
|
||||||
struct aice_port_s *aice;
|
|
||||||
|
|
||||||
LOG_DEBUG("aice_init_targets");
|
|
||||||
|
|
||||||
if (aice_num_of_target_id_codes == 0) {
|
|
||||||
res = aice_port->api->idcode(aice_target_id_codes, &aice_num_of_target_id_codes);
|
|
||||||
if (res != ERROR_OK) {
|
|
||||||
LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore "
|
|
||||||
"JTAG Manufacture ID in the JTAG scan chain. "
|
|
||||||
"Failed to access EDM registers. -->");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (target = all_targets; target; target = target->next) {
|
|
||||||
target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position];
|
|
||||||
|
|
||||||
unsigned ii, limit = target->tap->expected_ids_cnt;
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
for (ii = 0; ii < limit; ii++) {
|
|
||||||
uint32_t expected = target->tap->expected_ids[ii];
|
|
||||||
|
|
||||||
/* treat "-expected-id 0" as a "don't-warn" wildcard */
|
|
||||||
if (!expected || (target->tap->idcode == expected)) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found == 0) {
|
|
||||||
LOG_ERROR
|
|
||||||
("aice_init_targets: target not found: idcode: %" PRIx32,
|
|
||||||
target->tap->idcode);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
aice = calloc(1, sizeof(struct aice_port_s));
|
|
||||||
aice->port = aice_port;
|
|
||||||
aice->coreid = target->tap->abs_chain_position;
|
|
||||||
|
|
||||||
target->tap->priv = aice;
|
|
||||||
target->tap->hasidcode = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/* End of External interface implementation */
|
|
||||||
|
|
||||||
/* initial aice
|
|
||||||
* 1. open usb
|
|
||||||
* 2. get/show version number
|
|
||||||
* 3. reset
|
|
||||||
*/
|
|
||||||
static int aice_init(void)
|
|
||||||
{
|
|
||||||
if (aice_port->api->open(¶m) != ERROR_OK) {
|
|
||||||
LOG_ERROR("Cannot find AICE Interface! Please check "
|
|
||||||
"connection and permissions.");
|
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
aice_port->api->set_retry_times(retry_times);
|
|
||||||
aice_port->api->set_count_to_check_dbger(count_to_check_dbger);
|
|
||||||
|
|
||||||
LOG_INFO("AICE JTAG Interface ready");
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* cleanup aice resource
|
|
||||||
* close usb
|
|
||||||
*/
|
|
||||||
static int aice_quit(void)
|
|
||||||
{
|
|
||||||
aice_port->api->close();
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_execute_reset(struct jtag_command *cmd)
|
|
||||||
{
|
|
||||||
static int last_trst;
|
|
||||||
int retval = ERROR_OK;
|
|
||||||
|
|
||||||
LOG_DEBUG_IO("reset trst: %d", cmd->cmd.reset->trst);
|
|
||||||
|
|
||||||
if (cmd->cmd.reset->trst != last_trst) {
|
|
||||||
if (cmd->cmd.reset->trst)
|
|
||||||
retval = aice_port->api->reset();
|
|
||||||
|
|
||||||
last_trst = cmd->cmd.reset->trst;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_execute_command(struct jtag_command *cmd)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
switch (cmd->type) {
|
|
||||||
case JTAG_RESET:
|
|
||||||
retval = aice_execute_reset(cmd);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
retval = ERROR_OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* aice has no need to implement jtag execution model
|
|
||||||
*/
|
|
||||||
static int aice_execute_queue(void)
|
|
||||||
{
|
|
||||||
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = ERROR_OK;
|
|
||||||
|
|
||||||
while (cmd) {
|
|
||||||
if (aice_execute_command(cmd) != ERROR_OK)
|
|
||||||
retval = ERROR_JTAG_QUEUE_FAILED;
|
|
||||||
|
|
||||||
cmd = cmd->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set jtag frequency(base frequency/frequency divider) to your jtag adapter */
|
|
||||||
static int aice_speed(int speed)
|
|
||||||
{
|
|
||||||
return aice_port->api->set_jtag_clock(speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert jtag adapter frequency(base frequency/frequency divider) to
|
|
||||||
* human readable KHz value */
|
|
||||||
static int aice_speed_div(int speed, int *khz)
|
|
||||||
{
|
|
||||||
*khz = aice_khz_to_speed_map[speed];
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert human readable KHz value to jtag adapter frequency
|
|
||||||
* (base frequency/frequency divider) */
|
|
||||||
static int aice_khz(int khz, int *jtag_speed)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++) {
|
|
||||||
if (khz == aice_khz_to_speed_map[i]) {
|
|
||||||
if (i >= 8)
|
|
||||||
*jtag_speed = i | AICE_TCK_CONTROL_TCK3048;
|
|
||||||
else
|
|
||||||
*jtag_speed = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == AICE_KHZ_TO_SPEED_MAP_SIZE) {
|
|
||||||
LOG_INFO("No support the jtag clock: %d", khz);
|
|
||||||
LOG_INFO("Supported jtag clocks are:");
|
|
||||||
|
|
||||||
for (i = 0 ; i < AICE_KHZ_TO_SPEED_MAP_SIZE ; i++)
|
|
||||||
LOG_INFO("* %d", aice_khz_to_speed_map[i]);
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_scan_jtag_chain(void)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("=== %s ===", __func__);
|
|
||||||
uint8_t num_of_idcode = 0;
|
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
int res = aice_port->api->idcode(aice_target_id_codes, &num_of_idcode);
|
|
||||||
if (res != ERROR_OK) {
|
|
||||||
LOG_ERROR("<-- TARGET ERROR! Failed to identify AndesCore "
|
|
||||||
"JTAG Manufacture ID in the JTAG scan chain. "
|
|
||||||
"Failed to access EDM registers. -->");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num_of_idcode; i++)
|
|
||||||
LOG_DEBUG("id_codes[%u] = 0x%" PRIx32, i, aice_target_id_codes[i]);
|
|
||||||
|
|
||||||
/* Update tap idcode */
|
|
||||||
for (target = all_targets; target; target = target->next)
|
|
||||||
target->tap->idcode = aice_target_id_codes[target->tap->abs_chain_position];
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/* Command handlers */
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_info_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_info_command");
|
|
||||||
|
|
||||||
command_print(CMD, "Description: %s", param.device_desc);
|
|
||||||
command_print(CMD, "Serial number: %s", adapter_get_required_serial());
|
|
||||||
if (strncmp(aice_port->name, "aice_pipe", 9) == 0)
|
|
||||||
command_print(CMD, "Adapter: %s", param.adapter_name);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_port_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_port_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC != 1) {
|
|
||||||
LOG_ERROR("Need exactly one argument to 'aice port'");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const struct aice_port *l = aice_port_get_list(); l->name; l++) {
|
|
||||||
if (strcmp(l->name, CMD_ARGV[0]) == 0) {
|
|
||||||
aice_port = l;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_ERROR("No AICE port '%s' found", CMD_ARGV[0]);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_desc_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_desc_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC == 1)
|
|
||||||
param.device_desc = strdup(CMD_ARGV[0]);
|
|
||||||
else
|
|
||||||
LOG_ERROR("expected exactly one argument to aice desc <description>");
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_vid_pid_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_vid_pid_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC != 2) {
|
|
||||||
LOG_WARNING("ignoring extra IDs in aice vid_pid (maximum is 1 pair)");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], param.vid);
|
|
||||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], param.pid);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_adapter_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_adapter_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC == 1)
|
|
||||||
param.adapter_name = strdup(CMD_ARGV[0]);
|
|
||||||
else
|
|
||||||
LOG_ERROR("expected exactly one argument to aice adapter <adapter-name>");
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_retry_times_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_retry_times_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC == 1)
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], retry_times);
|
|
||||||
else
|
|
||||||
LOG_ERROR("expected exactly one argument to aice retry_times <num_of_retry>");
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_count_to_check_dbger_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_count_to_check_dbger_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC == 1)
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count_to_check_dbger);
|
|
||||||
else
|
|
||||||
LOG_ERROR("expected exactly one argument to aice count_to_check_dbger "
|
|
||||||
"<count_of_checking>");
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_custom_srst_script_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_custom_srst_script_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC > 0) {
|
|
||||||
aice_port->api->set_custom_srst_script(CMD_ARGV[0]);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_custom_trst_script_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_custom_trst_script_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC > 0) {
|
|
||||||
aice_port->api->set_custom_trst_script(CMD_ARGV[0]);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_custom_restart_script_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_custom_restart_script_command");
|
|
||||||
|
|
||||||
if (CMD_ARGC > 0) {
|
|
||||||
aice_port->api->set_custom_restart_script(CMD_ARGV[0]);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aice_handle_aice_reset_command)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_handle_aice_reset_command");
|
|
||||||
|
|
||||||
return aice_port->api->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct command_registration aice_subcommand_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "info",
|
|
||||||
.handler = &aice_handle_aice_info_command,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.help = "show aice info",
|
|
||||||
.usage = "",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "port",
|
|
||||||
.handler = &aice_handle_aice_port_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "set the port of the AICE",
|
|
||||||
.usage = "['aice_pipe'|'aice_usb']",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "desc",
|
|
||||||
.handler = &aice_handle_aice_desc_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "set the aice device description",
|
|
||||||
.usage = "[description string]",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "vid_pid",
|
|
||||||
.handler = &aice_handle_aice_vid_pid_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "the vendor and product ID of the AICE device",
|
|
||||||
.usage = "(vid pid)*",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "adapter",
|
|
||||||
.handler = &aice_handle_aice_adapter_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "set the file name of adapter",
|
|
||||||
.usage = "[adapter name]",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "retry_times",
|
|
||||||
.handler = &aice_handle_aice_retry_times_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "set retry times as AICE timeout",
|
|
||||||
.usage = "num_of_retry",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "count_to_check_dbger",
|
|
||||||
.handler = &aice_handle_aice_count_to_check_dbger_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.help = "set retry times as checking $DBGER status",
|
|
||||||
.usage = "count_of_checking",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "custom_srst_script",
|
|
||||||
.handler = &aice_handle_aice_custom_srst_script_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.usage = "script_file_name",
|
|
||||||
.help = "set custom srst script",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "custom_trst_script",
|
|
||||||
.handler = &aice_handle_aice_custom_trst_script_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.usage = "script_file_name",
|
|
||||||
.help = "set custom trst script",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "custom_restart_script",
|
|
||||||
.handler = &aice_handle_aice_custom_restart_script_command,
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.usage = "script_file_name",
|
|
||||||
.help = "set custom restart script",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "reset",
|
|
||||||
.handler = &aice_handle_aice_reset_command,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.usage = "",
|
|
||||||
.help = "reset AICE",
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct command_registration aice_command_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "aice",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.help = "perform aice management",
|
|
||||||
.usage = "[subcommand]",
|
|
||||||
.chain = aice_subcommand_handlers,
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
/***************************************************************************/
|
|
||||||
/* End of Command handlers */
|
|
||||||
|
|
||||||
static struct jtag_interface aice_interface = {
|
|
||||||
.execute_queue = aice_execute_queue,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct adapter_driver aice_adapter_driver = {
|
|
||||||
.name = "aice",
|
|
||||||
.transports = aice_transports,
|
|
||||||
.commands = aice_command_handlers,
|
|
||||||
|
|
||||||
.init = aice_init,
|
|
||||||
.quit = aice_quit,
|
|
||||||
.speed = aice_speed, /* set interface speed */
|
|
||||||
.khz = aice_khz, /* convert khz to interface speed value */
|
|
||||||
.speed_div = aice_speed_div, /* return readable value */
|
|
||||||
|
|
||||||
.jtag_ops = &aice_interface,
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_JTAG_AICE_AICE_INTERFACE_H
|
|
||||||
#define OPENOCD_JTAG_AICE_AICE_INTERFACE_H
|
|
||||||
|
|
||||||
int aice_init_targets(void);
|
|
||||||
int aice_scan_jtag_chain(void);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_AICE_AICE_INTERFACE_H */
|
|
|
@ -1,885 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/system.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#include <signal.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/log.h>
|
|
||||||
#include <helper/time_support.h>
|
|
||||||
#include <helper/system.h>
|
|
||||||
#include "aice_port.h"
|
|
||||||
#include "aice_pipe.h"
|
|
||||||
|
|
||||||
#define AICE_PIPE_MAXLINE 8192
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
PROCESS_INFORMATION proc_info;
|
|
||||||
|
|
||||||
static HANDLE aice_pipe_output[2];
|
|
||||||
static HANDLE aice_pipe_input[2];
|
|
||||||
|
|
||||||
static int aice_pipe_write(const void *buffer, int count)
|
|
||||||
{
|
|
||||||
BOOL success;
|
|
||||||
DWORD written;
|
|
||||||
|
|
||||||
success = WriteFile(aice_pipe_output[1], buffer, count, &written, NULL);
|
|
||||||
if (!success) {
|
|
||||||
LOG_ERROR("(WIN32) write to pipe failed, error code: 0x%08l" PRIx32, GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read(void *buffer, int count)
|
|
||||||
{
|
|
||||||
BOOL success;
|
|
||||||
DWORD has_read;
|
|
||||||
|
|
||||||
success = ReadFile(aice_pipe_input[0], buffer, count, &has_read, NULL);
|
|
||||||
if (!success || (has_read == 0)) {
|
|
||||||
LOG_ERROR("(WIN32) read from pipe failed, error code: 0x%08l" PRIx32, GetLastError());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return has_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_child_init(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
STARTUPINFO start_info;
|
|
||||||
BOOL success;
|
|
||||||
|
|
||||||
ZeroMemory(&proc_info, sizeof(PROCESS_INFORMATION));
|
|
||||||
ZeroMemory(&start_info, sizeof(STARTUPINFO));
|
|
||||||
start_info.cb = sizeof(STARTUPINFO);
|
|
||||||
start_info.hStdError = aice_pipe_input[1];
|
|
||||||
start_info.hStdOutput = aice_pipe_input[1];
|
|
||||||
start_info.hStdInput = aice_pipe_output[0];
|
|
||||||
start_info.dwFlags |= STARTF_USESTDHANDLES;
|
|
||||||
|
|
||||||
success = CreateProcess(NULL,
|
|
||||||
param->adapter_name,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
TRUE,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&start_info,
|
|
||||||
&proc_info);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
LOG_ERROR("Create new process failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_parent_init(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
/* send open to adapter */
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_OPEN;
|
|
||||||
set_u16(command + 1, param->vid);
|
|
||||||
set_u16(command + 3, param->pid);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5) {
|
|
||||||
LOG_ERROR("write failed\n");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) {
|
|
||||||
LOG_ERROR("read failed\n");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_open(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
SECURITY_ATTRIBUTES attribute;
|
|
||||||
|
|
||||||
attribute.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
attribute.bInheritHandle = TRUE;
|
|
||||||
attribute.lpSecurityDescriptor = NULL;
|
|
||||||
|
|
||||||
if (!CreatePipe(&aice_pipe_output[0], &aice_pipe_output[1],
|
|
||||||
&attribute, AICE_PIPE_MAXLINE)) {
|
|
||||||
LOG_ERROR("Create pipes failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (!CreatePipe(&aice_pipe_input[0], &aice_pipe_input[1],
|
|
||||||
&attribute, AICE_PIPE_MAXLINE)) {
|
|
||||||
LOG_ERROR("Create pipes failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do not inherit aice_pipe_output[1] & aice_pipe_input[0] to child process */
|
|
||||||
if (!SetHandleInformation(aice_pipe_output[1], HANDLE_FLAG_INHERIT, 0))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
if (!SetHandleInformation(aice_pipe_input[0], HANDLE_FLAG_INHERIT, 0))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
aice_pipe_child_init(param);
|
|
||||||
|
|
||||||
aice_pipe_parent_init(param);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static int aice_pipe_output[2];
|
|
||||||
static int aice_pipe_input[2];
|
|
||||||
|
|
||||||
static int aice_pipe_write(const void *buffer, int count)
|
|
||||||
{
|
|
||||||
if (write(aice_pipe_output[1], buffer, count) != count) {
|
|
||||||
LOG_ERROR("write to pipe failed");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read(void *buffer, int count)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
int64_t then, cur;
|
|
||||||
|
|
||||||
then = timeval_ms();
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
n = read(aice_pipe_input[0], buffer, count);
|
|
||||||
|
|
||||||
if ((n == -1) && (errno == EAGAIN)) {
|
|
||||||
cur = timeval_ms();
|
|
||||||
if (cur - then > 500)
|
|
||||||
keep_alive();
|
|
||||||
continue;
|
|
||||||
} else if (n > 0)
|
|
||||||
break;
|
|
||||||
else {
|
|
||||||
LOG_ERROR("read from pipe failed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_child_init(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
close(aice_pipe_output[1]);
|
|
||||||
close(aice_pipe_input[0]);
|
|
||||||
|
|
||||||
if (aice_pipe_output[0] != STDIN_FILENO) {
|
|
||||||
if (dup2(aice_pipe_output[0], STDIN_FILENO) != STDIN_FILENO) {
|
|
||||||
LOG_ERROR("Map aice_pipe to STDIN failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
close(aice_pipe_output[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aice_pipe_input[1] != STDOUT_FILENO) {
|
|
||||||
if (dup2(aice_pipe_input[1], STDOUT_FILENO) != STDOUT_FILENO) {
|
|
||||||
LOG_ERROR("Map aice_pipe to STDOUT failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
close(aice_pipe_input[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (execl(param->adapter_name, param->adapter_name, (char *)0) < 0) {
|
|
||||||
LOG_ERROR("Execute aice_pipe failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_parent_init(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
close(aice_pipe_output[0]);
|
|
||||||
close(aice_pipe_input[1]);
|
|
||||||
|
|
||||||
/* set read end of pipe as non-blocking */
|
|
||||||
if (fcntl(aice_pipe_input[0], F_SETFL, O_NONBLOCK))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* send open to adapter */
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_OPEN;
|
|
||||||
set_u16(command + 1, param->vid);
|
|
||||||
set_u16(command + 3, param->pid);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5) {
|
|
||||||
LOG_ERROR("write failed\n");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0) {
|
|
||||||
LOG_ERROR("read failed\n");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sig_pipe(int signo)
|
|
||||||
{
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_open(struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
|
|
||||||
LOG_ERROR("Register SIGPIPE handler failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipe(aice_pipe_output) < 0 || pipe(aice_pipe_input) < 0) {
|
|
||||||
LOG_ERROR("Create pipes failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if (pid < 0) {
|
|
||||||
LOG_ERROR("Fork new process failed");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
} else if (pid == 0) {
|
|
||||||
if (aice_pipe_child_init(param) != ERROR_OK) {
|
|
||||||
LOG_ERROR("AICE_PIPE child process initial error");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
} else {
|
|
||||||
if (aice_pipe_parent_init(param) != ERROR_OK) {
|
|
||||||
LOG_ERROR("AICE_PIPE parent process initial error");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int aice_pipe_close(void)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_CLOSE;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
WaitForSingleObject(proc_info.hProcess, INFINITE);
|
|
||||||
CloseHandle(proc_info.hProcess);
|
|
||||||
CloseHandle(proc_info.hThread);
|
|
||||||
#endif
|
|
||||||
return ERROR_OK;
|
|
||||||
} else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_idcode(uint32_t *idcode, uint8_t *num_of_idcode)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_IDCODE;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*num_of_idcode = line[0];
|
|
||||||
|
|
||||||
if ((*num_of_idcode == 0) || (*num_of_idcode >= 16))
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
for (int i = 0 ; i < *num_of_idcode ; i++)
|
|
||||||
idcode[i] = get_u32(line + i * 4 + 1);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_state(uint32_t coreid, enum aice_target_state_s *state)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_STATE;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*state = (enum aice_target_state_s)line[0];
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_reset(void)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_RESET;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_assert_srst(uint32_t coreid, enum aice_srst_type_s srst)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_ASSERT_SRST;
|
|
||||||
command[1] = srst;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 2) != 2)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_run(uint32_t coreid)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_RUN;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_halt(uint32_t coreid)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_HALT;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_reg(uint32_t coreid, uint32_t num, uint32_t *val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_READ_REG;
|
|
||||||
set_u32(command + 1, num);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*val = get_u32(line);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_write_reg(uint32_t coreid, uint32_t num, uint32_t val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_WRITE_REG;
|
|
||||||
set_u32(command + 1, num);
|
|
||||||
set_u32(command + 5, val);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 9) != 9)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_reg_64(uint32_t coreid, uint32_t num, uint64_t *val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_READ_REG_64;
|
|
||||||
set_u32(command + 1, num);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*val = (((uint64_t)get_u32(line + 4)) << 32) | get_u32(line);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_write_reg_64(uint32_t coreid, uint32_t num, uint64_t val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_WRITE_REG_64;
|
|
||||||
set_u32(command + 1, num);
|
|
||||||
set_u32(command + 5, val & 0xFFFFFFFF);
|
|
||||||
set_u32(command + 9, (val >> 32) & 0xFFFFFFFF);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 13) != 9)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_step(uint32_t coreid)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_STEP;
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 1) != 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size,
|
|
||||||
uint32_t count, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_READ_MEM_UNIT;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
set_u32(command + 5, size);
|
|
||||||
set_u32(command + 9, count);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 13) != 13)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(buffer, size * count) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_write_mem_unit(uint32_t coreid, uint32_t addr, uint32_t size,
|
|
||||||
uint32_t count, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_WRITE_MEM_UNIT;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
set_u32(command + 5, size);
|
|
||||||
set_u32(command + 9, count);
|
|
||||||
|
|
||||||
/* WRITE_MEM_UNIT|addr|size|count|data */
|
|
||||||
memcpy(command + 13, buffer, size * count);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 13 + size * count) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_mem_bulk(uint32_t coreid, uint32_t addr,
|
|
||||||
uint32_t length, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE + 1];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
uint32_t remain_len = length;
|
|
||||||
uint32_t prepare_len;
|
|
||||||
char *received_line;
|
|
||||||
uint32_t received_len;
|
|
||||||
int read_len;
|
|
||||||
|
|
||||||
command[0] = AICE_READ_MEM_BULK;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
set_u32(command + 5, length);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 9) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
while (remain_len > 0) {
|
|
||||||
if (remain_len > AICE_PIPE_MAXLINE)
|
|
||||||
prepare_len = AICE_PIPE_MAXLINE;
|
|
||||||
else
|
|
||||||
prepare_len = remain_len;
|
|
||||||
|
|
||||||
prepare_len++;
|
|
||||||
received_len = 0;
|
|
||||||
received_line = line;
|
|
||||||
do {
|
|
||||||
read_len = aice_pipe_read(received_line, prepare_len - received_len);
|
|
||||||
if (read_len < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
received_line += read_len;
|
|
||||||
received_len += read_len;
|
|
||||||
} while (received_len < prepare_len);
|
|
||||||
|
|
||||||
if (line[0] != AICE_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
prepare_len--;
|
|
||||||
memcpy(buffer, line + 1, prepare_len);
|
|
||||||
remain_len -= prepare_len;
|
|
||||||
buffer += prepare_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_write_mem_bulk(uint32_t coreid, uint32_t addr,
|
|
||||||
uint32_t length, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE + 4];
|
|
||||||
uint32_t remain_len = length;
|
|
||||||
uint32_t written_len = 0;
|
|
||||||
uint32_t write_len;
|
|
||||||
|
|
||||||
command[0] = AICE_WRITE_MEM_BULK;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
set_u32(command + 5, length);
|
|
||||||
|
|
||||||
/* Send command first */
|
|
||||||
if (aice_pipe_write(command, 9) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_ERROR)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
while (remain_len > 0) {
|
|
||||||
if (remain_len > AICE_PIPE_MAXLINE)
|
|
||||||
write_len = AICE_PIPE_MAXLINE;
|
|
||||||
else
|
|
||||||
write_len = remain_len;
|
|
||||||
|
|
||||||
set_u32(command, write_len);
|
|
||||||
memcpy(command + 4, buffer + written_len, write_len); /* data only */
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, write_len + 4) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_ERROR)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
remain_len -= write_len;
|
|
||||||
written_len += write_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_debug_reg(uint32_t coreid, uint32_t addr, uint32_t *val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_READ_DEBUG_REG;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*val = get_u32(line);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_write_debug_reg(uint32_t coreid, uint32_t addr, const uint32_t val)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_WRITE_DEBUG_REG;
|
|
||||||
set_u32(command + 1, addr);
|
|
||||||
set_u32(command + 5, val);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 9) != 9)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_set_jtag_clock(uint32_t a_clock)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_SET_JTAG_CLOCK;
|
|
||||||
set_u32(command + 1, a_clock);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_memory_access(uint32_t coreid, enum nds_memory_access access_channel)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_MEMORY_ACCESS;
|
|
||||||
set_u32(command + 1, access_channel);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_memory_mode(uint32_t coreid, enum nds_memory_select mem_select)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_MEMORY_MODE;
|
|
||||||
set_u32(command + 1, mem_select);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_read_tlb(uint32_t coreid, target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_READ_TLB;
|
|
||||||
set_u32(command + 1, virtual_address);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 5) != 5)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK) {
|
|
||||||
*physical_address = get_u32(line + 1);
|
|
||||||
return ERROR_OK;
|
|
||||||
} else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_cache_ctl(uint32_t coreid, uint32_t subtype, uint32_t address)
|
|
||||||
{
|
|
||||||
char line[AICE_PIPE_MAXLINE];
|
|
||||||
char command[AICE_PIPE_MAXLINE];
|
|
||||||
|
|
||||||
command[0] = AICE_CACHE_CTL;
|
|
||||||
set_u32(command + 1, subtype);
|
|
||||||
set_u32(command + 5, address);
|
|
||||||
|
|
||||||
if (aice_pipe_write(command, 9) != 9)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (aice_pipe_read(line, AICE_PIPE_MAXLINE) < 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (line[0] == AICE_OK)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int aice_pipe_set_retry_times(uint32_t a_retry_times)
|
|
||||||
{
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
struct aice_port_api_s aice_pipe = {
|
|
||||||
/** */
|
|
||||||
.open = aice_pipe_open,
|
|
||||||
/** */
|
|
||||||
.close = aice_pipe_close,
|
|
||||||
/** */
|
|
||||||
.idcode = aice_pipe_idcode,
|
|
||||||
/** */
|
|
||||||
.set_jtag_clock = aice_pipe_set_jtag_clock,
|
|
||||||
/** */
|
|
||||||
.state = aice_pipe_state,
|
|
||||||
/** */
|
|
||||||
.reset = aice_pipe_reset,
|
|
||||||
/** */
|
|
||||||
.assert_srst = aice_pipe_assert_srst,
|
|
||||||
/** */
|
|
||||||
.run = aice_pipe_run,
|
|
||||||
/** */
|
|
||||||
.halt = aice_pipe_halt,
|
|
||||||
/** */
|
|
||||||
.step = aice_pipe_step,
|
|
||||||
/** */
|
|
||||||
.read_reg = aice_pipe_read_reg,
|
|
||||||
/** */
|
|
||||||
.write_reg = aice_pipe_write_reg,
|
|
||||||
/** */
|
|
||||||
.read_reg_64 = aice_pipe_read_reg_64,
|
|
||||||
/** */
|
|
||||||
.write_reg_64 = aice_pipe_write_reg_64,
|
|
||||||
/** */
|
|
||||||
.read_mem_unit = aice_pipe_read_mem_unit,
|
|
||||||
/** */
|
|
||||||
.write_mem_unit = aice_pipe_write_mem_unit,
|
|
||||||
/** */
|
|
||||||
.read_mem_bulk = aice_pipe_read_mem_bulk,
|
|
||||||
/** */
|
|
||||||
.write_mem_bulk = aice_pipe_write_mem_bulk,
|
|
||||||
/** */
|
|
||||||
.read_debug_reg = aice_pipe_read_debug_reg,
|
|
||||||
/** */
|
|
||||||
.write_debug_reg = aice_pipe_write_debug_reg,
|
|
||||||
|
|
||||||
/** */
|
|
||||||
.memory_access = aice_pipe_memory_access,
|
|
||||||
/** */
|
|
||||||
.memory_mode = aice_pipe_memory_mode,
|
|
||||||
|
|
||||||
/** */
|
|
||||||
.read_tlb = aice_pipe_read_tlb,
|
|
||||||
|
|
||||||
/** */
|
|
||||||
.cache_ctl = aice_pipe_cache_ctl,
|
|
||||||
|
|
||||||
/** */
|
|
||||||
.set_retry_times = aice_pipe_set_retry_times,
|
|
||||||
};
|
|
|
@ -1,20 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_JTAG_AICE_AICE_PIPE_H
|
|
||||||
#define OPENOCD_JTAG_AICE_AICE_PIPE_H
|
|
||||||
|
|
||||||
#include <helper/types.h>
|
|
||||||
|
|
||||||
#define set_u32(buffer, value) h_u32_to_le((uint8_t *)buffer, value)
|
|
||||||
#define set_u16(buffer, value) h_u16_to_le((uint8_t *)buffer, value)
|
|
||||||
#define get_u32(buffer) le_to_h_u32((const uint8_t *)buffer)
|
|
||||||
#define get_u16(buffer) le_to_h_u16((const uint8_t *)buffer)
|
|
||||||
|
|
||||||
extern struct aice_port_api_s aice_pipe;
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_AICE_AICE_PIPE_H */
|
|
|
@ -1,34 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/log.h>
|
|
||||||
#include "aice_usb.h"
|
|
||||||
#include "aice_pipe.h"
|
|
||||||
#include "aice_port.h"
|
|
||||||
|
|
||||||
static const struct aice_port aice_ports[] = {
|
|
||||||
{
|
|
||||||
.name = "aice_usb",
|
|
||||||
.type = AICE_PORT_AICE_USB,
|
|
||||||
.api = &aice_usb_api,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "aice_pipe",
|
|
||||||
.type = AICE_PORT_AICE_PIPE,
|
|
||||||
.api = &aice_pipe,
|
|
||||||
},
|
|
||||||
{.name = NULL, /* END OF TABLE */ },
|
|
||||||
};
|
|
||||||
|
|
||||||
/** */
|
|
||||||
const struct aice_port *aice_port_get_list(void)
|
|
||||||
{
|
|
||||||
return aice_ports;
|
|
||||||
}
|
|
|
@ -1,224 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_JTAG_AICE_AICE_PORT_H
|
|
||||||
#define OPENOCD_JTAG_AICE_AICE_PORT_H
|
|
||||||
|
|
||||||
#include <target/nds32_edm.h>
|
|
||||||
|
|
||||||
#define AICE_MAX_NUM_CORE (0x10)
|
|
||||||
|
|
||||||
#define ERROR_AICE_DISCONNECT (-200)
|
|
||||||
#define ERROR_AICE_TIMEOUT (-201)
|
|
||||||
|
|
||||||
enum aice_target_state_s {
|
|
||||||
AICE_DISCONNECT = 0,
|
|
||||||
AICE_TARGET_DETACH,
|
|
||||||
AICE_TARGET_UNKNOWN,
|
|
||||||
AICE_TARGET_RUNNING,
|
|
||||||
AICE_TARGET_HALTED,
|
|
||||||
AICE_TARGET_RESET,
|
|
||||||
AICE_TARGET_DEBUG_RUNNING,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_srst_type_s {
|
|
||||||
AICE_SRST = 0x1,
|
|
||||||
AICE_RESET_HOLD = 0x8,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_target_endian {
|
|
||||||
AICE_LITTLE_ENDIAN = 0,
|
|
||||||
AICE_BIG_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_api_s {
|
|
||||||
AICE_OPEN = 0x0,
|
|
||||||
AICE_CLOSE,
|
|
||||||
AICE_RESET,
|
|
||||||
AICE_IDCODE,
|
|
||||||
AICE_SET_JTAG_CLOCK,
|
|
||||||
AICE_ASSERT_SRST,
|
|
||||||
AICE_RUN,
|
|
||||||
AICE_HALT,
|
|
||||||
AICE_STEP,
|
|
||||||
AICE_READ_REG,
|
|
||||||
AICE_WRITE_REG,
|
|
||||||
AICE_READ_REG_64,
|
|
||||||
AICE_WRITE_REG_64,
|
|
||||||
AICE_READ_MEM_UNIT,
|
|
||||||
AICE_WRITE_MEM_UNIT,
|
|
||||||
AICE_READ_MEM_BULK,
|
|
||||||
AICE_WRITE_MEM_BULK,
|
|
||||||
AICE_READ_DEBUG_REG,
|
|
||||||
AICE_WRITE_DEBUG_REG,
|
|
||||||
AICE_STATE,
|
|
||||||
AICE_MEMORY_ACCESS,
|
|
||||||
AICE_MEMORY_MODE,
|
|
||||||
AICE_READ_TLB,
|
|
||||||
AICE_CACHE_CTL,
|
|
||||||
AICE_SET_RETRY_TIMES,
|
|
||||||
AICE_PROGRAM_EDM,
|
|
||||||
AICE_SET_COMMAND_MODE,
|
|
||||||
AICE_EXECUTE,
|
|
||||||
AICE_SET_CUSTOM_SRST_SCRIPT,
|
|
||||||
AICE_SET_CUSTOM_TRST_SCRIPT,
|
|
||||||
AICE_SET_CUSTOM_RESTART_SCRIPT,
|
|
||||||
AICE_SET_COUNT_TO_CHECK_DBGER,
|
|
||||||
AICE_SET_DATA_ENDIAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_error_s {
|
|
||||||
AICE_OK,
|
|
||||||
AICE_ACK,
|
|
||||||
AICE_ERROR,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_cache_ctl_type {
|
|
||||||
AICE_CACHE_CTL_L1D_INVALALL = 0,
|
|
||||||
AICE_CACHE_CTL_L1D_VA_INVAL,
|
|
||||||
AICE_CACHE_CTL_L1D_WBALL,
|
|
||||||
AICE_CACHE_CTL_L1D_VA_WB,
|
|
||||||
AICE_CACHE_CTL_L1I_INVALALL,
|
|
||||||
AICE_CACHE_CTL_L1I_VA_INVAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum aice_command_mode {
|
|
||||||
AICE_COMMAND_MODE_NORMAL,
|
|
||||||
AICE_COMMAND_MODE_PACK,
|
|
||||||
AICE_COMMAND_MODE_BATCH,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct aice_port_param_s {
|
|
||||||
/** */
|
|
||||||
const char *device_desc;
|
|
||||||
/** */
|
|
||||||
uint16_t vid;
|
|
||||||
/** */
|
|
||||||
uint16_t pid;
|
|
||||||
/** */
|
|
||||||
char *adapter_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct aice_port_s {
|
|
||||||
/** */
|
|
||||||
uint32_t coreid;
|
|
||||||
/** */
|
|
||||||
const struct aice_port *port;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** */
|
|
||||||
extern struct aice_port_api_s aice_usb_layout_api;
|
|
||||||
|
|
||||||
/** */
|
|
||||||
struct aice_port_api_s {
|
|
||||||
/** */
|
|
||||||
int (*open)(struct aice_port_param_s *param);
|
|
||||||
/** */
|
|
||||||
int (*close)(void);
|
|
||||||
/** */
|
|
||||||
int (*reset)(void);
|
|
||||||
/** */
|
|
||||||
int (*idcode)(uint32_t *idcode, uint8_t *num_of_idcode);
|
|
||||||
/** */
|
|
||||||
int (*set_jtag_clock)(uint32_t a_clock);
|
|
||||||
/** */
|
|
||||||
int (*assert_srst)(uint32_t coreid, enum aice_srst_type_s srst);
|
|
||||||
/** */
|
|
||||||
int (*run)(uint32_t coreid);
|
|
||||||
/** */
|
|
||||||
int (*halt)(uint32_t coreid);
|
|
||||||
/** */
|
|
||||||
int (*step)(uint32_t coreid);
|
|
||||||
/** */
|
|
||||||
int (*read_reg)(uint32_t coreid, uint32_t num, uint32_t *val);
|
|
||||||
/** */
|
|
||||||
int (*write_reg)(uint32_t coreid, uint32_t num, uint32_t val);
|
|
||||||
/** */
|
|
||||||
int (*read_reg_64)(uint32_t coreid, uint32_t num, uint64_t *val);
|
|
||||||
/** */
|
|
||||||
int (*write_reg_64)(uint32_t coreid, uint32_t num, uint64_t val);
|
|
||||||
/** */
|
|
||||||
int (*read_mem_unit)(uint32_t coreid, uint32_t addr, uint32_t size,
|
|
||||||
uint32_t count, uint8_t *buffer);
|
|
||||||
/** */
|
|
||||||
int (*write_mem_unit)(uint32_t coreid, uint32_t addr, uint32_t size,
|
|
||||||
uint32_t count, const uint8_t *buffer);
|
|
||||||
/** */
|
|
||||||
int (*read_mem_bulk)(uint32_t coreid, uint32_t addr, uint32_t length,
|
|
||||||
uint8_t *buffer);
|
|
||||||
/** */
|
|
||||||
int (*write_mem_bulk)(uint32_t coreid, uint32_t addr, uint32_t length,
|
|
||||||
const uint8_t *buffer);
|
|
||||||
/** */
|
|
||||||
int (*read_debug_reg)(uint32_t coreid, uint32_t addr, uint32_t *val);
|
|
||||||
/** */
|
|
||||||
int (*write_debug_reg)(uint32_t coreid, uint32_t addr, const uint32_t val);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*state)(uint32_t coreid, enum aice_target_state_s *state);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*memory_access)(uint32_t coreid, enum nds_memory_access a_access);
|
|
||||||
/** */
|
|
||||||
int (*memory_mode)(uint32_t coreid, enum nds_memory_select mem_select);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*read_tlb)(uint32_t coreid, target_addr_t virtual_address, target_addr_t *physical_address);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*cache_ctl)(uint32_t coreid, uint32_t subtype, uint32_t address);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_retry_times)(uint32_t a_retry_times);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*program_edm)(uint32_t coreid, char *command_sequence);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_command_mode)(enum aice_command_mode command_mode);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*execute)(uint32_t coreid, uint32_t *instructions, uint32_t instruction_num);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_custom_srst_script)(const char *script);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_custom_trst_script)(const char *script);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_custom_restart_script)(const char *script);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_count_to_check_dbger)(uint32_t count_to_check);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*set_data_endian)(uint32_t coreid, enum aice_target_endian target_data_endian);
|
|
||||||
|
|
||||||
/** */
|
|
||||||
int (*profiling)(uint32_t coreid, uint32_t interval, uint32_t iteration,
|
|
||||||
uint32_t reg_no, uint32_t *samples, uint32_t *num_samples);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AICE_PORT_UNKNOWN 0
|
|
||||||
#define AICE_PORT_AICE_USB 1
|
|
||||||
#define AICE_PORT_AICE_PIPE 2
|
|
||||||
|
|
||||||
/** */
|
|
||||||
struct aice_port {
|
|
||||||
/** */
|
|
||||||
const char *name;
|
|
||||||
/** */
|
|
||||||
int type;
|
|
||||||
/** */
|
|
||||||
struct aice_port_api_s *const api;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** */
|
|
||||||
const struct aice_port *aice_port_get_list(void);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_AICE_AICE_PORT_H */
|
|
|
@ -1,432 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* project specific includes */
|
|
||||||
#include <jtag/interface.h>
|
|
||||||
#include <jtag/tcl.h>
|
|
||||||
#include <transport/transport.h>
|
|
||||||
#include <target/target.h>
|
|
||||||
#include <jtag/aice/aice_interface.h>
|
|
||||||
#include <jtag/aice/aice_transport.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi,
|
|
||||||
struct jtag_tap *tap)
|
|
||||||
{
|
|
||||||
jim_wide w;
|
|
||||||
int e = jim_getopt_wide(goi, &w);
|
|
||||||
if (e != JIM_OK) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "option: %s bad parameter",
|
|
||||||
n->name);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned expected_len = sizeof(uint32_t) * tap->expected_ids_cnt;
|
|
||||||
uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t));
|
|
||||||
if (!new_expected_ids) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "no memory");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(tap->expected_ids);
|
|
||||||
memcpy(new_expected_ids, tap->expected_ids, expected_len);
|
|
||||||
|
|
||||||
new_expected_ids[tap->expected_ids_cnt] = w;
|
|
||||||
|
|
||||||
free(tap->expected_ids);
|
|
||||||
tap->expected_ids = new_expected_ids;
|
|
||||||
tap->expected_ids_cnt++;
|
|
||||||
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NTAP_OPT_EXPECTED_ID 0
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int jim_aice_newtap_cmd(struct jim_getopt_info *goi)
|
|
||||||
{
|
|
||||||
struct jtag_tap *tap;
|
|
||||||
int x;
|
|
||||||
int e;
|
|
||||||
struct jim_nvp *n;
|
|
||||||
char *cp;
|
|
||||||
const struct jim_nvp opts[] = {
|
|
||||||
{.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID},
|
|
||||||
{.name = NULL, .value = -1},
|
|
||||||
};
|
|
||||||
|
|
||||||
tap = calloc(1, sizeof(struct jtag_tap));
|
|
||||||
if (!tap) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "no memory");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* we expect CHIP + TAP + OPTIONS
|
|
||||||
* */
|
|
||||||
if (goi->argc < 3) {
|
|
||||||
Jim_SetResultFormatted(goi->interp,
|
|
||||||
"Missing CHIP TAP OPTIONS ....");
|
|
||||||
free(tap);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *tmp;
|
|
||||||
jim_getopt_string(goi, &tmp, NULL);
|
|
||||||
tap->chip = strdup(tmp);
|
|
||||||
|
|
||||||
jim_getopt_string(goi, &tmp, NULL);
|
|
||||||
tap->tapname = strdup(tmp);
|
|
||||||
|
|
||||||
/* name + dot + name + null */
|
|
||||||
x = strlen(tap->chip) + 1 + strlen(tap->tapname) + 1;
|
|
||||||
cp = malloc(x);
|
|
||||||
sprintf(cp, "%s.%s", tap->chip, tap->tapname);
|
|
||||||
tap->dotted_name = cp;
|
|
||||||
|
|
||||||
LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
|
|
||||||
tap->chip, tap->tapname, tap->dotted_name, goi->argc);
|
|
||||||
|
|
||||||
while (goi->argc) {
|
|
||||||
e = jim_getopt_nvp(goi, opts, &n);
|
|
||||||
if (e != JIM_OK) {
|
|
||||||
jim_getopt_nvp_unknown(goi, opts, 0);
|
|
||||||
free(cp);
|
|
||||||
free(tap);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Processing option: %s", n->name);
|
|
||||||
switch (n->value) {
|
|
||||||
case NTAP_OPT_EXPECTED_ID:
|
|
||||||
e = jim_newtap_expected_id(n, goi, tap);
|
|
||||||
if (e != JIM_OK) {
|
|
||||||
free(cp);
|
|
||||||
free(tap);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} /* switch (n->value) */
|
|
||||||
} /* while (goi->argc) */
|
|
||||||
|
|
||||||
/* default is enabled-after-reset */
|
|
||||||
tap->enabled = !tap->disabled_after_reset;
|
|
||||||
|
|
||||||
jtag_tap_init(tap);
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int jim_aice_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
|
||||||
{
|
|
||||||
struct jim_getopt_info goi;
|
|
||||||
jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
|
|
||||||
return jim_aice_newtap_cmd(&goi);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
COMMAND_HANDLER(handle_aice_init_command)
|
|
||||||
{
|
|
||||||
if (CMD_ARGC != 0)
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
|
|
||||||
static bool jtag_initialized;
|
|
||||||
if (jtag_initialized) {
|
|
||||||
LOG_INFO("'jtag init' has already been called");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
jtag_initialized = true;
|
|
||||||
|
|
||||||
LOG_DEBUG("Initializing jtag devices...");
|
|
||||||
return jtag_init(CMD_CTX);
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_scan_chain_command)
|
|
||||||
{
|
|
||||||
struct jtag_tap *tap;
|
|
||||||
char expected_id[12];
|
|
||||||
|
|
||||||
aice_scan_jtag_chain();
|
|
||||||
tap = jtag_all_taps();
|
|
||||||
command_print(CMD,
|
|
||||||
" TapName Enabled IdCode Expected IrLen IrCap IrMask");
|
|
||||||
command_print(CMD,
|
|
||||||
"-- ------------------- -------- ---------- ---------- ----- ----- ------");
|
|
||||||
|
|
||||||
while (tap) {
|
|
||||||
uint32_t expected, expected_mask, ii;
|
|
||||||
|
|
||||||
snprintf(expected_id, sizeof(expected_id), "0x%08x",
|
|
||||||
(unsigned)((tap->expected_ids_cnt > 0)
|
|
||||||
? tap->expected_ids[0]
|
|
||||||
: 0));
|
|
||||||
if (tap->ignore_version)
|
|
||||||
expected_id[2] = '*';
|
|
||||||
|
|
||||||
expected = buf_get_u32(tap->expected, 0, tap->ir_length);
|
|
||||||
expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length);
|
|
||||||
|
|
||||||
command_print(CMD,
|
|
||||||
"%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x",
|
|
||||||
tap->abs_chain_position,
|
|
||||||
tap->dotted_name,
|
|
||||||
tap->enabled ? 'Y' : 'n',
|
|
||||||
(unsigned int)(tap->idcode),
|
|
||||||
expected_id,
|
|
||||||
(unsigned int)(tap->ir_length),
|
|
||||||
(unsigned int)(expected),
|
|
||||||
(unsigned int)(expected_mask));
|
|
||||||
|
|
||||||
for (ii = 1; ii < tap->expected_ids_cnt; ii++) {
|
|
||||||
snprintf(expected_id, sizeof(expected_id), "0x%08x",
|
|
||||||
(unsigned) tap->expected_ids[ii]);
|
|
||||||
if (tap->ignore_version)
|
|
||||||
expected_id[2] = '*';
|
|
||||||
|
|
||||||
command_print(CMD,
|
|
||||||
" %s",
|
|
||||||
expected_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
tap = tap->next_tap;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jim_aice_arp_init(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("No implement: jim_aice_arp_init");
|
|
||||||
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int aice_init_reset(struct command_context *cmd_ctx)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("Initializing with hard TRST+SRST reset");
|
|
||||||
|
|
||||||
int retval;
|
|
||||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
|
||||||
|
|
||||||
jtag_add_reset(1, 0); /* TAP_RESET */
|
|
||||||
if (jtag_reset_config & RESET_HAS_SRST) {
|
|
||||||
jtag_add_reset(1, 1);
|
|
||||||
if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)
|
|
||||||
jtag_add_reset(0, 1);
|
|
||||||
}
|
|
||||||
jtag_add_reset(0, 0);
|
|
||||||
retval = jtag_execute_queue();
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int jim_aice_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
|
||||||
{
|
|
||||||
int e = ERROR_OK;
|
|
||||||
struct jim_getopt_info goi;
|
|
||||||
jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
|
|
||||||
if (goi.argc != 0) {
|
|
||||||
Jim_WrongNumArgs(goi.interp, 1, goi.argv - 1, "(no params)");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
struct command_context *context = current_command_context(interp);
|
|
||||||
e = aice_init_reset(context);
|
|
||||||
|
|
||||||
if (e != ERROR_OK) {
|
|
||||||
Jim_Obj *obj = Jim_NewIntObj(goi.interp, e);
|
|
||||||
Jim_SetResultFormatted(goi.interp, "error: %#s", obj);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jim_aice_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|
||||||
{
|
|
||||||
struct jim_getopt_info goi;
|
|
||||||
jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
|
|
||||||
if (goi.argc != 0) {
|
|
||||||
Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0));
|
|
||||||
struct jtag_tap *tap;
|
|
||||||
|
|
||||||
for (tap = jtag_all_taps(); tap; tap = tap->next_tap)
|
|
||||||
Jim_ListAppendElement(goi.interp,
|
|
||||||
Jim_GetResult(goi.interp),
|
|
||||||
Jim_NewStringObj(goi.interp,
|
|
||||||
tap->dotted_name, -1));
|
|
||||||
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static const struct command_registration aice_transport_jtag_subcommand_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "init",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.handler = handle_aice_init_command,
|
|
||||||
.help = "initialize jtag scan chain",
|
|
||||||
.usage = ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "arp_init",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.jim_handler = jim_aice_arp_init,
|
|
||||||
.help = "Validates JTAG scan chain against the list of "
|
|
||||||
"declared TAPs.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "arp_init-reset",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.jim_handler = jim_aice_arp_init_reset,
|
|
||||||
.help = "Uses TRST and SRST to try resetting everything on "
|
|
||||||
"the JTAG scan chain, then performs 'jtag arp_init'."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "newtap",
|
|
||||||
.mode = COMMAND_CONFIG,
|
|
||||||
.jim_handler = jim_aice_newtap,
|
|
||||||
.help = "Create a new TAP instance named basename.tap_type, "
|
|
||||||
"and appends it to the scan chain.",
|
|
||||||
.usage = "basename tap_type ['-expected_id' number]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "tapisenabled",
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
|
||||||
.help = "Returns a Tcl boolean (0/1) indicating whether "
|
|
||||||
"the TAP is enabled (1) or not (0).",
|
|
||||||
.usage = "tap_name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "tapenable",
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
|
||||||
.help = "Try to enable the specified TAP using the "
|
|
||||||
"'tap-enable' TAP event.",
|
|
||||||
.usage = "tap_name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "tapdisable",
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
|
||||||
.help = "Try to disable the specified TAP using the "
|
|
||||||
"'tap-disable' TAP event.",
|
|
||||||
.usage = "tap_name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "configure",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.jim_handler = jim_jtag_configure,
|
|
||||||
.help = "Provide a Tcl handler for the specified "
|
|
||||||
"TAP event.",
|
|
||||||
.usage = "tap_name '-event' event_name handler",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "cget",
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.jim_handler = jim_jtag_configure,
|
|
||||||
.help = "Return any Tcl handler for the specified "
|
|
||||||
"TAP event.",
|
|
||||||
.usage = "tap_name '-event' event_name",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "names",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.jim_handler = jim_aice_names,
|
|
||||||
.help = "Returns list of all JTAG tap names.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "scan_chain",
|
|
||||||
.handler = handle_scan_chain_command,
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.help = "print current scan chain configuration",
|
|
||||||
.usage = ""
|
|
||||||
},
|
|
||||||
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static const struct command_registration aice_transport_command_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "jtag",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.usage = "",
|
|
||||||
.chain = aice_transport_jtag_subcommand_handlers,
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int aice_transport_register_commands(struct command_context *cmd_ctx)
|
|
||||||
{
|
|
||||||
return register_commands(cmd_ctx, NULL, aice_transport_command_handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int aice_transport_init(struct command_context *cmd_ctx)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_transport_init");
|
|
||||||
struct target *t = get_current_target(cmd_ctx);
|
|
||||||
struct transport *transport;
|
|
||||||
|
|
||||||
if (!t) {
|
|
||||||
LOG_ERROR("no current target");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
transport = get_current_transport();
|
|
||||||
|
|
||||||
if (!transport) {
|
|
||||||
LOG_ERROR("no transport selected");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("current transport %s", transport->name);
|
|
||||||
|
|
||||||
return aice_init_targets();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
static int aice_transport_select(struct command_context *ctx)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("aice_transport_select");
|
|
||||||
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
retval = aice_transport_register_commands(ctx);
|
|
||||||
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct transport aice_jtag_transport = {
|
|
||||||
.name = "aice_jtag",
|
|
||||||
.select = aice_transport_select,
|
|
||||||
.init = aice_transport_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *aice_transports[] = { "aice_jtag", NULL };
|
|
||||||
|
|
||||||
static void aice_constructor(void) __attribute__((constructor));
|
|
||||||
static void aice_constructor(void)
|
|
||||||
{
|
|
||||||
transport_register(&aice_jtag_transport);
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_JTAG_AICE_AICE_TRANSPORT_H
|
|
||||||
#define OPENOCD_JTAG_AICE_AICE_TRANSPORT_H
|
|
||||||
|
|
||||||
extern const char *aice_transports[];
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_AICE_AICE_TRANSPORT_H */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,122 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 by Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_JTAG_AICE_AICE_USB_H
|
|
||||||
#define OPENOCD_JTAG_AICE_AICE_USB_H
|
|
||||||
|
|
||||||
#include "aice_port.h"
|
|
||||||
|
|
||||||
/* AICE USB timeout value */
|
|
||||||
#define AICE_USB_TIMEOUT 5000
|
|
||||||
|
|
||||||
/* AICE USB buffer size */
|
|
||||||
#define AICE_IN_BUFFER_SIZE 2048
|
|
||||||
#define AICE_OUT_BUFFER_SIZE 2048
|
|
||||||
#define AICE_IN_PACKETS_BUFFER_SIZE 2048
|
|
||||||
#define AICE_OUT_PACKETS_BUFFER_SIZE 2048
|
|
||||||
#define AICE_IN_BATCH_COMMAND_SIZE 512
|
|
||||||
#define AICE_OUT_BATCH_COMMAND_SIZE 512
|
|
||||||
#define AICE_IN_PACK_COMMAND_SIZE 2048
|
|
||||||
#define AICE_OUT_PACK_COMMAND_SIZE 2048
|
|
||||||
|
|
||||||
/* Constants for AICE command READ_CTRL */
|
|
||||||
#define AICE_READ_CTRL_GET_ICE_STATE 0x00
|
|
||||||
#define AICE_READ_CTRL_GET_HARDWARE_VERSION 0x01
|
|
||||||
#define AICE_READ_CTRL_GET_FPGA_VERSION 0x02
|
|
||||||
#define AICE_READ_CTRL_GET_FIRMWARE_VERSION 0x03
|
|
||||||
#define AICE_READ_CTRL_GET_JTAG_PIN_STATUS 0x04
|
|
||||||
#define AICE_READ_CTRL_BATCH_BUF_INFO 0x22
|
|
||||||
#define AICE_READ_CTRL_BATCH_STATUS 0x23
|
|
||||||
#define AICE_READ_CTRL_BATCH_BUF0_STATE 0x31
|
|
||||||
#define AICE_READ_CTRL_BATCH_BUF4_STATE 0x39
|
|
||||||
#define AICE_READ_CTRL_BATCH_BUF5_STATE 0x3b
|
|
||||||
|
|
||||||
/* Constants for AICE command WRITE_CTRL */
|
|
||||||
#define AICE_WRITE_CTRL_TCK_CONTROL 0x00
|
|
||||||
#define AICE_WRITE_CTRL_JTAG_PIN_CONTROL 0x01
|
|
||||||
#define AICE_WRITE_CTRL_CLEAR_TIMEOUT_STATUS 0x02
|
|
||||||
#define AICE_WRITE_CTRL_RESERVED 0x03
|
|
||||||
#define AICE_WRITE_CTRL_JTAG_PIN_STATUS 0x04
|
|
||||||
#define AICE_WRITE_CTRL_CUSTOM_DELAY 0x0d
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_CTRL 0x20
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_ITERATION 0x21
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_DIM_SIZE 0x22
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_CMD_BUF0_CTRL 0x30
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_DATA_BUF0_CTRL 0x38
|
|
||||||
#define AICE_WRITE_CTRL_BATCH_DATA_BUF1_CTRL 0x3a
|
|
||||||
|
|
||||||
#define AICE_BATCH_COMMAND_BUFFER_0 0x0
|
|
||||||
#define AICE_BATCH_COMMAND_BUFFER_1 0x1
|
|
||||||
#define AICE_BATCH_COMMAND_BUFFER_2 0x2
|
|
||||||
#define AICE_BATCH_COMMAND_BUFFER_3 0x3
|
|
||||||
#define AICE_BATCH_DATA_BUFFER_0 0x4
|
|
||||||
#define AICE_BATCH_DATA_BUFFER_1 0x5
|
|
||||||
#define AICE_BATCH_DATA_BUFFER_2 0x6
|
|
||||||
#define AICE_BATCH_DATA_BUFFER_3 0x7
|
|
||||||
|
|
||||||
/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
|
|
||||||
#define AICE_TCK_CONTROL_TCK3048 0x08
|
|
||||||
#define AICE_TCK_CONTROL_TCK_SCAN 0x10
|
|
||||||
|
|
||||||
/* Constants for AICE command WRITE_CTRL:JTAG_PIN_CONTROL */
|
|
||||||
#define AICE_JTAG_PIN_CONTROL_SRST 0x01
|
|
||||||
#define AICE_JTAG_PIN_CONTROL_TRST 0x02
|
|
||||||
#define AICE_JTAG_PIN_CONTROL_STOP 0x04
|
|
||||||
#define AICE_JTAG_PIN_CONTROL_RESTART 0x08
|
|
||||||
|
|
||||||
/* Constants for AICE command WRITE_CTRL:TCK_CONTROL */
|
|
||||||
#define AICE_TCK_CONTROL_TCK_SCAN 0x10
|
|
||||||
|
|
||||||
/* Custom SRST/DBGI/TRST */
|
|
||||||
#define AICE_CUSTOM_DELAY_SET_SRST 0x01
|
|
||||||
#define AICE_CUSTOM_DELAY_CLEAN_SRST 0x02
|
|
||||||
#define AICE_CUSTOM_DELAY_SET_DBGI 0x04
|
|
||||||
#define AICE_CUSTOM_DELAY_CLEAN_DBGI 0x08
|
|
||||||
#define AICE_CUSTOM_DELAY_SET_TRST 0x10
|
|
||||||
#define AICE_CUSTOM_DELAY_CLEAN_TRST 0x20
|
|
||||||
|
|
||||||
struct aice_usb_handler_s {
|
|
||||||
unsigned int usb_read_ep;
|
|
||||||
unsigned int usb_write_ep;
|
|
||||||
struct libusb_device_handle *usb_handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cache_info {
|
|
||||||
uint32_t set;
|
|
||||||
uint32_t way;
|
|
||||||
uint32_t line_size;
|
|
||||||
|
|
||||||
uint32_t log2_set;
|
|
||||||
uint32_t log2_line_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct aice_nds32_info {
|
|
||||||
uint32_t edm_version;
|
|
||||||
uint32_t r0_backup;
|
|
||||||
uint32_t r1_backup;
|
|
||||||
uint32_t host_dtr_backup;
|
|
||||||
uint32_t target_dtr_backup;
|
|
||||||
uint32_t edmsw_backup;
|
|
||||||
uint32_t edm_ctl_backup;
|
|
||||||
bool debug_under_dex_on;
|
|
||||||
bool dex_use_psw_on;
|
|
||||||
bool host_dtr_valid;
|
|
||||||
bool target_dtr_valid;
|
|
||||||
enum nds_memory_access access_channel;
|
|
||||||
enum nds_memory_select memory_select;
|
|
||||||
enum aice_target_state_s core_state;
|
|
||||||
bool cache_init;
|
|
||||||
struct cache_info icache;
|
|
||||||
struct cache_info dcache;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct aice_port_api_s aice_usb_api;
|
|
||||||
|
|
||||||
int aice_read_ctrl(uint32_t address, uint32_t *data);
|
|
||||||
int aice_write_ctrl(uint32_t address, uint32_t data);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_AICE_AICE_USB_H */
|
|
|
@ -776,17 +776,12 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
|
||||||
|
|
||||||
static void armjtagew_debug_buffer(uint8_t *buffer, int length)
|
static void armjtagew_debug_buffer(uint8_t *buffer, int length)
|
||||||
{
|
{
|
||||||
char line[81];
|
char line[8 + 3 * BYTES_PER_LINE + 1];
|
||||||
char s[4];
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i += BYTES_PER_LINE) {
|
for (int i = 0; i < length; i += BYTES_PER_LINE) {
|
||||||
snprintf(line, 5, "%04x", i);
|
int n = snprintf(line, 9, "%04x", i);
|
||||||
for (j = i; j < i + BYTES_PER_LINE && j < length; j++) {
|
for (int j = i; j < i + BYTES_PER_LINE && j < length; j++)
|
||||||
snprintf(s, 4, " %02x", buffer[j]);
|
n += snprintf(line + n, 4, " %02x", buffer[j]);
|
||||||
strcat(line, s);
|
|
||||||
}
|
|
||||||
LOG_DEBUG("%s", line);
|
LOG_DEBUG("%s", line);
|
||||||
|
|
||||||
/* Prevent GDB timeout (writing to log might take some time) */
|
/* Prevent GDB timeout (writing to log might take some time) */
|
||||||
|
|
|
@ -57,6 +57,15 @@ static struct initial_gpio_state {
|
||||||
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
|
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
|
||||||
static uint32_t initial_drive_strength_etc;
|
static uint32_t initial_drive_strength_etc;
|
||||||
|
|
||||||
|
static inline void bcm2835_gpio_synchronize(void)
|
||||||
|
{
|
||||||
|
/* Ensure that previous writes to GPIO registers are flushed out of
|
||||||
|
* the inner shareable domain to prevent pipelined writes to the
|
||||||
|
* same address being merged.
|
||||||
|
*/
|
||||||
|
__sync_synchronize();
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
|
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
|
||||||
{
|
{
|
||||||
/* Only chip 0 is supported, accept unset value (-1) too */
|
/* Only chip 0 is supported, accept unset value (-1) too */
|
||||||
|
@ -96,6 +105,7 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_gpio(enum adapter_gpio_config_index idx)
|
static void restore_gpio(enum adapter_gpio_config_index idx)
|
||||||
|
@ -109,6 +119,7 @@ static void restore_gpio(enum adapter_gpio_config_index idx)
|
||||||
GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
|
GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initialize_gpio(enum adapter_gpio_config_index idx)
|
static void initialize_gpio(enum adapter_gpio_config_index idx)
|
||||||
|
@ -143,6 +154,7 @@ static void initialize_gpio(enum adapter_gpio_config_index idx)
|
||||||
/* Direction for non push-pull is already set by set_gpio_value() */
|
/* Direction for non push-pull is already set by set_gpio_value() */
|
||||||
if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
|
if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL)
|
||||||
OUT_GPIO(adapter_gpio_config[idx].gpio_num);
|
OUT_GPIO(adapter_gpio_config[idx].gpio_num);
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bb_value_t bcm2835gpio_read(void)
|
static bb_value_t bcm2835gpio_read(void)
|
||||||
|
@ -164,6 +176,7 @@ static int bcm2835gpio_write(int tck, int tms, int tdi)
|
||||||
|
|
||||||
GPIO_SET = set;
|
GPIO_SET = set;
|
||||||
GPIO_CLR = clear;
|
GPIO_CLR = clear;
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < jtag_delay; i++)
|
for (unsigned int i = 0; i < jtag_delay; i++)
|
||||||
asm volatile ("");
|
asm volatile ("");
|
||||||
|
@ -184,6 +197,7 @@ static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
|
||||||
|
|
||||||
GPIO_SET = set;
|
GPIO_SET = set;
|
||||||
GPIO_CLR = clear;
|
GPIO_CLR = clear;
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < jtag_delay; i++)
|
for (unsigned int i = 0; i < jtag_delay; i++)
|
||||||
asm volatile ("");
|
asm volatile ("");
|
||||||
|
@ -234,6 +248,7 @@ static void bcm2835_swdio_drive(bool is_output)
|
||||||
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
|
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
|
||||||
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
|
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
|
||||||
}
|
}
|
||||||
|
bcm2835_gpio_synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm2835_swdio_read(void)
|
static int bcm2835_swdio_read(void)
|
||||||
|
|
|
@ -380,8 +380,6 @@ static int bitbang_swd_init(void)
|
||||||
|
|
||||||
static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt)
|
static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("bitbang_swd_exchange");
|
|
||||||
|
|
||||||
if (bitbang_interface->blink) {
|
if (bitbang_interface->blink) {
|
||||||
/* FIXME: we should manage errors */
|
/* FIXME: we should manage errors */
|
||||||
bitbang_interface->blink(1);
|
bitbang_interface->blink(1);
|
||||||
|
@ -412,11 +410,9 @@ static void bitbang_swd_exchange(bool rnw, uint8_t buf[], unsigned int offset, u
|
||||||
|
|
||||||
static int bitbang_swd_switch_seq(enum swd_special_seq seq)
|
static int bitbang_swd_switch_seq(enum swd_special_seq seq)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("bitbang_swd_switch_seq");
|
|
||||||
|
|
||||||
switch (seq) {
|
switch (seq) {
|
||||||
case LINE_RESET:
|
case LINE_RESET:
|
||||||
LOG_DEBUG("SWD line reset");
|
LOG_DEBUG_IO("SWD line reset");
|
||||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len);
|
bitbang_swd_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len);
|
||||||
break;
|
break;
|
||||||
case JTAG_TO_SWD:
|
case JTAG_TO_SWD:
|
||||||
|
@ -459,7 +455,6 @@ static void swd_clear_sticky_errors(void)
|
||||||
|
|
||||||
static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
|
static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("bitbang_swd_read_reg");
|
|
||||||
assert(cmd & SWD_CMD_RNW);
|
assert(cmd & SWD_CMD_RNW);
|
||||||
|
|
||||||
if (queued_retval != ERROR_OK) {
|
if (queued_retval != ERROR_OK) {
|
||||||
|
@ -481,7 +476,7 @@ 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);
|
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);
|
int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1);
|
||||||
|
|
||||||
LOG_DEBUG("%s %s read reg %X = %08"PRIx32,
|
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",
|
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_APNDP ? "AP" : "DP",
|
||||||
(cmd & SWD_CMD_A32) >> 1,
|
(cmd & SWD_CMD_A32) >> 1,
|
||||||
|
@ -510,7 +505,6 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
|
||||||
|
|
||||||
static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
|
static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("bitbang_swd_write_reg");
|
|
||||||
assert(!(cmd & SWD_CMD_RNW));
|
assert(!(cmd & SWD_CMD_RNW));
|
||||||
|
|
||||||
if (queued_retval != ERROR_OK) {
|
if (queued_retval != ERROR_OK) {
|
||||||
|
@ -537,7 +531,7 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
|
||||||
|
|
||||||
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
|
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
|
||||||
|
|
||||||
LOG_DEBUG("%s%s %s write reg %X = %08"PRIx32,
|
LOG_DEBUG_IO("%s%s %s write reg %X = %08" PRIx32,
|
||||||
check_ack ? "" : "ack ignored ",
|
check_ack ? "" : "ack ignored ",
|
||||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
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_APNDP ? "AP" : "DP",
|
||||||
|
@ -562,14 +556,13 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
|
||||||
|
|
||||||
static int bitbang_swd_run_queue(void)
|
static int bitbang_swd_run_queue(void)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("bitbang_swd_run_queue");
|
|
||||||
/* A transaction must be followed by another transaction or at least 8 idle cycles to
|
/* A transaction must be followed by another transaction or at least 8 idle cycles to
|
||||||
* ensure that data is clocked through the AP. */
|
* ensure that data is clocked through the AP. */
|
||||||
bitbang_swd_exchange(true, NULL, 0, 8);
|
bitbang_swd_exchange(true, NULL, 0, 8);
|
||||||
|
|
||||||
int retval = queued_retval;
|
int retval = queued_retval;
|
||||||
queued_retval = ERROR_OK;
|
queued_retval = ERROR_OK;
|
||||||
LOG_DEBUG("SWD queue return value: %02x", retval);
|
LOG_DEBUG_IO("SWD queue return value: %02x", retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -573,6 +573,8 @@ static int cmsis_dap_metacmd_targetsel(uint32_t instance_id)
|
||||||
The purpose of this operation is to select the target
|
The purpose of this operation is to select the target
|
||||||
corresponding to the instance_id that is written */
|
corresponding to the instance_id that is written */
|
||||||
|
|
||||||
|
LOG_DEBUG_IO("DP write reg TARGETSEL %" PRIx32, instance_id);
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
command[idx++] = CMD_DAP_SWD_SEQUENCE;
|
command[idx++] = CMD_DAP_SWD_SEQUENCE;
|
||||||
command[idx++] = 3; /* sequence count */
|
command[idx++] = 3; /* sequence count */
|
||||||
|
@ -658,7 +660,7 @@ static int cmsis_dap_cmd_dap_swo_baudrate(
|
||||||
command[0] = CMD_DAP_SWO_BAUDRATE;
|
command[0] = CMD_DAP_SWO_BAUDRATE;
|
||||||
h_u32_to_le(&command[1], in_baudrate);
|
h_u32_to_le(&command[1], in_baudrate);
|
||||||
|
|
||||||
int retval = cmsis_dap_xfer(cmsis_dap_handle, 4);
|
int retval = cmsis_dap_xfer(cmsis_dap_handle, 5);
|
||||||
uint32_t rvbr = le_to_h_u32(&cmsis_dap_handle->response[1]);
|
uint32_t rvbr = le_to_h_u32(&cmsis_dap_handle->response[1]);
|
||||||
if (retval != ERROR_OK || rvbr == 0) {
|
if (retval != ERROR_OK || rvbr == 0) {
|
||||||
LOG_ERROR("CMSIS-DAP: command CMD_SWO_Baudrate(%u) -> %u failed.", in_baudrate, rvbr);
|
LOG_ERROR("CMSIS-DAP: command CMD_SWO_Baudrate(%u) -> %u failed.", in_baudrate, rvbr);
|
||||||
|
@ -783,7 +785,7 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
|
||||||
uint8_t cmd = transfer->cmd;
|
uint8_t cmd = transfer->cmd;
|
||||||
uint32_t data = transfer->data;
|
uint32_t data = transfer->data;
|
||||||
|
|
||||||
LOG_DEBUG_IO("%s %s reg %x %"PRIx32,
|
LOG_DEBUG_IO("%s %s reg %x %" PRIx32,
|
||||||
cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||||
cmd & SWD_CMD_RNW ? "read" : "write",
|
cmd & SWD_CMD_RNW ? "read" : "write",
|
||||||
(cmd & SWD_CMD_A32) >> 1, data);
|
(cmd & SWD_CMD_A32) >> 1, data);
|
||||||
|
@ -889,7 +891,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
|
||||||
uint32_t tmp = data;
|
uint32_t tmp = data;
|
||||||
idx += 4;
|
idx += 4;
|
||||||
|
|
||||||
LOG_DEBUG_IO("Read result: %"PRIx32, data);
|
LOG_DEBUG_IO("Read result: %" PRIx32, data);
|
||||||
|
|
||||||
/* Imitate posted AP reads */
|
/* Imitate posted AP reads */
|
||||||
if ((transfer->cmd & SWD_CMD_APNDP) ||
|
if ((transfer->cmd & SWD_CMD_APNDP) ||
|
||||||
|
|
|
@ -262,8 +262,10 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p
|
||||||
/* If the interface is reliably identified
|
/* If the interface is reliably identified
|
||||||
* then we need not insist on setting USB class, subclass and protocol
|
* then we need not insist on setting USB class, subclass and protocol
|
||||||
* exactly as the specification requires.
|
* exactly as the specification requires.
|
||||||
|
* Just filter out the well known classes, mainly CDC and MSC.
|
||||||
* At least KitProg3 uses class 0 contrary to the specification */
|
* At least KitProg3 uses class 0 contrary to the specification */
|
||||||
if (intf_identified_reliably) {
|
if (intf_identified_reliably &&
|
||||||
|
(intf_desc->bInterfaceClass == 0 || intf_desc->bInterfaceClass > 0x12)) {
|
||||||
LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8
|
LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8
|
||||||
" subclass %" PRId8 " or protocol %" PRId8,
|
" subclass %" PRId8 " or protocol %" PRId8,
|
||||||
interface_num,
|
interface_num,
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "bitq.h"
|
#include "bitq.h"
|
||||||
#include "libusb_helper.h"
|
#include "libusb_helper.h"
|
||||||
|
|
||||||
#define __packed __attribute__((packed))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Holy Crap, it's protocol documentation, and it's even vendor-provided!
|
Holy Crap, it's protocol documentation, and it's even vendor-provided!
|
||||||
|
|
||||||
|
@ -110,7 +108,7 @@ descriptor.
|
||||||
struct jtag_proto_caps_hdr {
|
struct jtag_proto_caps_hdr {
|
||||||
uint8_t proto_ver; /* Protocol version. Expects JTAG_PROTO_CAPS_VER for now. */
|
uint8_t proto_ver; /* Protocol version. Expects JTAG_PROTO_CAPS_VER for now. */
|
||||||
uint8_t length; /* of this plus any following descriptors */
|
uint8_t length; /* of this plus any following descriptors */
|
||||||
} __packed;
|
} __attribute__((packed));
|
||||||
|
|
||||||
/* start of the descriptor headers */
|
/* start of the descriptor headers */
|
||||||
#define JTAG_BUILTIN_DESCR_START_OFF 0 /* Devices with builtin usb jtag */
|
#define JTAG_BUILTIN_DESCR_START_OFF 0 /* Devices with builtin usb jtag */
|
||||||
|
@ -133,7 +131,7 @@ of caps header to assume this. If no such caps exist, assume a minimum (in) buff
|
||||||
struct jtag_gen_hdr {
|
struct jtag_gen_hdr {
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
} __packed;
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct jtag_proto_caps_speed_apb {
|
struct jtag_proto_caps_speed_apb {
|
||||||
uint8_t type; /* Type, always JTAG_PROTO_CAPS_SPEED_APB_TYPE */
|
uint8_t type; /* Type, always JTAG_PROTO_CAPS_SPEED_APB_TYPE */
|
||||||
|
@ -141,7 +139,7 @@ struct jtag_proto_caps_speed_apb {
|
||||||
uint8_t apb_speed_10khz[2]; /* ABP bus speed, in 10KHz increments. Base speed is half this. */
|
uint8_t apb_speed_10khz[2]; /* ABP bus speed, in 10KHz increments. Base speed is half this. */
|
||||||
uint8_t div_min[2]; /* minimum divisor (to base speed), inclusive */
|
uint8_t div_min[2]; /* minimum divisor (to base speed), inclusive */
|
||||||
uint8_t div_max[2]; /* maximum divisor (to base speed), inclusive */
|
uint8_t div_max[2]; /* maximum divisor (to base speed), inclusive */
|
||||||
} __packed;
|
} __attribute__((packed));
|
||||||
|
|
||||||
#define JTAG_PROTO_CAPS_DATA_LEN 255
|
#define JTAG_PROTO_CAPS_DATA_LEN 255
|
||||||
#define JTAG_PROTO_CAPS_SPEED_APB_TYPE 1
|
#define JTAG_PROTO_CAPS_SPEED_APB_TYPE 1
|
||||||
|
|
|
@ -796,17 +796,12 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag)
|
||||||
|
|
||||||
void opendous_debug_buffer(uint8_t *buffer, int length)
|
void opendous_debug_buffer(uint8_t *buffer, int length)
|
||||||
{
|
{
|
||||||
char line[81];
|
char line[8 + 3 * BYTES_PER_LINE + 1];
|
||||||
char s[4];
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i += BYTES_PER_LINE) {
|
for (int i = 0; i < length; i += BYTES_PER_LINE) {
|
||||||
snprintf(line, 5, "%04x", i);
|
int n = snprintf(line, 9, "%04x", i);
|
||||||
for (j = i; j < i + BYTES_PER_LINE && j < length; j++) {
|
for (int j = i; j < i + BYTES_PER_LINE && j < length; j++)
|
||||||
snprintf(s, 4, " %02x", buffer[j]);
|
n += snprintf(line + n, 4, " %02x", buffer[j]);
|
||||||
strcat(line, s);
|
|
||||||
}
|
|
||||||
LOG_DEBUG("%s", line);
|
LOG_DEBUG("%s", line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1246,7 +1246,7 @@ static const struct command_registration vdebug_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "mem_path",
|
.name = "mem_path",
|
||||||
.handler = &vdebug_set_mem,
|
.handler = &vdebug_set_mem,
|
||||||
.mode = COMMAND_ANY,
|
.mode = COMMAND_CONFIG,
|
||||||
.help = "set the design memory for the code load",
|
.help = "set the design memory for the code load",
|
||||||
.usage = "<path> <base_address> <size>",
|
.usage = "<path> <base_address> <size>",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1354,11 +1354,13 @@ static void xds110_swd_queue_cmd(uint8_t cmd, uint32_t *value)
|
||||||
static void xds110_swd_read_reg(uint8_t cmd, uint32_t *value,
|
static void xds110_swd_read_reg(uint8_t cmd, uint32_t *value,
|
||||||
uint32_t ap_delay_clk)
|
uint32_t ap_delay_clk)
|
||||||
{
|
{
|
||||||
|
assert(cmd & SWD_CMD_RNW);
|
||||||
xds110_swd_queue_cmd(cmd, value);
|
xds110_swd_queue_cmd(cmd, value);
|
||||||
}
|
}
|
||||||
static void xds110_swd_write_reg(uint8_t cmd, uint32_t value,
|
static void xds110_swd_write_reg(uint8_t cmd, uint32_t value,
|
||||||
uint32_t ap_delay_clk)
|
uint32_t ap_delay_clk)
|
||||||
{
|
{
|
||||||
|
assert(!(cmd & SWD_CMD_RNW));
|
||||||
xds110_swd_queue_cmd(cmd, &value);
|
xds110_swd_queue_cmd(cmd, &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,9 +118,6 @@ extern struct adapter_driver linuxgpiod_adapter_driver;
|
||||||
#if BUILD_XLNX_PCIE_XVC == 1
|
#if BUILD_XLNX_PCIE_XVC == 1
|
||||||
extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
|
extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
|
||||||
#endif
|
#endif
|
||||||
#if BUILD_AICE == 1
|
|
||||||
extern struct adapter_driver aice_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_BCM2835GPIO == 1
|
#if BUILD_BCM2835GPIO == 1
|
||||||
extern struct adapter_driver bcm2835gpio_adapter_driver;
|
extern struct adapter_driver bcm2835gpio_adapter_driver;
|
||||||
#endif
|
#endif
|
||||||
|
@ -238,9 +235,6 @@ struct adapter_driver *adapter_drivers[] = {
|
||||||
#if BUILD_XLNX_PCIE_XVC == 1
|
#if BUILD_XLNX_PCIE_XVC == 1
|
||||||
&xlnx_pcie_xvc_adapter_driver,
|
&xlnx_pcie_xvc_adapter_driver,
|
||||||
#endif
|
#endif
|
||||||
#if BUILD_AICE == 1
|
|
||||||
&aice_adapter_driver,
|
|
||||||
#endif
|
|
||||||
#if BUILD_BCM2835GPIO == 1
|
#if BUILD_BCM2835GPIO == 1
|
||||||
&bcm2835gpio_adapter_driver,
|
&bcm2835gpio_adapter_driver,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -865,12 +865,6 @@ proc ft232r_restore_serial args {
|
||||||
eval ft232r restore_serial $args
|
eval ft232r restore_serial $args
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend _telnet_autocomplete_skip "aice serial"
|
|
||||||
proc "aice serial" {args} {
|
|
||||||
echo "DEPRECATED! use 'adapter serial' not 'aice serial'"
|
|
||||||
eval adapter serial $args
|
|
||||||
}
|
|
||||||
|
|
||||||
lappend _telnet_autocomplete_skip cmsis_dap_serial
|
lappend _telnet_autocomplete_skip cmsis_dap_serial
|
||||||
proc cmsis_dap_serial args {
|
proc cmsis_dap_serial args {
|
||||||
echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'"
|
echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'"
|
||||||
|
|
|
@ -230,65 +230,6 @@ static int openocd_register_commands(struct command_context *cmd_ctx)
|
||||||
return register_commands(cmd_ctx, NULL, openocd_command_handlers);
|
return register_commands(cmd_ctx, NULL, openocd_command_handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: to be removed after v0.12.0
|
|
||||||
* workaround for syntax change of "expr" in jimtcl 0.81
|
|
||||||
* replace "expr" with openocd version that prints the deprecated msg
|
|
||||||
*/
|
|
||||||
struct jim_scriptobj {
|
|
||||||
void *token;
|
|
||||||
Jim_Obj *filename_obj;
|
|
||||||
int len;
|
|
||||||
int subst_flags;
|
|
||||||
int in_use;
|
|
||||||
int firstline;
|
|
||||||
int linenr;
|
|
||||||
int missing;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int jim_expr_command(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
|
||||||
{
|
|
||||||
if (argc == 2)
|
|
||||||
return Jim_EvalExpression(interp, argv[1]);
|
|
||||||
|
|
||||||
if (argc > 2) {
|
|
||||||
Jim_Obj *obj = Jim_ConcatObj(interp, argc - 1, argv + 1);
|
|
||||||
Jim_IncrRefCount(obj);
|
|
||||||
const char *s = Jim_String(obj);
|
|
||||||
struct jim_scriptobj *script = Jim_GetIntRepPtr(interp->currentScriptObj);
|
|
||||||
if (interp->currentScriptObj == interp->emptyObj ||
|
|
||||||
strcmp(interp->currentScriptObj->typePtr->name, "script") ||
|
|
||||||
script->subst_flags ||
|
|
||||||
script->filename_obj == interp->emptyObj)
|
|
||||||
LOG_WARNING("DEPRECATED! use 'expr { %s }' not 'expr %s'", s, s);
|
|
||||||
else
|
|
||||||
LOG_WARNING("DEPRECATED! (%s:%d) use 'expr { %s }' not 'expr %s'",
|
|
||||||
Jim_String(script->filename_obj), script->linenr, s, s);
|
|
||||||
int retcode = Jim_EvalExpression(interp, obj);
|
|
||||||
Jim_DecrRefCount(interp, obj);
|
|
||||||
return retcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct command_registration expr_handler[] = {
|
|
||||||
{
|
|
||||||
.name = "expr",
|
|
||||||
.jim_handler = jim_expr_command,
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.help = "",
|
|
||||||
.usage = "",
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
static int workaround_for_jimtcl_expr(struct command_context *cmd_ctx)
|
|
||||||
{
|
|
||||||
return register_commands(cmd_ctx, NULL, expr_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct command_context *global_cmd_ctx;
|
struct command_context *global_cmd_ctx;
|
||||||
|
|
||||||
static struct command_context *setup_command_handler(Jim_Interp *interp)
|
static struct command_context *setup_command_handler(Jim_Interp *interp)
|
||||||
|
@ -301,7 +242,6 @@ static struct command_context *setup_command_handler(Jim_Interp *interp)
|
||||||
/* register subsystem commands */
|
/* register subsystem commands */
|
||||||
typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value);
|
typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value);
|
||||||
static const command_registrant_t command_registrants[] = {
|
static const command_registrant_t command_registrants[] = {
|
||||||
&workaround_for_jimtcl_expr,
|
|
||||||
&openocd_register_commands,
|
&openocd_register_commands,
|
||||||
&server_register_commands,
|
&server_register_commands,
|
||||||
&gdb_register_commands,
|
&gdb_register_commands,
|
||||||
|
|
|
@ -157,6 +157,8 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename)
|
||||||
virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
|
virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
|
||||||
jtag_execute_queue();
|
jtag_execute_queue();
|
||||||
|
|
||||||
|
xilinx_free_bit_file(&bit_file);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +175,7 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command)
|
||||||
device = get_pld_device_by_num(dev_id);
|
device = get_pld_device_by_num(dev_id);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
|
command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
|
||||||
return ERROR_OK;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtex2_read_stat(device, &status);
|
virtex2_read_stat(device, &status);
|
||||||
|
@ -195,7 +197,7 @@ PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command)
|
||||||
tap = jtag_tap_by_string(CMD_ARGV[1]);
|
tap = jtag_tap_by_string(CMD_ARGV[1]);
|
||||||
if (!tap) {
|
if (!tap) {
|
||||||
command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
|
command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
|
||||||
return ERROR_OK;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtex2_info = malloc(sizeof(struct virtex2_pld_device));
|
virtex2_info = malloc(sizeof(struct virtex2_pld_device));
|
||||||
|
|
|
@ -87,26 +87,48 @@ int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename)
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bit_file->source_file = NULL;
|
||||||
|
bit_file->part_name = NULL;
|
||||||
|
bit_file->date = NULL;
|
||||||
|
bit_file->time = NULL;
|
||||||
|
bit_file->data = NULL;
|
||||||
|
|
||||||
read_count = fread(bit_file->unknown_header, 1, 13, input_file);
|
read_count = fread(bit_file->unknown_header, 1, 13, input_file);
|
||||||
if (read_count != 13) {
|
if (read_count != 13) {
|
||||||
LOG_ERROR("couldn't read unknown_header from file '%s'", filename);
|
LOG_ERROR("couldn't read unknown_header from file '%s'", filename);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK)
|
if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) {
|
||||||
|
xilinx_free_bit_file(bit_file);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK)
|
if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) {
|
||||||
|
xilinx_free_bit_file(bit_file);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK)
|
if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) {
|
||||||
|
xilinx_free_bit_file(bit_file);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK)
|
if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) {
|
||||||
|
xilinx_free_bit_file(bit_file);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK)
|
if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) {
|
||||||
|
xilinx_free_bit_file(bit_file);
|
||||||
|
fclose(input_file);
|
||||||
return ERROR_PLD_FILE_LOAD_FAILED;
|
return ERROR_PLD_FILE_LOAD_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name,
|
LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name,
|
||||||
bit_file->date, bit_file->time, bit_file->length);
|
bit_file->date, bit_file->time, bit_file->length);
|
||||||
|
@ -115,3 +137,12 @@ int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename)
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xilinx_free_bit_file(struct xilinx_bit_file *bit_file)
|
||||||
|
{
|
||||||
|
free(bit_file->source_file);
|
||||||
|
free(bit_file->part_name);
|
||||||
|
free(bit_file->date);
|
||||||
|
free(bit_file->time);
|
||||||
|
free(bit_file->data);
|
||||||
|
}
|
||||||
|
|
|
@ -22,4 +22,6 @@ struct xilinx_bit_file {
|
||||||
|
|
||||||
int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename);
|
int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename);
|
||||||
|
|
||||||
|
void xilinx_free_bit_file(struct xilinx_bit_file *bit_file);
|
||||||
|
|
||||||
#endif /* OPENOCD_PLD_XILINX_BIT_H */
|
#endif /* OPENOCD_PLD_XILINX_BIT_H */
|
||||||
|
|
|
@ -112,13 +112,6 @@ static int cortex_m_stacking(struct rtos *rtos, const struct rtos_register_stack
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nds32_stacking(struct rtos *rtos, const struct rtos_register_stacking **stacking,
|
|
||||||
target_addr_t stack_ptr)
|
|
||||||
{
|
|
||||||
*stacking = &rtos_standard_nds32_n1068_stacking;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* take 4 bytes (32 bits) as the default size,
|
/* take 4 bytes (32 bits) as the default size,
|
||||||
* which is suitable for most 32-bit targets and
|
* which is suitable for most 32-bit targets and
|
||||||
* configuration of configUSE_16_BIT_TICKS = 0. */
|
* configuration of configUSE_16_BIT_TICKS = 0. */
|
||||||
|
@ -226,10 +219,6 @@ static const struct freertos_params freertos_params_list[] = {
|
||||||
.stacking = cortex_m_stacking
|
.stacking = cortex_m_stacking
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.target_name = "nds32_v3",
|
|
||||||
.stacking = nds32_stacking,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.target_name = "riscv",
|
.target_name = "riscv",
|
||||||
.stacking = riscv_stacking,
|
.stacking = riscv_stacking,
|
||||||
.commands = riscv_commands,
|
.commands = riscv_commands,
|
||||||
|
|
|
@ -320,6 +320,12 @@ static int threadx_update_threads(struct rtos *rtos)
|
||||||
rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
|
rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
|
||||||
strcpy(rtos->thread_details->thread_name_str, tmp_str);
|
strcpy(rtos->thread_details->thread_name_str, tmp_str);
|
||||||
|
|
||||||
|
/* If we just invented thread 1 to represent the current execution, we
|
||||||
|
* need to make sure the RTOS object also claims it's the current thread
|
||||||
|
* so that threadx_get_thread_reg_list() doesn't attempt to read a
|
||||||
|
* thread control block at 0x00000001. */
|
||||||
|
rtos->current_thread = 1;
|
||||||
|
|
||||||
if (thread_list_size == 0) {
|
if (thread_list_size == 0) {
|
||||||
rtos->thread_count = 1;
|
rtos->thread_count = 1;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -364,6 +370,10 @@ static int threadx_update_threads(struct rtos *rtos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the thread name */
|
/* Read the thread name */
|
||||||
|
tmp_str[0] = '\x00';
|
||||||
|
|
||||||
|
/* Check if thread has a valid name */
|
||||||
|
if (name_ptr != 0) {
|
||||||
retval =
|
retval =
|
||||||
target_read_buffer(rtos->target,
|
target_read_buffer(rtos->target,
|
||||||
name_ptr,
|
name_ptr,
|
||||||
|
@ -373,7 +383,8 @@ static int threadx_update_threads(struct rtos *rtos)
|
||||||
LOG_ERROR("Error reading thread name from ThreadX target");
|
LOG_ERROR("Error reading thread name from ThreadX target");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
|
tmp_str[THREADX_THREAD_NAME_STR_SIZE - 1] = '\x00';
|
||||||
|
}
|
||||||
|
|
||||||
if (tmp_str[0] == '\x00')
|
if (tmp_str[0] == '\x00')
|
||||||
strcpy(tmp_str, "No Name");
|
strcpy(tmp_str, "No Name");
|
||||||
|
|
1005
src/rtos/eCos.c
1005
src/rtos/eCos.c
File diff suppressed because it is too large
Load Diff
|
@ -87,6 +87,7 @@ static int hwthread_update_threads(struct rtos *rtos)
|
||||||
struct target_list *head;
|
struct target_list *head;
|
||||||
struct target *target;
|
struct target *target;
|
||||||
int64_t current_thread = 0;
|
int64_t current_thread = 0;
|
||||||
|
int64_t current_threadid = rtos->current_threadid; /* thread selected by GDB */
|
||||||
enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
|
enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
|
||||||
|
|
||||||
if (!rtos)
|
if (!rtos)
|
||||||
|
@ -108,10 +109,14 @@ static int hwthread_update_threads(struct rtos *rtos)
|
||||||
} else
|
} else
|
||||||
thread_list_size = 1;
|
thread_list_size = 1;
|
||||||
|
|
||||||
/* Wipe out previous thread details if any, but preserve threadid. */
|
/* restore the threadid which is currently selected by GDB
|
||||||
int64_t current_threadid = rtos->current_threadid;
|
* because rtos_free_threadlist() wipes out it
|
||||||
rtos_free_threadlist(rtos);
|
* (GDB thread id is 1-based indexing) */
|
||||||
|
if (current_threadid <= thread_list_size)
|
||||||
rtos->current_threadid = current_threadid;
|
rtos->current_threadid = current_threadid;
|
||||||
|
else
|
||||||
|
LOG_WARNING("SMP node change, disconnect GDB from core/thread %" PRId64,
|
||||||
|
current_threadid);
|
||||||
|
|
||||||
/* create space for new thread details */
|
/* create space for new thread details */
|
||||||
rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
|
rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
|
||||||
|
@ -264,10 +269,19 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
|
||||||
for (int i = 0; i < reg_list_size; i++) {
|
for (int i = 0; i < reg_list_size; i++) {
|
||||||
if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
|
if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
|
||||||
continue;
|
continue;
|
||||||
(*rtos_reg_list)[j].number = (*reg_list)[i].number;
|
if (!reg_list[i]->valid) {
|
||||||
(*rtos_reg_list)[j].size = (*reg_list)[i].size;
|
retval = reg_list[i]->type->get(reg_list[i]);
|
||||||
memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value,
|
if (retval != ERROR_OK) {
|
||||||
((*reg_list)[i].size + 7) / 8);
|
LOG_ERROR("Couldn't get register %s.", reg_list[i]->name);
|
||||||
|
free(reg_list);
|
||||||
|
free(*rtos_reg_list);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*rtos_reg_list)[j].number = reg_list[i]->number;
|
||||||
|
(*rtos_reg_list)[j].size = reg_list[i]->size;
|
||||||
|
memcpy((*rtos_reg_list)[j].value, reg_list[i]->value,
|
||||||
|
DIV_ROUND_UP(reg_list[i]->size, 8));
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
free(reg_list);
|
free(reg_list);
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
#include "rtos_standard_stackings.h"
|
#include "rtos_standard_stackings.h"
|
||||||
#include "target/armv7m.h"
|
#include "target/armv7m.h"
|
||||||
|
|
||||||
|
/* For Cortex-M eCos applications the actual thread context register layout can
|
||||||
|
* be different between active threads of an application depending on whether
|
||||||
|
* the FPU is in use, configured for lazy FPU context saving, etc. */
|
||||||
|
|
||||||
|
/* Default fixed thread register context description used for older eCos
|
||||||
|
* application builds without the necessary symbolic information describing the
|
||||||
|
* actual configuration-dependent offsets. */
|
||||||
static const struct stack_register_offset rtos_ecos_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
|
static const struct stack_register_offset rtos_ecos_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
|
||||||
{ ARMV7M_R0, 0x0c, 32 }, /* r0 */
|
{ ARMV7M_R0, 0x0c, 32 }, /* r0 */
|
||||||
{ ARMV7M_R1, 0x10, 32 }, /* r1 */
|
{ ARMV7M_R1, 0x10, 32 }, /* r1 */
|
||||||
|
|
|
@ -103,45 +103,6 @@ static const struct stack_register_offset rtos_standard_cortex_r4_stack_offsets[
|
||||||
{ 26, 0x04, 32 }, /* CSPR */
|
{ 26, 0x04, 32 }, /* CSPR */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct stack_register_offset rtos_standard_nds32_n1068_stack_offsets[] = {
|
|
||||||
{ 0, 0x88, 32 }, /* R0 */
|
|
||||||
{ 1, 0x8C, 32 }, /* R1 */
|
|
||||||
{ 2, 0x14, 32 }, /* R2 */
|
|
||||||
{ 3, 0x18, 32 }, /* R3 */
|
|
||||||
{ 4, 0x1C, 32 }, /* R4 */
|
|
||||||
{ 5, 0x20, 32 }, /* R5 */
|
|
||||||
{ 6, 0x24, 32 }, /* R6 */
|
|
||||||
{ 7, 0x28, 32 }, /* R7 */
|
|
||||||
{ 8, 0x2C, 32 }, /* R8 */
|
|
||||||
{ 9, 0x30, 32 }, /* R9 */
|
|
||||||
{ 10, 0x34, 32 }, /* R10 */
|
|
||||||
{ 11, 0x38, 32 }, /* R11 */
|
|
||||||
{ 12, 0x3C, 32 }, /* R12 */
|
|
||||||
{ 13, 0x40, 32 }, /* R13 */
|
|
||||||
{ 14, 0x44, 32 }, /* R14 */
|
|
||||||
{ 15, 0x48, 32 }, /* R15 */
|
|
||||||
{ 16, 0x4C, 32 }, /* R16 */
|
|
||||||
{ 17, 0x50, 32 }, /* R17 */
|
|
||||||
{ 18, 0x54, 32 }, /* R18 */
|
|
||||||
{ 19, 0x58, 32 }, /* R19 */
|
|
||||||
{ 20, 0x5C, 32 }, /* R20 */
|
|
||||||
{ 21, 0x60, 32 }, /* R21 */
|
|
||||||
{ 22, 0x64, 32 }, /* R22 */
|
|
||||||
{ 23, 0x68, 32 }, /* R23 */
|
|
||||||
{ 24, 0x6C, 32 }, /* R24 */
|
|
||||||
{ 25, 0x70, 32 }, /* R25 */
|
|
||||||
{ 26, 0x74, 32 }, /* R26 */
|
|
||||||
{ 27, 0x78, 32 }, /* R27 */
|
|
||||||
{ 28, 0x7C, 32 }, /* R28 */
|
|
||||||
{ 29, 0x80, 32 }, /* R29 */
|
|
||||||
{ 30, 0x84, 32 }, /* R30 (LP) */
|
|
||||||
{ 31, 0x00, 32 }, /* R31 (SP) */
|
|
||||||
{ 32, 0x04, 32 }, /* PSW */
|
|
||||||
{ 33, 0x08, 32 }, /* IPC */
|
|
||||||
{ 34, 0x0C, 32 }, /* IPSW */
|
|
||||||
{ 35, 0x10, 32 }, /* IFC_LP */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct stack_register_offset rtos_metal_rv32_stack_offsets[] = {
|
static const struct stack_register_offset rtos_metal_rv32_stack_offsets[] = {
|
||||||
/* zero isn't on the stack. By making its offset -1 we leave the value at 0
|
/* zero isn't on the stack. By making its offset -1 we leave the value at 0
|
||||||
* inside rtos_generic_stack_read(). */
|
* inside rtos_generic_stack_read(). */
|
||||||
|
@ -436,14 +397,6 @@ const struct rtos_register_stacking rtos_standard_cortex_r4_stacking = {
|
||||||
.register_offsets = rtos_standard_cortex_r4_stack_offsets
|
.register_offsets = rtos_standard_cortex_r4_stack_offsets
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct rtos_register_stacking rtos_standard_nds32_n1068_stacking = {
|
|
||||||
.stack_registers_size = 0x90,
|
|
||||||
.stack_growth_direction = -1,
|
|
||||||
.num_output_registers = 32,
|
|
||||||
.calculate_process_stack = rtos_generic_stack_align8,
|
|
||||||
.register_offsets = rtos_standard_nds32_n1068_stack_offsets
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct rtos_register_stacking rtos_metal_rv32_stacking = {
|
const struct rtos_register_stacking rtos_metal_rv32_stacking = {
|
||||||
.stack_registers_size = (32 + 2) * 4,
|
.stack_registers_size = (32 + 2) * 4,
|
||||||
.stack_growth_direction = -1,
|
.stack_growth_direction = -1,
|
||||||
|
|
|
@ -18,7 +18,6 @@ extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking;
|
||||||
extern const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking;
|
extern const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking;
|
||||||
extern const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking;
|
extern const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking;
|
||||||
extern const struct rtos_register_stacking rtos_standard_cortex_r4_stacking;
|
extern const struct rtos_register_stacking rtos_standard_cortex_r4_stacking;
|
||||||
extern const struct rtos_register_stacking rtos_standard_nds32_n1068_stacking;
|
|
||||||
target_addr_t rtos_generic_stack_align8(struct target *target,
|
target_addr_t rtos_generic_stack_align8(struct target *target,
|
||||||
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
|
const uint8_t *stack_data, const struct rtos_register_stacking *stacking,
|
||||||
target_addr_t stack_ptr);
|
target_addr_t stack_ptr);
|
||||||
|
|
|
@ -19,7 +19,6 @@ noinst_LTLIBRARIES += %D%/libtarget.la
|
||||||
$(ARM_MISC_SRC) \
|
$(ARM_MISC_SRC) \
|
||||||
$(AVR32_SRC) \
|
$(AVR32_SRC) \
|
||||||
$(MIPS32_SRC) \
|
$(MIPS32_SRC) \
|
||||||
$(NDS32_SRC) \
|
|
||||||
$(STM8_SRC) \
|
$(STM8_SRC) \
|
||||||
$(INTEL_IA32_SRC) \
|
$(INTEL_IA32_SRC) \
|
||||||
$(ESIRISC_SRC) \
|
$(ESIRISC_SRC) \
|
||||||
|
@ -134,18 +133,6 @@ MIPS64_SRC = \
|
||||||
%D%/trace.c \
|
%D%/trace.c \
|
||||||
%D%/mips_ejtag.c
|
%D%/mips_ejtag.c
|
||||||
|
|
||||||
NDS32_SRC = \
|
|
||||||
%D%/nds32.c \
|
|
||||||
%D%/nds32_reg.c \
|
|
||||||
%D%/nds32_cmd.c \
|
|
||||||
%D%/nds32_disassembler.c \
|
|
||||||
%D%/nds32_tlb.c \
|
|
||||||
%D%/nds32_v2.c \
|
|
||||||
%D%/nds32_v3_common.c \
|
|
||||||
%D%/nds32_v3.c \
|
|
||||||
%D%/nds32_v3m.c \
|
|
||||||
%D%/nds32_aice.c
|
|
||||||
|
|
||||||
STM8_SRC = \
|
STM8_SRC = \
|
||||||
%D%/stm8.c
|
%D%/stm8.c
|
||||||
|
|
||||||
|
@ -235,18 +222,6 @@ ARC_SRC = \
|
||||||
%D%/avr32_jtag.h \
|
%D%/avr32_jtag.h \
|
||||||
%D%/avr32_mem.h \
|
%D%/avr32_mem.h \
|
||||||
%D%/avr32_regs.h \
|
%D%/avr32_regs.h \
|
||||||
%D%/nds32.h \
|
|
||||||
%D%/nds32_cmd.h \
|
|
||||||
%D%/nds32_disassembler.h \
|
|
||||||
%D%/nds32_edm.h \
|
|
||||||
%D%/nds32_insn.h \
|
|
||||||
%D%/nds32_reg.h \
|
|
||||||
%D%/nds32_tlb.h \
|
|
||||||
%D%/nds32_v2.h \
|
|
||||||
%D%/nds32_v3_common.h \
|
|
||||||
%D%/nds32_v3.h \
|
|
||||||
%D%/nds32_v3m.h \
|
|
||||||
%D%/nds32_aice.h \
|
|
||||||
%D%/semihosting_common.h \
|
%D%/semihosting_common.h \
|
||||||
%D%/stm8.h \
|
%D%/stm8.h \
|
||||||
%D%/lakemont.h \
|
%D%/lakemont.h \
|
||||||
|
|
|
@ -2546,11 +2546,7 @@ static int aarch64_examine_first(struct target *target)
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (armv8->debug_ap) {
|
if (!armv8->debug_ap) {
|
||||||
dap_put_ap(armv8->debug_ap);
|
|
||||||
armv8->debug_ap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) {
|
if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) {
|
||||||
/* Search for the APB-AB */
|
/* Search for the APB-AB */
|
||||||
retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap);
|
retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap);
|
||||||
|
@ -2565,6 +2561,7 @@ static int aarch64_examine_first(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retval = mem_ap_init(armv8->debug_ap);
|
retval = mem_ap_init(armv8->debug_ap);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
|
|
@ -177,6 +177,19 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr
|
||||||
assert(dap_is_multidrop(dap));
|
assert(dap_is_multidrop(dap));
|
||||||
|
|
||||||
swd_send_sequence(dap, LINE_RESET);
|
swd_send_sequence(dap, LINE_RESET);
|
||||||
|
/* From ARM IHI 0074C ADIv6.0, chapter B4.3.3 "Connection and line reset
|
||||||
|
* sequence":
|
||||||
|
* - line reset sets DP_SELECT_DPBANK to zero;
|
||||||
|
* - read of DP_DPIDR takes the connection out of reset;
|
||||||
|
* - write of DP_TARGETSEL keeps the connection in reset;
|
||||||
|
* - other accesses return protocol error (SWDIO not driven by target).
|
||||||
|
*
|
||||||
|
* Read DP_DPIDR to get out of reset. Initialize dap->select to zero to
|
||||||
|
* skip the write to DP_SELECT, avoiding the protocol error. Set again
|
||||||
|
* dap->select to DP_SELECT_INVALID because the rest of the register is
|
||||||
|
* unknown after line reset.
|
||||||
|
*/
|
||||||
|
dap->select = 0;
|
||||||
|
|
||||||
retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel);
|
retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -196,6 +209,8 @@ static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dap->select = DP_SELECT_INVALID;
|
||||||
|
|
||||||
retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr);
|
retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -257,6 +272,8 @@ static int swd_multidrop_select(struct adiv5_dap *dap)
|
||||||
|
|
||||||
LOG_DEBUG("Failed to select multidrop %s, retrying...",
|
LOG_DEBUG("Failed to select multidrop %s, retrying...",
|
||||||
adiv5_dap_name(dap));
|
adiv5_dap_name(dap));
|
||||||
|
/* we going to retry localy, do not ask for full reconnect */
|
||||||
|
dap->do_reconnect = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -342,6 +359,7 @@ static int swd_connect_single(struct adiv5_dap *dap)
|
||||||
|
|
||||||
dap->switch_through_dormant = !dap->switch_through_dormant;
|
dap->switch_through_dormant = !dap->switch_through_dormant;
|
||||||
} while (timeval_ms() < timeout);
|
} while (timeval_ms() < timeout);
|
||||||
|
|
||||||
dap->select = DP_SELECT_INVALID;
|
dap->select = DP_SELECT_INVALID;
|
||||||
|
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
|
|
@ -113,7 +113,7 @@ static int mem_ap_setup_tar(struct adiv5_ap *ap, target_addr_t tar)
|
||||||
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR(ap->dap), (uint32_t)(tar & 0xffffffffUL));
|
int retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR(ap->dap), (uint32_t)(tar & 0xffffffffUL));
|
||||||
if (retval == ERROR_OK && is_64bit_ap(ap)) {
|
if (retval == ERROR_OK && is_64bit_ap(ap)) {
|
||||||
/* See if bits 63:32 of tar is different from last setting */
|
/* See if bits 63:32 of tar is different from last setting */
|
||||||
if ((ap->tar_value >> 32) != (tar >> 32))
|
if (!ap->tar_valid || (ap->tar_value >> 32) != (tar >> 32))
|
||||||
retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR64(ap->dap), (uint32_t)(tar >> 32));
|
retval = dap_queue_ap_write(ap, MEM_AP_REG_TAR64(ap->dap), (uint32_t)(tar >> 32));
|
||||||
}
|
}
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
|
|
@ -116,27 +116,27 @@ static const struct {
|
||||||
{ 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" },
|
||||||
{ 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" },
|
||||||
|
|
||||||
/* ARMv8-M specific registers */
|
/* ARMv8-M security extension (TrustZone) specific registers */
|
||||||
{ ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "v8-m.sp" },
|
{ ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" },
|
||||||
|
|
||||||
{ 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 },
|
||||||
{ ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
|
|
||||||
{ 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 },
|
||||||
{ ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
{ ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" },
|
{ ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" },
|
||||||
|
|
||||||
/* 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" },
|
||||||
|
@ -182,8 +182,11 @@ int armv7m_restore_context(struct target *target)
|
||||||
for (i = cache->num_regs - 1; i >= 0; i--) {
|
for (i = cache->num_regs - 1; i >= 0; i--) {
|
||||||
struct reg *r = &cache->reg_list[i];
|
struct reg *r = &cache->reg_list[i];
|
||||||
|
|
||||||
if (r->exist && r->dirty)
|
if (r->exist && r->dirty) {
|
||||||
armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value);
|
int retval = armv7m->arm.write_core_reg(target, r, i, ARM_MODE_ANY, r->value);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -528,11 +531,17 @@ int armv7m_start_algorithm(struct target *target,
|
||||||
|
|
||||||
/* Store all non-debug execution registers to armv7m_algorithm_info context */
|
/* Store all non-debug execution registers to armv7m_algorithm_info context */
|
||||||
for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
|
for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) {
|
||||||
|
struct reg *reg = &armv7m->arm.core_cache->reg_list[i];
|
||||||
|
if (!reg->exist)
|
||||||
|
continue;
|
||||||
|
|
||||||
armv7m_algorithm_info->context[i] = buf_get_u32(
|
if (!reg->valid)
|
||||||
armv7m->arm.core_cache->reg_list[i].value,
|
armv7m_get_core_reg(reg);
|
||||||
0,
|
|
||||||
32);
|
if (!reg->valid)
|
||||||
|
LOG_TARGET_WARNING(target, "Storing invalid register %s", reg->name);
|
||||||
|
|
||||||
|
armv7m_algorithm_info->context[i] = buf_get_u32(reg->value, 0, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_mem_params; i++) {
|
for (int i = 0; i < num_mem_params; i++) {
|
||||||
|
@ -685,16 +694,19 @@ int armv7m_wait_algorithm(struct target *target,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
|
for (int i = armv7m->arm.core_cache->num_regs - 1; i >= 0; i--) {
|
||||||
|
struct reg *reg = &armv7m->arm.core_cache->reg_list[i];
|
||||||
|
if (!reg->exist)
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t regvalue;
|
uint32_t regvalue;
|
||||||
regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32);
|
regvalue = buf_get_u32(reg->value, 0, 32);
|
||||||
if (regvalue != armv7m_algorithm_info->context[i]) {
|
if (regvalue != armv7m_algorithm_info->context[i]) {
|
||||||
LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
|
LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32,
|
||||||
armv7m->arm.core_cache->reg_list[i].name,
|
reg->name, armv7m_algorithm_info->context[i]);
|
||||||
armv7m_algorithm_info->context[i]);
|
buf_set_u32(reg->value,
|
||||||
buf_set_u32(armv7m->arm.core_cache->reg_list[i].value,
|
|
||||||
0, 32, armv7m_algorithm_info->context[i]);
|
0, 32, armv7m_algorithm_info->context[i]);
|
||||||
armv7m->arm.core_cache->reg_list[i].valid = true;
|
reg->valid = true;
|
||||||
armv7m->arm.core_cache->reg_list[i].dirty = true;
|
reg->dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,8 +738,9 @@ int armv7m_arch_state(struct target *target)
|
||||||
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
||||||
sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
|
sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
|
||||||
|
|
||||||
LOG_USER("target halted due to %s, current mode: %s %s\n"
|
LOG_USER("[%s] halted due to %s, current mode: %s %s\n"
|
||||||
"xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
|
"xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
|
||||||
|
target_name(target),
|
||||||
debug_reason_name(target),
|
debug_reason_name(target),
|
||||||
arm_mode_name(arm->core_mode),
|
arm_mode_name(arm->core_mode),
|
||||||
armv7m_exception_string(armv7m->exception_number),
|
armv7m_exception_string(armv7m->exception_number),
|
||||||
|
|
|
@ -114,6 +114,166 @@ const char *armv8_mode_name(unsigned psr_mode)
|
||||||
return "UNRECOGNIZED";
|
return "UNRECOGNIZED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t armv8_pa_size(uint32_t ps)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
switch (ps) {
|
||||||
|
case 0:
|
||||||
|
ret = 32;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ret = 36;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ret = 40;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ret = 42;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
ret = 44;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
ret = 48;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_INFO("Unknown physical address size");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target)
|
||||||
|
{
|
||||||
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
|
struct arm_dpm *dpm = armv8->arm.dpm;
|
||||||
|
uint32_t ttbcr, ttbcr_n;
|
||||||
|
int retval = dpm->prepare(dpm);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
/* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
|
||||||
|
retval = dpm->instr_read_data_r0(dpm,
|
||||||
|
ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
|
||||||
|
&ttbcr);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
LOG_DEBUG("ttbcr %" PRIx32, ttbcr);
|
||||||
|
|
||||||
|
ttbcr_n = ttbcr & 0x7;
|
||||||
|
armv8->armv8_mmu.ttbcr = ttbcr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
|
||||||
|
* document # ARM DDI 0406C
|
||||||
|
*/
|
||||||
|
armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n;
|
||||||
|
armv8->armv8_mmu.ttbr_range[1] = 0xffffffff;
|
||||||
|
armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n);
|
||||||
|
armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14;
|
||||||
|
|
||||||
|
LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32,
|
||||||
|
(ttbcr_n != 0) ? "used" : "not used",
|
||||||
|
armv8->armv8_mmu.ttbr_mask[0],
|
||||||
|
armv8->armv8_mmu.ttbr_mask[1]);
|
||||||
|
|
||||||
|
done:
|
||||||
|
dpm->finish(dpm);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int armv8_read_ttbcr(struct target *target)
|
||||||
|
{
|
||||||
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
|
struct arm_dpm *dpm = armv8->arm.dpm;
|
||||||
|
struct arm *arm = &armv8->arm;
|
||||||
|
uint32_t ttbcr;
|
||||||
|
uint64_t ttbcr_64;
|
||||||
|
|
||||||
|
int retval = dpm->prepare(dpm);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* clear ttrr1_used and ttbr0_mask */
|
||||||
|
memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used));
|
||||||
|
memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask));
|
||||||
|
|
||||||
|
switch (armv8_curel_from_core_mode(arm->core_mode)) {
|
||||||
|
case SYSTEM_CUREL_EL3:
|
||||||
|
retval = dpm->instr_read_data_r0(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TCR_EL3, 0),
|
||||||
|
&ttbcr);
|
||||||
|
retval += dpm->instr_read_data_r0_64(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TTBR0_EL3, 0),
|
||||||
|
&armv8->ttbr_base);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
armv8->va_size = 64 - (ttbcr & 0x3F);
|
||||||
|
armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
|
||||||
|
armv8->page_size = (ttbcr >> 14) & 3;
|
||||||
|
break;
|
||||||
|
case SYSTEM_CUREL_EL2:
|
||||||
|
retval = dpm->instr_read_data_r0(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TCR_EL2, 0),
|
||||||
|
&ttbcr);
|
||||||
|
retval += dpm->instr_read_data_r0_64(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TTBR0_EL2, 0),
|
||||||
|
&armv8->ttbr_base);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
armv8->va_size = 64 - (ttbcr & 0x3F);
|
||||||
|
armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
|
||||||
|
armv8->page_size = (ttbcr >> 14) & 3;
|
||||||
|
break;
|
||||||
|
case SYSTEM_CUREL_EL0:
|
||||||
|
armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
|
||||||
|
/* fall through */
|
||||||
|
case SYSTEM_CUREL_EL1:
|
||||||
|
retval = dpm->instr_read_data_r0_64(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TCR_EL1, 0),
|
||||||
|
&ttbcr_64);
|
||||||
|
armv8->va_size = 64 - (ttbcr_64 & 0x3F);
|
||||||
|
armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7);
|
||||||
|
armv8->page_size = (ttbcr_64 >> 14) & 3;
|
||||||
|
armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0;
|
||||||
|
armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF;
|
||||||
|
retval += dpm->instr_read_data_r0_64(dpm,
|
||||||
|
ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0),
|
||||||
|
&armv8->ttbr_base);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("unknown core state");
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (armv8->armv8_mmu.ttbr1_used == 1)
|
||||||
|
LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask));
|
||||||
|
|
||||||
|
done:
|
||||||
|
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
||||||
|
dpm->finish(dpm);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask)
|
||||||
|
{
|
||||||
|
struct arm *arm = &armv8->arm;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
if (armv8->va_size == 0)
|
||||||
|
retval = armv8_read_ttbcr(arm->target);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
*mask = ~(((uint64_t)1 << armv8->va_size) - 1);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
|
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
|
||||||
{
|
{
|
||||||
struct arm_dpm *dpm = &armv8->dpm;
|
struct arm_dpm *dpm = &armv8->dpm;
|
||||||
|
@ -191,6 +351,10 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
|
||||||
ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value);
|
ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value);
|
||||||
value_64 = value;
|
value_64 = value;
|
||||||
break;
|
break;
|
||||||
|
case ARMV8_PAUTH_CMASK:
|
||||||
|
case ARMV8_PAUTH_DMASK:
|
||||||
|
retval = armv8_get_pauth_mask(armv8, &value_64);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
retval = ERROR_FAIL;
|
retval = ERROR_FAIL;
|
||||||
break;
|
break;
|
||||||
|
@ -772,152 +936,6 @@ static __attribute__((unused)) void armv8_show_fault_registers(struct target *ta
|
||||||
armv8_show_fault_registers32(armv8);
|
armv8_show_fault_registers32(armv8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t armv8_pa_size(uint32_t ps)
|
|
||||||
{
|
|
||||||
uint8_t ret = 0;
|
|
||||||
switch (ps) {
|
|
||||||
case 0:
|
|
||||||
ret = 32;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ret = 36;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ret = 40;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
ret = 42;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
ret = 44;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
ret = 48;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_INFO("Unknown physical address size");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target)
|
|
||||||
{
|
|
||||||
struct armv8_common *armv8 = target_to_armv8(target);
|
|
||||||
struct arm_dpm *dpm = armv8->arm.dpm;
|
|
||||||
uint32_t ttbcr, ttbcr_n;
|
|
||||||
int retval = dpm->prepare(dpm);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
/* MRC p15,0,<Rt>,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/
|
|
||||||
retval = dpm->instr_read_data_r0(dpm,
|
|
||||||
ARMV4_5_MRC(15, 0, 0, 2, 0, 2),
|
|
||||||
&ttbcr);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
LOG_DEBUG("ttbcr %" PRIx32, ttbcr);
|
|
||||||
|
|
||||||
ttbcr_n = ttbcr & 0x7;
|
|
||||||
armv8->armv8_mmu.ttbcr = ttbcr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ARM Architecture Reference Manual (ARMv7-A and ARMv7-R edition),
|
|
||||||
* document # ARM DDI 0406C
|
|
||||||
*/
|
|
||||||
armv8->armv8_mmu.ttbr_range[0] = 0xffffffff >> ttbcr_n;
|
|
||||||
armv8->armv8_mmu.ttbr_range[1] = 0xffffffff;
|
|
||||||
armv8->armv8_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n);
|
|
||||||
armv8->armv8_mmu.ttbr_mask[1] = 0xffffffff << 14;
|
|
||||||
|
|
||||||
LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32,
|
|
||||||
(ttbcr_n != 0) ? "used" : "not used",
|
|
||||||
armv8->armv8_mmu.ttbr_mask[0],
|
|
||||||
armv8->armv8_mmu.ttbr_mask[1]);
|
|
||||||
|
|
||||||
done:
|
|
||||||
dpm->finish(dpm);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __attribute__((unused)) int armv8_read_ttbcr(struct target *target)
|
|
||||||
{
|
|
||||||
struct armv8_common *armv8 = target_to_armv8(target);
|
|
||||||
struct arm_dpm *dpm = armv8->arm.dpm;
|
|
||||||
struct arm *arm = &armv8->arm;
|
|
||||||
uint32_t ttbcr;
|
|
||||||
uint64_t ttbcr_64;
|
|
||||||
|
|
||||||
int retval = dpm->prepare(dpm);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* clear ttrr1_used and ttbr0_mask */
|
|
||||||
memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used));
|
|
||||||
memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask));
|
|
||||||
|
|
||||||
switch (armv8_curel_from_core_mode(arm->core_mode)) {
|
|
||||||
case SYSTEM_CUREL_EL3:
|
|
||||||
retval = dpm->instr_read_data_r0(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TCR_EL3, 0),
|
|
||||||
&ttbcr);
|
|
||||||
retval += dpm->instr_read_data_r0_64(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TTBR0_EL3, 0),
|
|
||||||
&armv8->ttbr_base);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
armv8->va_size = 64 - (ttbcr & 0x3F);
|
|
||||||
armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
|
|
||||||
armv8->page_size = (ttbcr >> 14) & 3;
|
|
||||||
break;
|
|
||||||
case SYSTEM_CUREL_EL2:
|
|
||||||
retval = dpm->instr_read_data_r0(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TCR_EL2, 0),
|
|
||||||
&ttbcr);
|
|
||||||
retval += dpm->instr_read_data_r0_64(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TTBR0_EL2, 0),
|
|
||||||
&armv8->ttbr_base);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
armv8->va_size = 64 - (ttbcr & 0x3F);
|
|
||||||
armv8->pa_size = armv8_pa_size((ttbcr >> 16) & 7);
|
|
||||||
armv8->page_size = (ttbcr >> 14) & 3;
|
|
||||||
break;
|
|
||||||
case SYSTEM_CUREL_EL0:
|
|
||||||
armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
|
|
||||||
/* fall through */
|
|
||||||
case SYSTEM_CUREL_EL1:
|
|
||||||
retval = dpm->instr_read_data_r0_64(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TCR_EL1, 0),
|
|
||||||
&ttbcr_64);
|
|
||||||
armv8->va_size = 64 - (ttbcr_64 & 0x3F);
|
|
||||||
armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7);
|
|
||||||
armv8->page_size = (ttbcr_64 >> 14) & 3;
|
|
||||||
armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0;
|
|
||||||
armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF;
|
|
||||||
retval += dpm->instr_read_data_r0_64(dpm,
|
|
||||||
ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0),
|
|
||||||
&armv8->ttbr_base);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("unknown core state");
|
|
||||||
retval = ERROR_FAIL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (armv8->armv8_mmu.ttbr1_used == 1)
|
|
||||||
LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask));
|
|
||||||
|
|
||||||
done:
|
|
||||||
armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
|
|
||||||
dpm->finish(dpm);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* method adapted to cortex A : reused arm v4 v5 method*/
|
/* method adapted to cortex A : reused arm v4 v5 method*/
|
||||||
int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val)
|
int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val)
|
||||||
{
|
{
|
||||||
|
@ -1083,6 +1101,15 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(armv8_pauth_command)
|
||||||
|
{
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
|
return CALL_COMMAND_HANDLER(handle_command_parse_bool,
|
||||||
|
&armv8->enable_pauth,
|
||||||
|
"pauth feature");
|
||||||
|
}
|
||||||
|
|
||||||
int armv8_handle_cache_info_command(struct command_invocation *cmd,
|
int armv8_handle_cache_info_command(struct command_invocation *cmd,
|
||||||
struct armv8_cache_common *armv8_cache)
|
struct armv8_cache_common *armv8_cache)
|
||||||
{
|
{
|
||||||
|
@ -1421,6 +1448,8 @@ static const struct {
|
||||||
NULL},
|
NULL},
|
||||||
{ ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
{ ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
|
||||||
NULL},
|
NULL},
|
||||||
|
{ ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
|
||||||
|
{ ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
|
@ -1650,6 +1679,9 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
|
||||||
*reg_list[i].reg_data_type = *armv8_regs[i].data_type;
|
*reg_list[i].reg_data_type = *armv8_regs[i].data_type;
|
||||||
} else
|
} else
|
||||||
LOG_ERROR("unable to allocate reg type list");
|
LOG_ERROR("unable to allocate reg type list");
|
||||||
|
|
||||||
|
if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK)
|
||||||
|
reg_list[i].hidden = !armv8->enable_pauth;
|
||||||
}
|
}
|
||||||
|
|
||||||
arm->cpsr = reg_list + ARMV8_XPSR;
|
arm->cpsr = reg_list + ARMV8_XPSR;
|
||||||
|
@ -1745,6 +1777,17 @@ const struct command_registration armv8_command_handlers[] = {
|
||||||
.help = "configure exception catch",
|
.help = "configure exception catch",
|
||||||
.usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]",
|
.usage = "[(nsec_el1,nsec_el2,sec_el1,sec_el3)+,off]",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "pauth",
|
||||||
|
.handler = armv8_pauth_command,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "enable or disable providing GDB with an 8-bytes mask to "
|
||||||
|
"remove signature bits added by pointer authentication."
|
||||||
|
"Pointer authentication feature is broken until gdb 12.1, going to be fixed. "
|
||||||
|
"Consider using a newer version of gdb if you want enable "
|
||||||
|
"pauth feature.",
|
||||||
|
.usage = "[on|off]",
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,10 @@ enum {
|
||||||
ARMV8_ESR_EL3 = 75,
|
ARMV8_ESR_EL3 = 75,
|
||||||
ARMV8_SPSR_EL3 = 76,
|
ARMV8_SPSR_EL3 = 76,
|
||||||
|
|
||||||
|
/* Pseudo registers defined by GDB to remove the pauth signature. */
|
||||||
|
ARMV8_PAUTH_DMASK = 77,
|
||||||
|
ARMV8_PAUTH_CMASK = 78,
|
||||||
|
|
||||||
ARMV8_LAST_REG,
|
ARMV8_LAST_REG,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -205,6 +209,9 @@ struct armv8_common {
|
||||||
|
|
||||||
struct arm_cti *cti;
|
struct arm_cti *cti;
|
||||||
|
|
||||||
|
/* True if OpenOCD provides pointer auth related info to GDB */
|
||||||
|
bool enable_pauth;
|
||||||
|
|
||||||
/* last run-control command issued to this target (resume, halt, step) */
|
/* last run-control command issued to this target (resume, halt, step) */
|
||||||
enum run_control_op last_run_control_op;
|
enum run_control_op last_run_control_op;
|
||||||
|
|
||||||
|
|
|
@ -2246,7 +2246,7 @@ static int cortex_a_write_cpu_memory(struct target *target,
|
||||||
/* Switch to non-blocking mode if not already in that mode. */
|
/* Switch to non-blocking mode if not already in that mode. */
|
||||||
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
|
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
/* Mark R0 as dirty. */
|
/* Mark R0 as dirty. */
|
||||||
arm_reg_current(arm, 0)->dirty = true;
|
arm_reg_current(arm, 0)->dirty = true;
|
||||||
|
@ -2254,16 +2254,16 @@ static int cortex_a_write_cpu_memory(struct target *target,
|
||||||
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
|
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
|
||||||
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
|
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
/* Get the memory address into R0. */
|
/* Get the memory address into R0. */
|
||||||
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
||||||
armv7a->debug_base + CPUDBG_DTRRX, address);
|
armv7a->debug_base + CPUDBG_DTRRX, address);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
|
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
if (size == 4 && (address % 4) == 0) {
|
if (size == 4 && (address % 4) == 0) {
|
||||||
/* We are doing a word-aligned transfer, so use fast mode. */
|
/* We are doing a word-aligned transfer, so use fast mode. */
|
||||||
|
@ -2288,7 +2288,6 @@ static int cortex_a_write_cpu_memory(struct target *target,
|
||||||
retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr);
|
retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
final_retval = retval;
|
final_retval = retval;
|
||||||
|
|
||||||
/* Switch to non-blocking mode if not already in that mode. */
|
/* Switch to non-blocking mode if not already in that mode. */
|
||||||
|
@ -2564,7 +2563,7 @@ static int cortex_a_read_cpu_memory(struct target *target,
|
||||||
/* Switch to non-blocking mode if not already in that mode. */
|
/* Switch to non-blocking mode if not already in that mode. */
|
||||||
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
|
retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
/* Mark R0 as dirty. */
|
/* Mark R0 as dirty. */
|
||||||
arm_reg_current(arm, 0)->dirty = true;
|
arm_reg_current(arm, 0)->dirty = true;
|
||||||
|
@ -2572,16 +2571,16 @@ static int cortex_a_read_cpu_memory(struct target *target,
|
||||||
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
|
/* Read DFAR and DFSR, as they will be modified in the event of a fault. */
|
||||||
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
|
retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
/* Get the memory address into R0. */
|
/* Get the memory address into R0. */
|
||||||
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
|
||||||
armv7a->debug_base + CPUDBG_DTRRX, address);
|
armv7a->debug_base + CPUDBG_DTRRX, address);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
|
retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto out;
|
return retval;
|
||||||
|
|
||||||
if (size == 4 && (address % 4) == 0) {
|
if (size == 4 && (address % 4) == 0) {
|
||||||
/* We are doing a word-aligned transfer, so use fast mode. */
|
/* We are doing a word-aligned transfer, so use fast mode. */
|
||||||
|
@ -2607,7 +2606,6 @@ static int cortex_a_read_cpu_memory(struct target *target,
|
||||||
retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr);
|
retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
final_retval = retval;
|
final_retval = retval;
|
||||||
|
|
||||||
/* Switch to non-blocking mode if not already in that mode. */
|
/* Switch to non-blocking mode if not already in that mode. */
|
||||||
|
@ -2874,11 +2872,7 @@ static int cortex_a_examine_first(struct target *target)
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1;
|
uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1;
|
||||||
|
|
||||||
if (armv7a->debug_ap) {
|
if (!armv7a->debug_ap) {
|
||||||
dap_put_ap(armv7a->debug_ap);
|
|
||||||
armv7a->debug_ap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc->ap_num == DP_APSEL_INVALID) {
|
if (pc->ap_num == DP_APSEL_INVALID) {
|
||||||
/* Search for the APB-AP - it is needed for access to debug registers */
|
/* Search for the APB-AP - it is needed for access to debug registers */
|
||||||
retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
|
retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
|
||||||
|
@ -2893,6 +2887,7 @@ static int cortex_a_examine_first(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retval = mem_ap_init(armv7a->debug_ap);
|
retval = mem_ap_init(armv7a->debug_ap);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "register.h"
|
#include "register.h"
|
||||||
#include "arm_opcodes.h"
|
#include "arm_opcodes.h"
|
||||||
#include "arm_semihosting.h"
|
#include "arm_semihosting.h"
|
||||||
|
#include "smp.h"
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
#include <rtt/rtt.h>
|
#include <rtt/rtt.h>
|
||||||
|
|
||||||
|
@ -871,7 +872,7 @@ static int cortex_m_debug_entry(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cortex_m_poll(struct target *target)
|
static int cortex_m_poll_one(struct target *target)
|
||||||
{
|
{
|
||||||
int detected_failure = ERROR_OK;
|
int detected_failure = ERROR_OK;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
@ -879,16 +880,6 @@ static int cortex_m_poll(struct target *target)
|
||||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||||
|
|
||||||
/* Check if debug_ap is available to prevent segmentation fault.
|
|
||||||
* If the re-examination after an error does not find a MEM-AP
|
|
||||||
* (e.g. the target stopped communicating), debug_ap pointer
|
|
||||||
* can suddenly become NULL.
|
|
||||||
*/
|
|
||||||
if (!armv7m->debug_ap) {
|
|
||||||
target->state = TARGET_UNKNOWN;
|
|
||||||
return ERROR_TARGET_NOT_EXAMINED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read from Debug Halting Control and Status Register */
|
/* Read from Debug Halting Control and Status Register */
|
||||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -944,21 +935,26 @@ static int cortex_m_poll(struct target *target)
|
||||||
|
|
||||||
if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) {
|
if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) {
|
||||||
retval = cortex_m_debug_entry(target);
|
retval = cortex_m_debug_entry(target);
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
/* arm_semihosting needs to know registers, don't run if debug entry returned error */
|
||||||
|
if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0)
|
||||||
if (arm_semihosting(target, &retval) != 0)
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
if (target->smp) {
|
||||||
|
LOG_TARGET_DEBUG(target, "postpone target event 'halted'");
|
||||||
|
target->smp_halt_event_postponed = true;
|
||||||
|
} else {
|
||||||
|
/* regardless of errors returned in previous code update state */
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (prev_target_state == TARGET_DEBUG_RUNNING) {
|
if (prev_target_state == TARGET_DEBUG_RUNNING) {
|
||||||
retval = cortex_m_debug_entry(target);
|
retval = cortex_m_debug_entry(target);
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
||||||
}
|
}
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->state == TARGET_UNKNOWN) {
|
if (target->state == TARGET_UNKNOWN) {
|
||||||
|
@ -991,7 +987,104 @@ static int cortex_m_poll(struct target *target)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cortex_m_halt(struct target *target)
|
static int cortex_m_halt_one(struct target *target);
|
||||||
|
|
||||||
|
static int cortex_m_smp_halt_all(struct list_head *smp_targets)
|
||||||
|
{
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
struct target_list *head;
|
||||||
|
|
||||||
|
foreach_smp_target(head, smp_targets) {
|
||||||
|
struct target *curr = head->target;
|
||||||
|
if (!target_was_examined(curr))
|
||||||
|
continue;
|
||||||
|
if (curr->state == TARGET_HALTED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int ret2 = cortex_m_halt_one(curr);
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
retval = ret2; /* store the first error code ignore others */
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_smp_post_halt_poll(struct list_head *smp_targets)
|
||||||
|
{
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
struct target_list *head;
|
||||||
|
|
||||||
|
foreach_smp_target(head, smp_targets) {
|
||||||
|
struct target *curr = head->target;
|
||||||
|
if (!target_was_examined(curr))
|
||||||
|
continue;
|
||||||
|
/* skip targets that were already halted */
|
||||||
|
if (curr->state == TARGET_HALTED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int ret2 = cortex_m_poll_one(curr);
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
retval = ret2; /* store the first error code ignore others */
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_poll_smp(struct list_head *smp_targets)
|
||||||
|
{
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
struct target_list *head;
|
||||||
|
bool halted = false;
|
||||||
|
|
||||||
|
foreach_smp_target(head, smp_targets) {
|
||||||
|
struct target *curr = head->target;
|
||||||
|
if (curr->smp_halt_event_postponed) {
|
||||||
|
halted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (halted) {
|
||||||
|
retval = cortex_m_smp_halt_all(smp_targets);
|
||||||
|
|
||||||
|
int ret2 = cortex_m_smp_post_halt_poll(smp_targets);
|
||||||
|
if (retval == ERROR_OK)
|
||||||
|
retval = ret2; /* store the first error code ignore others */
|
||||||
|
|
||||||
|
foreach_smp_target(head, smp_targets) {
|
||||||
|
struct target *curr = head->target;
|
||||||
|
if (!curr->smp_halt_event_postponed)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
curr->smp_halt_event_postponed = false;
|
||||||
|
if (curr->state == TARGET_HALTED) {
|
||||||
|
LOG_TARGET_DEBUG(curr, "sending postponed target event 'halted'");
|
||||||
|
target_call_event_callbacks(curr, TARGET_EVENT_HALTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* There is no need to set gdb_service->target
|
||||||
|
* as hwthread_update_threads() selects an interesting thread
|
||||||
|
* by its own
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_poll(struct target *target)
|
||||||
|
{
|
||||||
|
int retval = cortex_m_poll_one(target);
|
||||||
|
|
||||||
|
if (target->smp) {
|
||||||
|
struct target_list *last;
|
||||||
|
last = list_last_entry(target->smp_targets, struct target_list, lh);
|
||||||
|
if (target == last->target)
|
||||||
|
/* After the last target in SMP group has been polled
|
||||||
|
* check for postponed halted events and eventually halt and re-poll
|
||||||
|
* other targets */
|
||||||
|
cortex_m_poll_smp(target->smp_targets);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_halt_one(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target));
|
LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target));
|
||||||
|
|
||||||
|
@ -1029,6 +1122,14 @@ static int cortex_m_halt(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cortex_m_halt(struct target *target)
|
||||||
|
{
|
||||||
|
if (target->smp)
|
||||||
|
return cortex_m_smp_halt_all(target->smp_targets);
|
||||||
|
else
|
||||||
|
return cortex_m_halt_one(target);
|
||||||
|
}
|
||||||
|
|
||||||
static int cortex_m_soft_reset_halt(struct target *target)
|
static int cortex_m_soft_reset_halt(struct target *target)
|
||||||
{
|
{
|
||||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||||
|
@ -1106,8 +1207,8 @@ void cortex_m_enable_breakpoints(struct target *target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cortex_m_resume(struct target *target, int current,
|
static int cortex_m_restore_one(struct target *target, bool current,
|
||||||
target_addr_t address, int handle_breakpoints, int debug_execution)
|
target_addr_t *address, bool handle_breakpoints, bool debug_execution)
|
||||||
{
|
{
|
||||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
struct breakpoint *breakpoint = NULL;
|
struct breakpoint *breakpoint = NULL;
|
||||||
|
@ -1115,7 +1216,7 @@ static int cortex_m_resume(struct target *target, int current,
|
||||||
struct reg *r;
|
struct reg *r;
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_TARGET_WARNING(target, "target not halted");
|
LOG_TARGET_ERROR(target, "target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,7 +1258,7 @@ static int cortex_m_resume(struct target *target, int current,
|
||||||
/* current = 1: continue on current pc, otherwise continue at <address> */
|
/* current = 1: continue on current pc, otherwise continue at <address> */
|
||||||
r = armv7m->arm.pc;
|
r = armv7m->arm.pc;
|
||||||
if (!current) {
|
if (!current) {
|
||||||
buf_set_u32(r->value, 0, 32, address);
|
buf_set_u32(r->value, 0, 32, *address);
|
||||||
r->dirty = true;
|
r->dirty = true;
|
||||||
r->valid = true;
|
r->valid = true;
|
||||||
}
|
}
|
||||||
|
@ -1171,8 +1272,12 @@ static int cortex_m_resume(struct target *target, int current,
|
||||||
armv7m_maybe_skip_bkpt_inst(target, NULL);
|
armv7m_maybe_skip_bkpt_inst(target, NULL);
|
||||||
|
|
||||||
resume_pc = buf_get_u32(r->value, 0, 32);
|
resume_pc = buf_get_u32(r->value, 0, 32);
|
||||||
|
if (current)
|
||||||
|
*address = resume_pc;
|
||||||
|
|
||||||
armv7m_restore_context(target);
|
int retval = armv7m_restore_context(target);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
/* the front-end may request us not to handle breakpoints */
|
/* the front-end may request us not to handle breakpoints */
|
||||||
if (handle_breakpoints) {
|
if (handle_breakpoints) {
|
||||||
|
@ -1182,34 +1287,99 @@ static int cortex_m_resume(struct target *target, int current,
|
||||||
LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")",
|
LOG_TARGET_DEBUG(target, "unset breakpoint at " TARGET_ADDR_FMT " (ID: %" PRIu32 ")",
|
||||||
breakpoint->address,
|
breakpoint->address,
|
||||||
breakpoint->unique_id);
|
breakpoint->unique_id);
|
||||||
cortex_m_unset_breakpoint(target, breakpoint);
|
retval = cortex_m_unset_breakpoint(target, breakpoint);
|
||||||
cortex_m_single_step_core(target);
|
if (retval == ERROR_OK)
|
||||||
cortex_m_set_breakpoint(target, breakpoint);
|
retval = cortex_m_single_step_core(target);
|
||||||
|
int ret2 = cortex_m_set_breakpoint(target, breakpoint);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
if (ret2 != ERROR_OK)
|
||||||
|
return ret2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_restart_one(struct target *target, bool debug_execution)
|
||||||
|
{
|
||||||
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
|
||||||
/* Restart core */
|
/* Restart core */
|
||||||
cortex_m_set_maskints_for_run(target);
|
cortex_m_set_maskints_for_run(target);
|
||||||
cortex_m_write_debug_halt_mask(target, 0, C_HALT);
|
cortex_m_write_debug_halt_mask(target, 0, C_HALT);
|
||||||
|
|
||||||
target->debug_reason = DBG_REASON_NOTHALTED;
|
target->debug_reason = DBG_REASON_NOTHALTED;
|
||||||
|
|
||||||
/* registers are now invalid */
|
/* registers are now invalid */
|
||||||
register_cache_invalidate(armv7m->arm.core_cache);
|
register_cache_invalidate(armv7m->arm.core_cache);
|
||||||
|
|
||||||
if (!debug_execution) {
|
if (!debug_execution) {
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
|
||||||
LOG_TARGET_DEBUG(target, "target resumed at 0x%" PRIx32 "", resume_pc);
|
|
||||||
} else {
|
} else {
|
||||||
target->state = TARGET_DEBUG_RUNNING;
|
target->state = TARGET_DEBUG_RUNNING;
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
|
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
|
||||||
LOG_TARGET_DEBUG(target, "target debug resumed at 0x%" PRIx32 "", resume_pc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints)
|
||||||
|
{
|
||||||
|
struct target_list *head;
|
||||||
|
target_addr_t address;
|
||||||
|
foreach_smp_target(head, target->smp_targets) {
|
||||||
|
struct target *curr = head->target;
|
||||||
|
/* skip calling target */
|
||||||
|
if (curr == target)
|
||||||
|
continue;
|
||||||
|
if (!target_was_examined(curr))
|
||||||
|
continue;
|
||||||
|
/* skip running targets */
|
||||||
|
if (curr->state == TARGET_RUNNING)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int retval = cortex_m_restore_one(curr, true, &address,
|
||||||
|
handle_breakpoints, false);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = cortex_m_restart_one(curr, false);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(curr, "SMP resumed at " TARGET_ADDR_FMT, address);
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortex_m_resume(struct target *target, int current,
|
||||||
|
target_addr_t address, int handle_breakpoints, int debug_execution)
|
||||||
|
{
|
||||||
|
int retval = cortex_m_restore_one(target, !!current, &address, !!handle_breakpoints, !!debug_execution);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_TARGET_ERROR(target, "context restore failed, aborting resume");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->smp && !debug_execution) {
|
||||||
|
retval = cortex_m_restore_smp(target, !!handle_breakpoints);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
LOG_WARNING("resume of a SMP target failed, trying to resume current one");
|
||||||
|
}
|
||||||
|
|
||||||
|
cortex_m_restart_one(target, !!debug_execution);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_TARGET_ERROR(target, "resume failed");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(target, "%sresumed at " TARGET_ADDR_FMT,
|
||||||
|
debug_execution ? "debug " : "", address);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* int irqstepcount = 0; */
|
/* int irqstepcount = 0; */
|
||||||
static int cortex_m_step(struct target *target, int current,
|
static int cortex_m_step(struct target *target, int current,
|
||||||
target_addr_t address, int handle_breakpoints)
|
target_addr_t address, int handle_breakpoints)
|
||||||
|
@ -1227,6 +1397,11 @@ static int cortex_m_step(struct target *target, int current,
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Just one of SMP cores will step. Set the gdb control
|
||||||
|
* target to current one or gdb miss gdb-end event */
|
||||||
|
if (target->smp && target->gdb_service)
|
||||||
|
target->gdb_service->target = target;
|
||||||
|
|
||||||
/* current = 1: continue on current pc, otherwise continue at <address> */
|
/* current = 1: continue on current pc, otherwise continue at <address> */
|
||||||
if (!current) {
|
if (!current) {
|
||||||
buf_set_u32(pc->value, 0, 32, address);
|
buf_set_u32(pc->value, 0, 32, address);
|
||||||
|
@ -1408,8 +1583,9 @@ static int cortex_m_assert_reset(struct target *target)
|
||||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||||
enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config;
|
enum cortex_m_soft_reset_config reset_config = cortex_m->soft_reset_config;
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "target->state: %s",
|
LOG_TARGET_DEBUG(target, "target->state: %s,%s examined",
|
||||||
target_state_name(target));
|
target_state_name(target),
|
||||||
|
target_was_examined(target) ? "" : " not");
|
||||||
|
|
||||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||||
|
|
||||||
|
@ -1428,24 +1604,40 @@ static int cortex_m_assert_reset(struct target *target)
|
||||||
|
|
||||||
bool srst_asserted = false;
|
bool srst_asserted = false;
|
||||||
|
|
||||||
if (!target_was_examined(target)) {
|
|
||||||
if (jtag_reset_config & RESET_HAS_SRST) {
|
|
||||||
adapter_assert_reset();
|
|
||||||
if (target->reset_halt)
|
|
||||||
LOG_TARGET_ERROR(target, "Target not examined, will not halt after reset!");
|
|
||||||
return ERROR_OK;
|
|
||||||
} else {
|
|
||||||
LOG_TARGET_ERROR(target, "Target not examined, reset NOT asserted!");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((jtag_reset_config & RESET_HAS_SRST) &&
|
if ((jtag_reset_config & RESET_HAS_SRST) &&
|
||||||
(jtag_reset_config & RESET_SRST_NO_GATING)) {
|
((jtag_reset_config & RESET_SRST_NO_GATING) || !armv7m->debug_ap)) {
|
||||||
|
/* If we have no debug_ap, asserting SRST is the only thing
|
||||||
|
* we can do now */
|
||||||
adapter_assert_reset();
|
adapter_assert_reset();
|
||||||
srst_asserted = true;
|
srst_asserted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: replace the hack calling target_examine_one()
|
||||||
|
* as soon as a better reset framework is available */
|
||||||
|
if (!target_was_examined(target) && !target->defer_examine
|
||||||
|
&& srst_asserted && (jtag_reset_config & RESET_SRST_NO_GATING)) {
|
||||||
|
LOG_TARGET_DEBUG(target, "Trying to re-examine under reset");
|
||||||
|
target_examine_one(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need at least debug_ap to go further.
|
||||||
|
* Inform user and bail out if we don't have one. */
|
||||||
|
if (!armv7m->debug_ap) {
|
||||||
|
if (srst_asserted) {
|
||||||
|
if (target->reset_halt)
|
||||||
|
LOG_TARGET_ERROR(target, "Debug AP not available, will not halt after reset!");
|
||||||
|
|
||||||
|
/* Do not propagate error: reset was asserted, proceed to deassert! */
|
||||||
|
target->state = TARGET_RESET;
|
||||||
|
register_cache_invalidate(cortex_m->armv7m.arm.core_cache);
|
||||||
|
return ERROR_OK;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_TARGET_ERROR(target, "Debug AP not available, reset NOT asserted!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable debug requests */
|
/* Enable debug requests */
|
||||||
int retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
int retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||||
|
|
||||||
|
@ -1546,7 +1738,7 @@ static int cortex_m_assert_reset(struct target *target)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (target->reset_halt) {
|
if (target->reset_halt && target_was_examined(target)) {
|
||||||
retval = target_halt(target);
|
retval = target_halt(target);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -1559,8 +1751,9 @@ static int cortex_m_deassert_reset(struct target *target)
|
||||||
{
|
{
|
||||||
struct armv7m_common *armv7m = &target_to_cm(target)->armv7m;
|
struct armv7m_common *armv7m = &target_to_cm(target)->armv7m;
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "target->state: %s",
|
LOG_TARGET_DEBUG(target, "target->state: %s,%s examined",
|
||||||
target_state_name(target));
|
target_state_name(target),
|
||||||
|
target_was_examined(target) ? "" : " not");
|
||||||
|
|
||||||
/* deassert reset lines */
|
/* deassert reset lines */
|
||||||
adapter_deassert_reset();
|
adapter_deassert_reset();
|
||||||
|
@ -1569,7 +1762,7 @@ static int cortex_m_deassert_reset(struct target *target)
|
||||||
|
|
||||||
if ((jtag_reset_config & RESET_HAS_SRST) &&
|
if ((jtag_reset_config & RESET_HAS_SRST) &&
|
||||||
!(jtag_reset_config & RESET_SRST_NO_GATING) &&
|
!(jtag_reset_config & RESET_SRST_NO_GATING) &&
|
||||||
target_was_examined(target)) {
|
armv7m->debug_ap) {
|
||||||
|
|
||||||
int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap);
|
int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -2262,6 +2455,22 @@ static void cortex_m_dwt_free(struct target *target)
|
||||||
cm->dwt_cache = NULL;
|
cm->dwt_cache = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cortex_m_has_tz(struct target *target)
|
||||||
|
{
|
||||||
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
uint32_t dauthstatus;
|
||||||
|
|
||||||
|
if (armv7m->arm.arch != ARM_ARCH_V8M)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int retval = target_read_u32(target, DAUTHSTATUS, &dauthstatus);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_WARNING("Error reading DAUTHSTATUS register");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define MVFR0 0xe000ef40
|
#define MVFR0 0xe000ef40
|
||||||
#define MVFR1 0xe000ef44
|
#define MVFR1 0xe000ef44
|
||||||
|
|
||||||
|
@ -2293,11 +2502,7 @@ int cortex_m_examine(struct target *target)
|
||||||
/* hla_target shares the examine handler but does not support
|
/* hla_target shares the examine handler but does not support
|
||||||
* all its calls */
|
* all its calls */
|
||||||
if (!armv7m->is_hla_target) {
|
if (!armv7m->is_hla_target) {
|
||||||
if (armv7m->debug_ap) {
|
if (!armv7m->debug_ap) {
|
||||||
dap_put_ap(armv7m->debug_ap);
|
|
||||||
armv7m->debug_ap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cortex_m->apsel == DP_APSEL_INVALID) {
|
if (cortex_m->apsel == DP_APSEL_INVALID) {
|
||||||
/* Search for the MEM-AP */
|
/* Search for the MEM-AP */
|
||||||
retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap);
|
retval = cortex_m_find_mem_ap(swjdp, &armv7m->debug_ap);
|
||||||
|
@ -2312,6 +2517,7 @@ int cortex_m_examine(struct target *target)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
armv7m->debug_ap->memaccess_tck = 8;
|
armv7m->debug_ap->memaccess_tck = 8;
|
||||||
|
|
||||||
|
@ -2393,7 +2599,7 @@ 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;
|
||||||
|
|
||||||
if (armv7m->arm.arch != ARM_ARCH_V8M)
|
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;
|
||||||
|
|
||||||
|
@ -2829,6 +3035,9 @@ static const struct command_registration cortex_m_exec_command_handlers[] = {
|
||||||
.help = "configure software reset handling",
|
.help = "configure software reset handling",
|
||||||
.usage = "['sysresetreq'|'vectreset']",
|
.usage = "['sysresetreq'|'vectreset']",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.chain = smp_command_handlers,
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
static const struct command_registration cortex_m_command_handlers[] = {
|
static const struct command_registration cortex_m_command_handlers[] = {
|
||||||
|
|
|
@ -68,6 +68,9 @@ struct cortex_m_part_info {
|
||||||
#define DCB_DEMCR 0xE000EDFC
|
#define DCB_DEMCR 0xE000EDFC
|
||||||
#define DCB_DSCSR 0xE000EE08
|
#define DCB_DSCSR 0xE000EE08
|
||||||
|
|
||||||
|
#define DAUTHSTATUS 0xE000EFB8
|
||||||
|
#define DAUTHSTATUS_SID_MASK 0x00000030
|
||||||
|
|
||||||
#define DCRSR_WNR BIT(16)
|
#define DCRSR_WNR BIT(16)
|
||||||
|
|
||||||
#define DWT_CTRL 0xE0001000
|
#define DWT_CTRL 0xE0001000
|
||||||
|
|
|
@ -2200,8 +2200,8 @@ int dsp5680xx_f_lock(struct target *target)
|
||||||
struct jtag_tap *tap_chp;
|
struct jtag_tap *tap_chp;
|
||||||
|
|
||||||
struct jtag_tap *tap_cpu;
|
struct jtag_tap *tap_cpu;
|
||||||
uint16_t lock_word[] = { HFM_LOCK_FLASH };
|
uint16_t lock_word = HFM_LOCK_FLASH;
|
||||||
retval = dsp5680xx_f_wr(target, (uint8_t *) (lock_word), HFM_LOCK_ADDR_L, 2, 1);
|
retval = dsp5680xx_f_wr(target, (uint8_t *)&lock_word, HFM_LOCK_ADDR_L, 2, 1);
|
||||||
err_check_propagate(retval);
|
err_check_propagate(retval);
|
||||||
|
|
||||||
jtag_add_reset(0, 1);
|
jtag_add_reset(0, 1);
|
||||||
|
|
|
@ -130,7 +130,9 @@ static int esirisc_jtag_recv(struct esirisc_jtag *jtag_info,
|
||||||
int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8);
|
int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8);
|
||||||
|
|
||||||
struct scan_field fields[3];
|
struct scan_field fields[3];
|
||||||
uint8_t r[num_in_bytes * 2];
|
/* prevent zero-size variable length array */
|
||||||
|
int r_size = num_in_bytes ? num_in_bytes * 2 : 1;
|
||||||
|
uint8_t r[r_size];
|
||||||
|
|
||||||
esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG);
|
esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG);
|
||||||
|
|
||||||
|
|
|
@ -402,6 +402,8 @@ static int esp32s2_poll(struct target *target)
|
||||||
{
|
{
|
||||||
enum target_state old_state = target->state;
|
enum target_state old_state = target->state;
|
||||||
int ret = esp_xtensa_poll(target);
|
int ret = esp_xtensa_poll(target);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
|
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
|
||||||
/* Call any event callbacks that are applicable */
|
/* Call any event callbacks that are applicable */
|
||||||
|
|
|
@ -347,6 +347,13 @@ static int hl_assert_reset(struct target *target)
|
||||||
|
|
||||||
adapter->layout->api->write_debug_reg(adapter->handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
|
adapter->layout->api->write_debug_reg(adapter->handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
|
||||||
|
|
||||||
|
if (!target_was_examined(target) && !target->defer_examine
|
||||||
|
&& srst_asserted && res == ERROR_OK) {
|
||||||
|
/* If the target is not examined, now under reset it is good time to retry examination */
|
||||||
|
LOG_TARGET_DEBUG(target, "Trying to re-examine under reset");
|
||||||
|
target_examine_one(target);
|
||||||
|
}
|
||||||
|
|
||||||
/* only set vector catch if halt is requested */
|
/* only set vector catch if halt is requested */
|
||||||
if (target->reset_halt)
|
if (target->reset_halt)
|
||||||
adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA|VC_CORERESET);
|
adapter->layout->api->write_debug_reg(adapter->handle, DCB_DEMCR, TRCENA|VC_CORERESET);
|
||||||
|
|
|
@ -136,16 +136,13 @@ static int mem_ap_examine(struct target *target)
|
||||||
struct mem_ap *mem_ap = target->arch_info;
|
struct mem_ap *mem_ap = target->arch_info;
|
||||||
|
|
||||||
if (!target_was_examined(target)) {
|
if (!target_was_examined(target)) {
|
||||||
if (mem_ap->ap) {
|
if (!mem_ap->ap) {
|
||||||
dap_put_ap(mem_ap->ap);
|
|
||||||
mem_ap->ap = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num);
|
mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num);
|
||||||
if (!mem_ap->ap) {
|
if (!mem_ap->ap) {
|
||||||
LOG_ERROR("Cannot get AP");
|
LOG_ERROR("Cannot get AP");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
target_set_examined(target);
|
target_set_examined(target);
|
||||||
target->state = TARGET_UNKNOWN;
|
target->state = TARGET_UNKNOWN;
|
||||||
target->debug_reason = DBG_REASON_UNDEFINED;
|
target->debug_reason = DBG_REASON_UNDEFINED;
|
||||||
|
|
|
@ -900,7 +900,7 @@ static int mips_m4k_set_watchpoint(struct target *target,
|
||||||
LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
|
LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
|
||||||
}
|
}
|
||||||
|
|
||||||
watchpoint->number = wp_num;
|
watchpoint_set(watchpoint, wp_num);
|
||||||
comparator_list[wp_num].used = 1;
|
comparator_list[wp_num].used = 1;
|
||||||
comparator_list[wp_num].bp_value = watchpoint->address;
|
comparator_list[wp_num].bp_value = watchpoint->address;
|
||||||
|
|
||||||
|
|
2613
src/target/nds32.c
2613
src/target/nds32.c
File diff suppressed because it is too large
Load Diff
|
@ -1,447 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_H
|
|
||||||
|
|
||||||
#include <jtag/jtag.h>
|
|
||||||
#include "target.h"
|
|
||||||
#include "target_type.h"
|
|
||||||
#include "register.h"
|
|
||||||
#include "breakpoints.h"
|
|
||||||
#include "nds32_reg.h"
|
|
||||||
#include "nds32_insn.h"
|
|
||||||
#include "nds32_edm.h"
|
|
||||||
|
|
||||||
#define NDS32_EDM_OPERATION_MAX_NUM 64
|
|
||||||
|
|
||||||
#define CHECK_RETVAL(action) \
|
|
||||||
do { \
|
|
||||||
int __retval = (action); \
|
|
||||||
if (__retval != ERROR_OK) { \
|
|
||||||
LOG_DEBUG("error while calling \"%s\"", \
|
|
||||||
# action); \
|
|
||||||
return __retval; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Holds the interface to Andes cores.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern const char *nds32_debug_type_name[11];
|
|
||||||
|
|
||||||
enum nds32_debug_reason {
|
|
||||||
NDS32_DEBUG_BREAK = 0,
|
|
||||||
NDS32_DEBUG_BREAK_16,
|
|
||||||
NDS32_DEBUG_INST_BREAK,
|
|
||||||
NDS32_DEBUG_DATA_ADDR_WATCHPOINT_PRECISE,
|
|
||||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_PRECISE,
|
|
||||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_IMPRECISE,
|
|
||||||
NDS32_DEBUG_DEBUG_INTERRUPT,
|
|
||||||
NDS32_DEBUG_HARDWARE_SINGLE_STEP,
|
|
||||||
NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE,
|
|
||||||
NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE,
|
|
||||||
NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NDS32_STRUCT_STAT_SIZE 60
|
|
||||||
#define NDS32_STRUCT_TIMEVAL_SIZE 8
|
|
||||||
|
|
||||||
enum nds32_syscall_id {
|
|
||||||
NDS32_SYSCALL_UNDEFINED = 0,
|
|
||||||
NDS32_SYSCALL_EXIT = 1,
|
|
||||||
NDS32_SYSCALL_OPEN = 2,
|
|
||||||
NDS32_SYSCALL_CLOSE = 3,
|
|
||||||
NDS32_SYSCALL_READ = 4,
|
|
||||||
NDS32_SYSCALL_WRITE = 5,
|
|
||||||
NDS32_SYSCALL_LSEEK = 6,
|
|
||||||
NDS32_SYSCALL_UNLINK = 7,
|
|
||||||
NDS32_SYSCALL_RENAME = 3001,
|
|
||||||
NDS32_SYSCALL_FSTAT = 10,
|
|
||||||
NDS32_SYSCALL_STAT = 15,
|
|
||||||
NDS32_SYSCALL_GETTIMEOFDAY = 19,
|
|
||||||
NDS32_SYSCALL_ISATTY = 3002,
|
|
||||||
NDS32_SYSCALL_SYSTEM = 3003,
|
|
||||||
NDS32_SYSCALL_ERRNO = 6001,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NDS32_COMMON_MAGIC 0xADE5ADE5U
|
|
||||||
|
|
||||||
struct nds32_edm {
|
|
||||||
|
|
||||||
/** EDM_CFG.VER, indicate the EDM version */
|
|
||||||
int version;
|
|
||||||
|
|
||||||
/** The number of hardware breakpoints */
|
|
||||||
int breakpoint_num;
|
|
||||||
|
|
||||||
/** EDM_CFG.DALM, indicate if direct local memory access
|
|
||||||
* feature is supported or not */
|
|
||||||
bool direct_access_local_memory;
|
|
||||||
|
|
||||||
/** Support ACC_CTL register */
|
|
||||||
bool access_control;
|
|
||||||
|
|
||||||
/** */
|
|
||||||
bool support_max_stop;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_cache {
|
|
||||||
|
|
||||||
/** enable cache or not */
|
|
||||||
bool enable;
|
|
||||||
|
|
||||||
/** cache sets per way */
|
|
||||||
int set;
|
|
||||||
|
|
||||||
/** cache ways */
|
|
||||||
int way;
|
|
||||||
|
|
||||||
/** cache line size */
|
|
||||||
int line_size;
|
|
||||||
|
|
||||||
/** cache locking support */
|
|
||||||
bool lock_support;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_memory {
|
|
||||||
|
|
||||||
/** ICache */
|
|
||||||
struct nds32_cache icache;
|
|
||||||
|
|
||||||
/** DCache */
|
|
||||||
struct nds32_cache dcache;
|
|
||||||
|
|
||||||
/** On-chip instruction local memory base */
|
|
||||||
int ilm_base;
|
|
||||||
|
|
||||||
/** On-chip instruction local memory size */
|
|
||||||
int ilm_size;
|
|
||||||
|
|
||||||
/** ILM base register alignment version */
|
|
||||||
int ilm_align_ver;
|
|
||||||
|
|
||||||
/** DLM is enabled or not */
|
|
||||||
bool ilm_enable;
|
|
||||||
|
|
||||||
/** DLM start address */
|
|
||||||
int ilm_start;
|
|
||||||
|
|
||||||
/** DLM end address */
|
|
||||||
int ilm_end;
|
|
||||||
|
|
||||||
/** On-chip data local memory base */
|
|
||||||
int dlm_base;
|
|
||||||
|
|
||||||
/** On-chip data local memory size */
|
|
||||||
int dlm_size;
|
|
||||||
|
|
||||||
/** DLM base register alignment version */
|
|
||||||
int dlm_align_ver;
|
|
||||||
|
|
||||||
/** DLM is enabled or not */
|
|
||||||
bool dlm_enable;
|
|
||||||
|
|
||||||
/** DLM start address */
|
|
||||||
int dlm_start;
|
|
||||||
|
|
||||||
/** DLM end address */
|
|
||||||
int dlm_end;
|
|
||||||
|
|
||||||
/** Memory access method */
|
|
||||||
enum nds_memory_access access_channel;
|
|
||||||
|
|
||||||
/** Memory access mode */
|
|
||||||
enum nds_memory_select mode;
|
|
||||||
|
|
||||||
/** Address translation */
|
|
||||||
bool address_translation;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_cpu_version {
|
|
||||||
bool performance_extension;
|
|
||||||
bool _16bit_extension;
|
|
||||||
bool performance_extension_2;
|
|
||||||
bool cop_fpu_extension;
|
|
||||||
bool string_extension;
|
|
||||||
|
|
||||||
int revision;
|
|
||||||
int cpu_id_family;
|
|
||||||
int cpu_id_version;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_mmu_config {
|
|
||||||
int memory_protection;
|
|
||||||
int memory_protection_version;
|
|
||||||
bool fully_associative_tlb;
|
|
||||||
int tlb_size;
|
|
||||||
int tlb_ways;
|
|
||||||
int tlb_sets;
|
|
||||||
bool _8k_page_support;
|
|
||||||
int extra_page_size_support;
|
|
||||||
bool tlb_lock;
|
|
||||||
bool hardware_page_table_walker;
|
|
||||||
bool default_endian;
|
|
||||||
int partition_num;
|
|
||||||
bool invisible_tlb;
|
|
||||||
bool vlpt;
|
|
||||||
bool ntme;
|
|
||||||
bool drde;
|
|
||||||
int default_min_page_size;
|
|
||||||
bool multiple_page_size_in_use;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_misc_config {
|
|
||||||
bool edm;
|
|
||||||
bool local_memory_dma;
|
|
||||||
bool performance_monitor;
|
|
||||||
bool high_speed_memory_port;
|
|
||||||
bool debug_tracer;
|
|
||||||
bool div_instruction;
|
|
||||||
bool mac_instruction;
|
|
||||||
int audio_isa;
|
|
||||||
bool l2_cache;
|
|
||||||
bool reduce_register;
|
|
||||||
bool addr_24;
|
|
||||||
bool interruption_level;
|
|
||||||
int baseline_instruction;
|
|
||||||
bool no_dx_register;
|
|
||||||
bool implement_dependant_register;
|
|
||||||
bool implement_dependant_sr_encoding;
|
|
||||||
bool ifc;
|
|
||||||
bool mcu;
|
|
||||||
bool ex9;
|
|
||||||
int shadow;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a generic Andes core.
|
|
||||||
*/
|
|
||||||
struct nds32 {
|
|
||||||
unsigned int common_magic;
|
|
||||||
|
|
||||||
struct reg_cache *core_cache;
|
|
||||||
|
|
||||||
/** Handle for the debug module. */
|
|
||||||
struct nds32_edm edm;
|
|
||||||
|
|
||||||
/** Memory information */
|
|
||||||
struct nds32_memory memory;
|
|
||||||
|
|
||||||
/** cpu version */
|
|
||||||
struct nds32_cpu_version cpu_version;
|
|
||||||
|
|
||||||
/** MMU configuration */
|
|
||||||
struct nds32_mmu_config mmu_config;
|
|
||||||
|
|
||||||
/** Misc configuration */
|
|
||||||
struct nds32_misc_config misc_config;
|
|
||||||
|
|
||||||
/** Retrieve all core registers, for display. */
|
|
||||||
int (*full_context)(struct nds32 *nds32);
|
|
||||||
|
|
||||||
/** Register mappings */
|
|
||||||
int (*register_map)(struct nds32 *nds32, int reg_no);
|
|
||||||
|
|
||||||
/** Get debug exception virtual address */
|
|
||||||
int (*get_debug_reason)(struct nds32 *nds32, uint32_t *reason);
|
|
||||||
|
|
||||||
/** Restore target registers may be modified in debug state */
|
|
||||||
int (*leave_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
|
|
||||||
|
|
||||||
/** Backup target registers may be modified in debug state */
|
|
||||||
int (*enter_debug_state)(struct nds32 *nds32, bool enable_watchpoint);
|
|
||||||
|
|
||||||
/** Get address hit watchpoint */
|
|
||||||
int (*get_watched_address)(struct nds32 *nds32, uint32_t *address, uint32_t reason);
|
|
||||||
|
|
||||||
/** maximum interrupt level */
|
|
||||||
uint32_t max_interrupt_level;
|
|
||||||
|
|
||||||
/** current interrupt level */
|
|
||||||
uint32_t current_interrupt_level;
|
|
||||||
|
|
||||||
uint32_t watched_address;
|
|
||||||
|
|
||||||
/** Flag reporting whether virtual hosting is active. */
|
|
||||||
bool virtual_hosting;
|
|
||||||
|
|
||||||
/** Flag reporting whether continue/step hits syscall or not */
|
|
||||||
bool hit_syscall;
|
|
||||||
|
|
||||||
/** Value to be returned by virtual hosting SYS_ERRNO request. */
|
|
||||||
int virtual_hosting_errno;
|
|
||||||
|
|
||||||
/** Flag reporting whether syscall is aborted */
|
|
||||||
bool virtual_hosting_ctrl_c;
|
|
||||||
|
|
||||||
/** Record syscall ID for other operations to do special processing for target */
|
|
||||||
int active_syscall_id;
|
|
||||||
|
|
||||||
struct breakpoint syscall_break;
|
|
||||||
|
|
||||||
/** Flag reporting whether global stop is active. */
|
|
||||||
bool global_stop;
|
|
||||||
|
|
||||||
/** Flag reporting whether to use soft-reset-halt or not as issuing reset-halt. */
|
|
||||||
bool soft_reset_halt;
|
|
||||||
|
|
||||||
/** reset-halt as target examine */
|
|
||||||
bool reset_halt_as_examine;
|
|
||||||
|
|
||||||
/** backup/restore target EDM_CTL value. As debugging target debug
|
|
||||||
* handler, it should be true. */
|
|
||||||
bool keep_target_edm_ctl;
|
|
||||||
|
|
||||||
/* Value of $EDM_CTL before target enters debug mode */
|
|
||||||
uint32_t backup_edm_ctl;
|
|
||||||
|
|
||||||
/** always use word-aligned address to access memory */
|
|
||||||
bool word_access_mem;
|
|
||||||
|
|
||||||
/** EDM passcode for debugging secure MCU */
|
|
||||||
char *edm_passcode;
|
|
||||||
|
|
||||||
/** current privilege_level if using secure MCU. value 0 is the highest level. */
|
|
||||||
int privilege_level;
|
|
||||||
|
|
||||||
/** Period to wait after SRST. */
|
|
||||||
uint32_t boot_time;
|
|
||||||
|
|
||||||
/** Flag to indicate HSS steps into ISR or not */
|
|
||||||
bool step_isr_enable;
|
|
||||||
|
|
||||||
/** Flag to indicate register table is ready or not */
|
|
||||||
bool init_arch_info_after_halted;
|
|
||||||
|
|
||||||
/** Flag to indicate audio-extension is enabled or not */
|
|
||||||
bool audio_enable;
|
|
||||||
|
|
||||||
/** Flag to indicate fpu-extension is enabled or not */
|
|
||||||
bool fpu_enable;
|
|
||||||
|
|
||||||
/* Andes Core has mixed endian model. Instruction is always big-endian.
|
|
||||||
* Data may be big or little endian. Device registers may have different
|
|
||||||
* endian from data and instruction. */
|
|
||||||
/** Endian of data memory */
|
|
||||||
enum target_endianness data_endian;
|
|
||||||
|
|
||||||
/** Endian of device registers */
|
|
||||||
enum target_endianness device_reg_endian;
|
|
||||||
|
|
||||||
/** Flag to indicate if auto convert software breakpoints to
|
|
||||||
* hardware breakpoints or not in ROM */
|
|
||||||
bool auto_convert_hw_bp;
|
|
||||||
|
|
||||||
/* Flag to indicate the target is attached by debugger or not */
|
|
||||||
bool attached;
|
|
||||||
|
|
||||||
/** Backpointer to the target. */
|
|
||||||
struct target *target;
|
|
||||||
|
|
||||||
void *arch_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_reg {
|
|
||||||
int32_t num;
|
|
||||||
uint8_t value[8];
|
|
||||||
struct target *target;
|
|
||||||
struct nds32 *nds32;
|
|
||||||
bool enable;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_edm_operation {
|
|
||||||
uint32_t reg_no;
|
|
||||||
uint32_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int nds32_config(struct nds32 *nds32);
|
|
||||||
extern int nds32_init_arch_info(struct target *target, struct nds32 *nds32);
|
|
||||||
extern int nds32_full_context(struct nds32 *nds32);
|
|
||||||
extern int nds32_arch_state(struct target *target);
|
|
||||||
extern int nds32_add_software_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint);
|
|
||||||
extern int nds32_remove_software_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint);
|
|
||||||
|
|
||||||
extern int nds32_get_gdb_reg_list(struct target *target,
|
|
||||||
struct reg **reg_list[], int *reg_list_size,
|
|
||||||
enum target_register_class reg_class);
|
|
||||||
|
|
||||||
extern int nds32_write_buffer(struct target *target, uint32_t address,
|
|
||||||
uint32_t size, const uint8_t *buffer);
|
|
||||||
extern int nds32_read_buffer(struct target *target, uint32_t address,
|
|
||||||
uint32_t size, uint8_t *buffer);
|
|
||||||
extern int nds32_read_memory(struct target *target, uint32_t address,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
|
||||||
extern int nds32_write_memory(struct target *target, uint32_t address,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
|
||||||
|
|
||||||
extern int nds32_init_register_table(struct nds32 *nds32);
|
|
||||||
extern int nds32_init_memory_info(struct nds32 *nds32);
|
|
||||||
extern int nds32_restore_context(struct target *target);
|
|
||||||
extern int nds32_get_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t *value);
|
|
||||||
extern int nds32_set_mapped_reg(struct nds32 *nds32, unsigned regnum, uint32_t value);
|
|
||||||
|
|
||||||
extern int nds32_edm_config(struct nds32 *nds32);
|
|
||||||
extern int nds32_cache_sync(struct target *target, target_addr_t address, uint32_t length);
|
|
||||||
extern int nds32_mmu(struct target *target, int *enabled);
|
|
||||||
extern int nds32_virtual_to_physical(struct target *target, target_addr_t address,
|
|
||||||
target_addr_t *physical);
|
|
||||||
extern int nds32_read_phys_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
|
||||||
extern int nds32_write_phys_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
|
||||||
extern uint32_t nds32_nextpc(struct nds32 *nds32, int current, uint32_t address);
|
|
||||||
extern int nds32_examine_debug_reason(struct nds32 *nds32);
|
|
||||||
extern int nds32_step(struct target *target, int current,
|
|
||||||
target_addr_t address, int handle_breakpoints);
|
|
||||||
extern int nds32_target_state(struct nds32 *nds32, enum target_state *state);
|
|
||||||
extern int nds32_halt(struct target *target);
|
|
||||||
extern int nds32_poll(struct target *target);
|
|
||||||
extern int nds32_resume(struct target *target, int current,
|
|
||||||
target_addr_t address, int handle_breakpoints, int debug_execution);
|
|
||||||
extern int nds32_assert_reset(struct target *target);
|
|
||||||
extern int nds32_init(struct nds32 *nds32);
|
|
||||||
extern int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
|
|
||||||
extern int nds32_gdb_fileio_write_memory(struct nds32 *nds32, uint32_t address,
|
|
||||||
uint32_t size, const uint8_t *buffer);
|
|
||||||
extern int nds32_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
|
|
||||||
extern int nds32_reset_halt(struct nds32 *nds32);
|
|
||||||
extern int nds32_login(struct nds32 *nds32);
|
|
||||||
extern int nds32_profiling(struct target *target, uint32_t *samples,
|
|
||||||
uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds);
|
|
||||||
|
|
||||||
/** Convert target handle to generic Andes target state handle. */
|
|
||||||
static inline struct nds32 *target_to_nds32(struct target *target)
|
|
||||||
{
|
|
||||||
assert(target);
|
|
||||||
return target->arch_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
|
||||||
static inline struct aice_port_s *target_to_aice(struct target *target)
|
|
||||||
{
|
|
||||||
assert(target);
|
|
||||||
return target->tap->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_nds32(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
assert(nds32);
|
|
||||||
return nds32->common_magic == NDS32_COMMON_MAGIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool nds32_reach_max_interrupt_level(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
assert(nds32);
|
|
||||||
return nds32->max_interrupt_level == nds32->current_interrupt_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_H */
|
|
|
@ -1,147 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes technology. *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/log.h>
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
|
|
||||||
int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->read_reg_64) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->read_reg_64(aice->coreid, num, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->write_reg_64) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->write_reg_64(aice->coreid, num, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->read_tlb) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->read_tlb(aice->coreid, virtual_address, physical_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->cache_ctl) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->cache_ctl(aice->coreid, subtype, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_retry_times) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_retry_times(a_retry_times);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_program_edm(struct aice_port_s *aice, char *command_sequence)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->program_edm) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->program_edm(aice->coreid, command_sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_command_mode(struct aice_port_s *aice,
|
|
||||||
enum aice_command_mode command_mode)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_command_mode) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_command_mode(command_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
|
|
||||||
uint32_t instruction_num)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->execute) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->execute(aice->coreid, instructions, instruction_num);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_custom_srst_script) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_custom_srst_script(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_custom_trst_script) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_custom_trst_script(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_custom_restart_script) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_custom_restart_script(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->set_count_to_check_dbger) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->set_count_to_check_dbger(count_to_check);
|
|
||||||
}
|
|
||||||
|
|
||||||
int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration,
|
|
||||||
uint32_t reg_no, uint32_t *samples, uint32_t *num_samples)
|
|
||||||
{
|
|
||||||
if (!aice->port->api->profiling) {
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return aice->port->api->profiling(aice->coreid, interval, iteration,
|
|
||||||
reg_no, samples, num_samples);
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes technology. *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_AICE_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_AICE_H
|
|
||||||
|
|
||||||
#include <jtag/aice/aice_port.h>
|
|
||||||
|
|
||||||
int aice_read_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t *val);
|
|
||||||
int aice_write_reg_64(struct aice_port_s *aice, uint32_t num, uint64_t val);
|
|
||||||
int aice_read_tlb(struct aice_port_s *aice, target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address);
|
|
||||||
int aice_cache_ctl(struct aice_port_s *aice, uint32_t subtype, uint32_t address);
|
|
||||||
int aice_set_retry_times(struct aice_port_s *aice, uint32_t a_retry_times);
|
|
||||||
int aice_program_edm(struct aice_port_s *aice, char *command_sequence);
|
|
||||||
int aice_set_command_mode(struct aice_port_s *aice,
|
|
||||||
enum aice_command_mode command_mode);
|
|
||||||
int aice_execute(struct aice_port_s *aice, uint32_t *instructions,
|
|
||||||
uint32_t instruction_num);
|
|
||||||
int aice_set_custom_srst_script(struct aice_port_s *aice, const char *script);
|
|
||||||
int aice_set_custom_trst_script(struct aice_port_s *aice, const char *script);
|
|
||||||
int aice_set_custom_restart_script(struct aice_port_s *aice, const char *script);
|
|
||||||
int aice_set_count_to_check_dbger(struct aice_port_s *aice, uint32_t count_to_check);
|
|
||||||
int aice_profiling(struct aice_port_s *aice, uint32_t interval, uint32_t iteration,
|
|
||||||
uint32_t reg_no, uint32_t *samples, uint32_t *num_samples);
|
|
||||||
|
|
||||||
static inline int aice_open(struct aice_port_s *aice, struct aice_port_param_s *param)
|
|
||||||
{
|
|
||||||
return aice->port->api->open(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_close(struct aice_port_s *aice)
|
|
||||||
{
|
|
||||||
return aice->port->api->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_reset(struct aice_port_s *aice)
|
|
||||||
{
|
|
||||||
return aice->port->api->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_assert_srst(struct aice_port_s *aice,
|
|
||||||
enum aice_srst_type_s srst)
|
|
||||||
{
|
|
||||||
return aice->port->api->assert_srst(aice->coreid, srst);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_run(struct aice_port_s *aice)
|
|
||||||
{
|
|
||||||
return aice->port->api->run(aice->coreid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_halt(struct aice_port_s *aice)
|
|
||||||
{
|
|
||||||
return aice->port->api->halt(aice->coreid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_step(struct aice_port_s *aice)
|
|
||||||
{
|
|
||||||
return aice->port->api->step(aice->coreid);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_read_register(struct aice_port_s *aice, uint32_t num,
|
|
||||||
uint32_t *val)
|
|
||||||
{
|
|
||||||
return aice->port->api->read_reg(aice->coreid, num, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_write_register(struct aice_port_s *aice, uint32_t num,
|
|
||||||
uint32_t val)
|
|
||||||
{
|
|
||||||
return aice->port->api->write_reg(aice->coreid, num, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_read_debug_reg(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
uint32_t *val)
|
|
||||||
{
|
|
||||||
return aice->port->api->read_debug_reg(aice->coreid, addr, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_write_debug_reg(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
const uint32_t val)
|
|
||||||
{
|
|
||||||
return aice->port->api->write_debug_reg(aice->coreid, addr, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_read_mem_unit(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
return aice->port->api->read_mem_unit(aice->coreid, addr, size, count, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_write_mem_unit(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
return aice->port->api->write_mem_unit(aice->coreid, addr, size, count, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_read_mem_bulk(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
uint32_t length, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
return aice->port->api->read_mem_bulk(aice->coreid, addr, length, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_write_mem_bulk(struct aice_port_s *aice, uint32_t addr,
|
|
||||||
uint32_t length, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
return aice->port->api->write_mem_bulk(aice->coreid, addr, length, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_idcode(struct aice_port_s *aice, uint32_t *idcode,
|
|
||||||
uint8_t *num_of_idcode)
|
|
||||||
{
|
|
||||||
return aice->port->api->idcode(idcode, num_of_idcode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_state(struct aice_port_s *aice,
|
|
||||||
enum aice_target_state_s *state)
|
|
||||||
{
|
|
||||||
return aice->port->api->state(aice->coreid, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_set_jtag_clock(struct aice_port_s *aice, uint32_t a_clock)
|
|
||||||
{
|
|
||||||
return aice->port->api->set_jtag_clock(a_clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_memory_access(struct aice_port_s *aice,
|
|
||||||
enum nds_memory_access a_access)
|
|
||||||
{
|
|
||||||
return aice->port->api->memory_access(aice->coreid, a_access);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_memory_mode(struct aice_port_s *aice,
|
|
||||||
enum nds_memory_select mem_select)
|
|
||||||
{
|
|
||||||
return aice->port->api->memory_mode(aice->coreid, mem_select);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int aice_set_data_endian(struct aice_port_s *aice,
|
|
||||||
enum aice_target_endian target_data_endian)
|
|
||||||
{
|
|
||||||
return aice->port->api->set_data_endian(aice->coreid, target_data_endian);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_AICE_H */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_CMD_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_CMD_H
|
|
||||||
|
|
||||||
#include <helper/command.h>
|
|
||||||
|
|
||||||
extern const struct command_registration nds32_command_handlers[];
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_CMD_H */
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,45 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_DISASSEMBLER_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_DISASSEMBLER_H
|
|
||||||
|
|
||||||
#include <target/nds32.h>
|
|
||||||
|
|
||||||
enum nds32_instruction_type {
|
|
||||||
NDS32_INSN_DATA_PROC = 0,
|
|
||||||
NDS32_INSN_LOAD_STORE,
|
|
||||||
NDS32_INSN_JUMP_BRANCH,
|
|
||||||
NDS32_INSN_RESOURCE_ACCESS,
|
|
||||||
NDS32_INSN_MISC,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_instruction {
|
|
||||||
enum nds32_instruction_type type;
|
|
||||||
char text[128];
|
|
||||||
uint32_t opcode;
|
|
||||||
uint8_t instruction_size;
|
|
||||||
uint32_t access_start;
|
|
||||||
uint32_t access_end;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
uint8_t opc_6;
|
|
||||||
uint8_t rt;
|
|
||||||
uint8_t ra;
|
|
||||||
uint8_t rb;
|
|
||||||
uint8_t rd;
|
|
||||||
uint8_t sub_opc;
|
|
||||||
int32_t imm;
|
|
||||||
} info;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
int nds32_read_opcode(struct nds32 *nds32, uint32_t address, uint32_t *value);
|
|
||||||
int nds32_evaluate_opcode(struct nds32 *nds32, uint32_t opcode, uint32_t address,
|
|
||||||
struct nds32_instruction *instruction);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_DISASSEMBLER_H */
|
|
|
@ -1,106 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_EDM_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_EDM_H
|
|
||||||
|
|
||||||
#include "helper/types.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* This is the interface to the Embedded Debug Module for Andes cores.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* EDM misc registers */
|
|
||||||
enum nds_edm_misc_reg {
|
|
||||||
NDS_EDM_MISC_DIMIR = 0x0,
|
|
||||||
NDS_EDM_MISC_SBAR,
|
|
||||||
NDS_EDM_MISC_EDM_CMDR,
|
|
||||||
NDS_EDM_MISC_DBGER,
|
|
||||||
NDS_EDM_MISC_ACC_CTL,
|
|
||||||
NDS_EDM_MISC_EDM_PROBE,
|
|
||||||
NDS_EDM_MISC_GEN_PORT0,
|
|
||||||
NDS_EDM_MISC_GEN_PORT1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* EDM system registers */
|
|
||||||
enum nds_edm_system_reg {
|
|
||||||
NDS_EDM_SR_BPC0 = 0x00,
|
|
||||||
NDS_EDM_SR_BPC1,
|
|
||||||
NDS_EDM_SR_BPC2,
|
|
||||||
NDS_EDM_SR_BPC3,
|
|
||||||
NDS_EDM_SR_BPC4,
|
|
||||||
NDS_EDM_SR_BPC5,
|
|
||||||
NDS_EDM_SR_BPC6,
|
|
||||||
NDS_EDM_SR_BPC7,
|
|
||||||
NDS_EDM_SR_BPA0 = 0x08,
|
|
||||||
NDS_EDM_SR_BPA1,
|
|
||||||
NDS_EDM_SR_BPA2,
|
|
||||||
NDS_EDM_SR_BPA3,
|
|
||||||
NDS_EDM_SR_BPA4,
|
|
||||||
NDS_EDM_SR_BPA5,
|
|
||||||
NDS_EDM_SR_BPA6,
|
|
||||||
NDS_EDM_SR_BPA7,
|
|
||||||
NDS_EDM_SR_BPAM0 = 0x10,
|
|
||||||
NDS_EDM_SR_BPAM1,
|
|
||||||
NDS_EDM_SR_BPAM2,
|
|
||||||
NDS_EDM_SR_BPAM3,
|
|
||||||
NDS_EDM_SR_BPAM4,
|
|
||||||
NDS_EDM_SR_BPAM5,
|
|
||||||
NDS_EDM_SR_BPAM6,
|
|
||||||
NDS_EDM_SR_BPAM7,
|
|
||||||
NDS_EDM_SR_BPV0 = 0x18,
|
|
||||||
NDS_EDM_SR_BPV1,
|
|
||||||
NDS_EDM_SR_BPV2,
|
|
||||||
NDS_EDM_SR_BPV3,
|
|
||||||
NDS_EDM_SR_BPV4,
|
|
||||||
NDS_EDM_SR_BPV5,
|
|
||||||
NDS_EDM_SR_BPV6,
|
|
||||||
NDS_EDM_SR_BPV7,
|
|
||||||
NDS_EDM_SR_BPCID0 = 0x20,
|
|
||||||
NDS_EDM_SR_BPCID1,
|
|
||||||
NDS_EDM_SR_BPCID2,
|
|
||||||
NDS_EDM_SR_BPCID3,
|
|
||||||
NDS_EDM_SR_BPCID4,
|
|
||||||
NDS_EDM_SR_BPCID5,
|
|
||||||
NDS_EDM_SR_BPCID6,
|
|
||||||
NDS_EDM_SR_BPCID7,
|
|
||||||
NDS_EDM_SR_EDM_CFG = 0x28,
|
|
||||||
NDS_EDM_SR_EDMSW = 0x30,
|
|
||||||
NDS_EDM_SR_EDM_CTL = 0x38,
|
|
||||||
NDS_EDM_SR_EDM_DTR = 0x40,
|
|
||||||
NDS_EDM_SR_BPMTV = 0x48,
|
|
||||||
NDS_EDM_SR_DIMBR = 0x50,
|
|
||||||
NDS_EDM_SR_TECR0 = 0x70,
|
|
||||||
NDS_EDM_SR_TECR1 = 0x71,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum nds_memory_access {
|
|
||||||
NDS_MEMORY_ACC_BUS = 0,
|
|
||||||
NDS_MEMORY_ACC_CPU,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum nds_memory_select {
|
|
||||||
NDS_MEMORY_SELECT_AUTO = 0,
|
|
||||||
NDS_MEMORY_SELECT_MEM = 1,
|
|
||||||
NDS_MEMORY_SELECT_ILM = 2,
|
|
||||||
NDS_MEMORY_SELECT_DLM = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NDS_DBGER_DEX (0x1)
|
|
||||||
#define NDS_DBGER_DPED (0x2)
|
|
||||||
#define NDS_DBGER_CRST (0x4)
|
|
||||||
#define NDS_DBGER_AT_MAX (0x8)
|
|
||||||
#define NDS_DBGER_ILL_SEC_ACC (0x10)
|
|
||||||
#define NDS_DBGER_ALL_SUPRS_EX (0x40000000)
|
|
||||||
#define NDS_DBGER_RESACC (0x80000000)
|
|
||||||
#define NDS_DBGER_CLEAR_ALL (0x1F)
|
|
||||||
|
|
||||||
#define NDS_EDMSW_WDV (1 << 0)
|
|
||||||
#define NDS_EDMSW_RDV (1 << 1)
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_EDM_H */
|
|
|
@ -1,67 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_INSN_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_INSN_H
|
|
||||||
|
|
||||||
#define NOP (0x40000009)
|
|
||||||
#define DSB (0x64000008)
|
|
||||||
#define ISB (0x64000009)
|
|
||||||
#define BEQ_MINUS_12 (0x4C000000 | 0x3FFA)
|
|
||||||
#define MTSR_DTR(a) (0x64000003 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
|
|
||||||
#define MFSR_DTR(a) (0x64000002 | (((0x03 << 7) | (0x08 << 3) | (0x00 << 0)) << 10) | (((a) & 0x1F) << 20))
|
|
||||||
#define SETHI(a, b) (0x46000000 | ((a) << 20) | (b))
|
|
||||||
#define ORI(a, b, c) (0x58000000 | ((a) << 20) | ((b) << 15) | (c))
|
|
||||||
#define LWI_BI(a, b) (0x0C000001 | (a << 20) | (b << 15))
|
|
||||||
#define LHI_BI(a, b) (0x0A000001 | (a << 20) | (b << 15))
|
|
||||||
#define LBI_BI(a, b) (0x08000001 | (a << 20) | (b << 15))
|
|
||||||
#define SWI_BI(a, b) (0x1C000001 | (a << 20) | (b << 15))
|
|
||||||
#define SHI_BI(a, b) (0x1A000001 | (a << 20) | (b << 15))
|
|
||||||
#define SBI_BI(a, b) (0x18000001 | (a << 20) | (b << 15))
|
|
||||||
#define IRET (0x64000004)
|
|
||||||
#define L1D_IX_WB(a) (0x64000021 | ((a) << 15))
|
|
||||||
#define L1D_IX_INVAL(a) (0x64000001 | ((a) << 15))
|
|
||||||
#define L1D_VA_INVAL(a) (0x64000101 | ((a) << 15))
|
|
||||||
#define L1D_VA_WB(a) (0x64000121 | ((a) << 15))
|
|
||||||
#define L1D_IX_RTAG(a) (0x64000061 | ((a) << 15))
|
|
||||||
#define L1D_IX_RWD(a) (0x64000081 | ((a) << 15))
|
|
||||||
#define L1I_IX_INVAL(a) (0x64000201 | ((a) << 15))
|
|
||||||
#define L1I_VA_INVAL(a) (0x64000301 | ((a) << 15))
|
|
||||||
#define L1I_IX_RTAG(a) (0x64000261 | ((a) << 15))
|
|
||||||
#define L1I_IX_RWD(a) (0x64000281 | ((a) << 15))
|
|
||||||
#define L1I_VA_FILLCK(a) (0x64000361 | ((a) << 15))
|
|
||||||
#define ISYNC(a) (0x6400000d | ((a) << 20))
|
|
||||||
#define MSYNC_STORE (0x6400002c)
|
|
||||||
#define MSYNC_ALL (0x6400000c)
|
|
||||||
#define TLBOP_TARGET_READ(a) (0x6400000e | ((a) << 15))
|
|
||||||
#define TLBOP_TARGET_PROBE(a, b) (0x640000AE | ((a) << 20) | ((b) << 15))
|
|
||||||
#define MFCPD(a, b, c) (0x6A000041 | (a << 20) | (b << 8) | (c << 4))
|
|
||||||
#define MFCPW(a, b, c) (0x6A000001 | (a << 20) | (b << 8) | (c << 4))
|
|
||||||
#define MTCPD(a, b, c) (0x6A000049 | (a << 20) | (b << 8) | (c << 4))
|
|
||||||
#define MTCPW(a, b, c) (0x6A000009 | (a << 20) | (b << 8) | (c << 4))
|
|
||||||
#define MOVI_(a, b) (0x44000000 | (a << 20) | (b & 0xFFFFF))
|
|
||||||
#define MFUSR_G0(a, b) (0x42000020 | (a << 20) | (b << 15))
|
|
||||||
#define MTUSR_G0(a, b) (0x42000021 | (a << 20) | (b << 15))
|
|
||||||
#define MFSR(a, b) (0x64000002 | (b << 10) | (a << 20))
|
|
||||||
#define MTSR(a, b) (0x64000003 | (b << 10) | (a << 20))
|
|
||||||
#define AMFAR(a, b) (0x60300060 | (a << 15) | b)
|
|
||||||
#define AMTAR(a, b) (0x60300040 | (a << 15) | b)
|
|
||||||
#define AMFAR2(a, b) (0x60300260 | (a << 15) | b)
|
|
||||||
#define AMTAR2(a, b) (0x60300240 | (a << 15) | b)
|
|
||||||
#define FMFCSR (0x6A000701)
|
|
||||||
#define FMTCSR (0x6A000709)
|
|
||||||
#define FMFCFG (0x6A000301)
|
|
||||||
#define FMFSR(a, b) (0x6A000001 | ((a) << 20) | ((b) << 15))
|
|
||||||
#define FMTSR(a, b) (0x6A000009 | ((a) << 20) | ((b) << 15))
|
|
||||||
#define FMFDR(a, b) (0x6A000041 | ((a) << 20) | ((b) << 15))
|
|
||||||
#define FMTDR(a, b) (0x6A000049 | ((a) << 20) | ((b) << 15))
|
|
||||||
|
|
||||||
/* break instructions */
|
|
||||||
#define NDS32_BREAK_16 (0x00EA)
|
|
||||||
#define NDS32_BREAK_32 (0x0A000064)
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_INSN_H */
|
|
|
@ -1,369 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/log.h>
|
|
||||||
#include "nds32_reg.h"
|
|
||||||
|
|
||||||
static bool nds32_reg_init_done;
|
|
||||||
static struct nds32_reg_s nds32_regs[TOTAL_REG_NUM];
|
|
||||||
static const struct nds32_reg_exception_s nds32_ex_reg_values[] = {
|
|
||||||
{IR0, 3, 0x3, 2},
|
|
||||||
{IR0, 3, 0x3, 3},
|
|
||||||
{IR1, 3, 0x3, 2},
|
|
||||||
{IR1, 3, 0x3, 3},
|
|
||||||
{IR2, 3, 0x3, 2},
|
|
||||||
{IR2, 3, 0x3, 3},
|
|
||||||
{MR3, 1, 0x7, 0},
|
|
||||||
{MR3, 1, 0x7, 4},
|
|
||||||
{MR3, 1, 0x7, 6},
|
|
||||||
{MR3, 8, 0x7, 3},
|
|
||||||
{0, 0, 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void nds32_reg_set(uint32_t number, const char *simple_mnemonic,
|
|
||||||
const char *symbolic_mnemonic, uint32_t sr_index,
|
|
||||||
enum nds32_reg_type_s type, uint8_t size)
|
|
||||||
{
|
|
||||||
nds32_regs[number].simple_mnemonic = simple_mnemonic;
|
|
||||||
nds32_regs[number].symbolic_mnemonic = symbolic_mnemonic;
|
|
||||||
nds32_regs[number].sr_index = sr_index;
|
|
||||||
nds32_regs[number].type = type;
|
|
||||||
nds32_regs[number].size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nds32_reg_init(void)
|
|
||||||
{
|
|
||||||
if (nds32_reg_init_done == true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
nds32_reg_set(R0, "r0", "r0", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R1, "r1", "r1", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R2, "r2", "r2", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R3, "r3", "r3", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R4, "r4", "r4", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R5, "r5", "r5", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R6, "r6", "r6", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R7, "r7", "r7", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R8, "r8", "r8", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R9, "r9", "r9", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R10, "r10", "r10", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R11, "r11", "r11", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R12, "r12", "r12", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R13, "r13", "r13", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R14, "r14", "r14", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R15, "r15", "r15", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R16, "r16", "r16", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R17, "r17", "r17", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R18, "r18", "r18", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R19, "r19", "r19", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R20, "r20", "r20", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R21, "r21", "r21", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R22, "r22", "r22", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R23, "r23", "r23", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R24, "r24", "r24", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R25, "r25", "r25", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R26, "r26", "p0", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R27, "r27", "p1", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R28, "fp", "fp", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R29, "gp", "gp", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R30, "lp", "lp", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(R31, "sp", "sp", 0, NDS32_REG_TYPE_GPR, 32);
|
|
||||||
nds32_reg_set(PC, "pc", "pc", 31, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(D0LO, "d0lo", "d0lo", 0, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
nds32_reg_set(D0HI, "d0hi", "d0hi", 1, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
nds32_reg_set(D1LO, "d1lo", "d1lo", 2, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
nds32_reg_set(D1HI, "d1hi", "d1hi", 3, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
nds32_reg_set(ITB, "itb", "itb", 28, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
nds32_reg_set(IFC_LP, "ifc_lp", "ifc_lp", 29, NDS32_REG_TYPE_SPR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(CR0, "cr0", "CPU_VER", SRIDX(0, 0, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR1, "cr1", "ICM_CFG", SRIDX(0, 1, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR2, "cr2", "DCM_CFG", SRIDX(0, 2, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR3, "cr3", "MMU_CFG", SRIDX(0, 3, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR4, "cr4", "MSC_CFG", SRIDX(0, 4, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR5, "cr5", "CORE_ID", SRIDX(0, 0, 1), NDS32_REG_TYPE_CR, 32);
|
|
||||||
nds32_reg_set(CR6, "cr6", "FUCOP_EXIST", SRIDX(0, 5, 0), NDS32_REG_TYPE_CR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(IR0, "ir0", "PSW", SRIDX(1, 0, 0), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR1, "ir1", "IPSW", SRIDX(1, 0, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR2, "ir2", "P_IPSW", SRIDX(1, 0, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR3, "ir3", "IVB", SRIDX(1, 1, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR4, "ir4", "EVA", SRIDX(1, 2, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR5, "ir5", "P_EVA", SRIDX(1, 2, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR6, "ir6", "ITYPE", SRIDX(1, 3, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR7, "ir7", "P_ITYPE", SRIDX(1, 3, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR8, "ir8", "MERR", SRIDX(1, 4, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR9, "ir9", "IPC", SRIDX(1, 5, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR10, "ir10", "P_IPC", SRIDX(1, 5, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR11, "ir11", "OIPC", SRIDX(1, 5, 3), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR12, "ir12", "P_P0", SRIDX(1, 6, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR13, "ir13", "P_P1", SRIDX(1, 7, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR14, "ir14", "INT_MASK", SRIDX(1, 8, 0), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR15, "ir15", "INT_PEND", SRIDX(1, 9, 0), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR16, "ir16", "", SRIDX(1, 10, 0), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR17, "ir17", "", SRIDX(1, 10, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR18, "ir18", "", SRIDX(1, 11, 0), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR19, "ir19", "", SRIDX(1, 1, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR20, "ir20", "", SRIDX(1, 10, 2), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR21, "ir21", "", SRIDX(1, 10, 3), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR22, "ir22", "", SRIDX(1, 10, 4), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR23, "ir23", "", SRIDX(1, 10, 5), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR24, "ir24", "", SRIDX(1, 10, 6), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR25, "ir25", "", SRIDX(1, 10, 7), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR26, "ir26", "", SRIDX(1, 8, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR27, "ir27", "", SRIDX(1, 9, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR28, "ir28", "", SRIDX(1, 11, 1), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR29, "ir29", "", SRIDX(1, 9, 4), NDS32_REG_TYPE_IR, 32);
|
|
||||||
nds32_reg_set(IR30, "ir30", "", SRIDX(1, 1, 3), NDS32_REG_TYPE_IR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(MR0, "mr0", "MMU_CTL", SRIDX(2, 0, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR1, "mr1", "L1_PPTB", SRIDX(2, 1, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR2, "mr2", "TLB_VPN", SRIDX(2, 2, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR3, "mr3", "TLB_DATA", SRIDX(2, 3, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR4, "mr4", "TLB_MISC", SRIDX(2, 4, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR5, "mr5", "VLPT_IDX", SRIDX(2, 5, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR6, "mr6", "ILMB", SRIDX(2, 6, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR7, "mr7", "DLMB", SRIDX(2, 7, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR8, "mr8", "CACHE_CTL", SRIDX(2, 8, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR9, "mr9", "HSMP_SADDR", SRIDX(2, 9, 0), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR10, "mr10", "HSMP_EADDR", SRIDX(2, 9, 1), NDS32_REG_TYPE_MR, 32);
|
|
||||||
nds32_reg_set(MR11, "mr11", "", SRIDX(2, 0, 1), NDS32_REG_TYPE_MR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(DR0, "dr0", "BPC0", SRIDX(3, 0, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR1, "dr1", "BPA0", SRIDX(3, 1, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR2, "dr2", "BPAM0", SRIDX(3, 2, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR3, "dr3", "BPV0", SRIDX(3, 3, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR4, "dr4", "BPCID0", SRIDX(3, 4, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR5, "dr5", "BPC1", SRIDX(3, 0, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR6, "dr6", "BPA1", SRIDX(3, 1, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR7, "dr7", "BPAM1", SRIDX(3, 2, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR8, "dr8", "BPV1", SRIDX(3, 3, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR9, "dr9", "BPCID1", SRIDX(3, 4, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR10, "dr10", "BPC2", SRIDX(3, 0, 2), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR11, "dr11", "BPA2", SRIDX(3, 1, 2), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR12, "dr12", "BPAM2", SRIDX(3, 2, 2), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR13, "dr13", "BPV2", SRIDX(3, 3, 2), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR14, "dr14", "BPCID2", SRIDX(3, 4, 2), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR15, "dr15", "BPC3", SRIDX(3, 0, 3), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR16, "dr16", "BPA3", SRIDX(3, 1, 3), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR17, "dr17", "BPAM3", SRIDX(3, 2, 3), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR18, "dr18", "BPV3", SRIDX(3, 3, 3), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR19, "dr19", "BPCID3", SRIDX(3, 4, 3), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR20, "dr20", "BPC4", SRIDX(3, 0, 4), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR21, "dr21", "BPA4", SRIDX(3, 1, 4), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR22, "dr22", "BPAM4", SRIDX(3, 2, 4), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR23, "dr23", "BPV4", SRIDX(3, 3, 4), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR24, "dr24", "BPCID4", SRIDX(3, 4, 4), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR25, "dr25", "BPC5", SRIDX(3, 0, 5), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR26, "dr26", "BPA5", SRIDX(3, 1, 5), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR27, "dr27", "BPAM5", SRIDX(3, 2, 5), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR28, "dr28", "BPV5", SRIDX(3, 3, 5), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR29, "dr29", "BPCID5", SRIDX(3, 4, 5), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR30, "dr30", "BPC6", SRIDX(3, 0, 6), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR31, "dr31", "BPA6", SRIDX(3, 1, 6), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR32, "dr32", "BPAM6", SRIDX(3, 2, 6), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR33, "dr33", "BPV6", SRIDX(3, 3, 6), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR34, "dr34", "BPCID6", SRIDX(3, 4, 6), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR35, "dr35", "BPC7", SRIDX(3, 0, 7), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR36, "dr36", "BPA7", SRIDX(3, 1, 7), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR37, "dr37", "BPAM7", SRIDX(3, 2, 7), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR38, "dr38", "BPV7", SRIDX(3, 3, 7), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR39, "dr39", "BPCID7", SRIDX(3, 4, 7), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR40, "dr40", "EDM_CFG", SRIDX(3, 5, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR41, "dr41", "EDMSW", SRIDX(3, 6, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR42, "dr42", "EDM_CTL", SRIDX(3, 7, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR43, "dr43", "EDM_DTR", SRIDX(3, 8, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR44, "dr44", "BPMTC", SRIDX(3, 9, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR45, "dr45", "DIMBR", SRIDX(3, 10, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR46, "dr46", "TECR0", SRIDX(3, 14, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR47, "dr47", "TECR1", SRIDX(3, 14, 1), NDS32_REG_TYPE_DR, 32);
|
|
||||||
nds32_reg_set(DR48, "dr48", "", SRIDX(3, 11, 0), NDS32_REG_TYPE_DR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(PFR0, "pfr0", "PFMC0", SRIDX(4, 0, 0), NDS32_REG_TYPE_PFR, 32);
|
|
||||||
nds32_reg_set(PFR1, "pfr1", "PFMC1", SRIDX(4, 0, 1), NDS32_REG_TYPE_PFR, 32);
|
|
||||||
nds32_reg_set(PFR2, "pfr2", "PFMC2", SRIDX(4, 0, 2), NDS32_REG_TYPE_PFR, 32);
|
|
||||||
nds32_reg_set(PFR3, "pfr3", "PFM_CTL", SRIDX(4, 1, 0), NDS32_REG_TYPE_PFR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(DMAR0, "dmar0", "DMA_CFG", SRIDX(5, 0, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR1, "dmar1", "DMA_GCSW", SRIDX(5, 1, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR2, "dmar2", "DMA_CHNSEL", SRIDX(5, 2, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR3, "dmar3", "DMA_ACT", SRIDX(5, 3, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR4, "dmar4", "DMA_SETUP", SRIDX(5, 4, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR5, "dmar5", "DMA_ISADDR", SRIDX(5, 5, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR6, "dmar6", "DMA_ESADDR", SRIDX(5, 6, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR7, "dmar7", "DMA_TCNT", SRIDX(5, 7, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR8, "dmar8", "DMA_STATUS", SRIDX(5, 8, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR9, "dmar9", "DMA_2DSET", SRIDX(5, 9, 0), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
nds32_reg_set(DMAR10, "dmar10", "DMA_2DSCTL", SRIDX(5, 9, 1), NDS32_REG_TYPE_DMAR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(RACR, "racr", "PRUSR_ACC_CTL", SRIDX(4, 4, 0), NDS32_REG_TYPE_RACR, 32);
|
|
||||||
nds32_reg_set(FUCPR, "fucpr", "FUCOP_CTL", SRIDX(4, 5, 0), NDS32_REG_TYPE_RACR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(IDR0, "idr0", "SDZ_CTL", SRIDX(2, 15, 0), NDS32_REG_TYPE_IDR, 32);
|
|
||||||
nds32_reg_set(IDR1, "idr1", "MISC_CTL", SRIDX(2, 15, 1), NDS32_REG_TYPE_IDR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(SECUR0, "secur0", "", SRIDX(6, 0, 0), NDS32_REG_TYPE_SECURE, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(D0L24, "D0L24", "D0L24", 0x10, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(D1L24, "D1L24", "D1L24", 0x11, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I0, "I0", "I0", 0x0, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I1, "I1", "I1", 0x1, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I2, "I2", "I2", 0x2, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I3, "I3", "I3", 0x3, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I4, "I4", "I4", 0x4, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I5, "I5", "I5", 0x5, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I6, "I6", "I6", 0x6, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(I7, "I7", "I7", 0x7, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M1, "M1", "M1", 0x9, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M2, "M2", "M2", 0xA, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M3, "M3", "M3", 0xB, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M5, "M5", "M5", 0xD, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M6, "M6", "M6", 0xE, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(M7, "M7", "M7", 0xF, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(MOD, "MOD", "MOD", 0x8, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(LBE, "LBE", "LBE", 0x18, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(LE, "LE", "LE", 0x19, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(LC, "LC", "LC", 0x1A, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(ADM_VBASE, "ADM_VBASE", "ADM_VBASE", 0x1B, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(SHFT_CTL0, "SHFT_CTL0", "SHFT_CTL0", 0x12, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(SHFT_CTL1, "SHFT_CTL1", "SHFT_CTL1", 0x13, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(CB_CTL, "CB_CTL", "CB_CTL", 0x1F, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBB0, "CBB0", "CBB0", 0x0, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBB1, "CBB1", "CBB1", 0x1, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBB2, "CBB2", "CBB2", 0x2, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBB3, "CBB3", "CBB3", 0x3, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBE0, "CBE0", "CBE0", 0x4, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBE1, "CBE1", "CBE1", 0x5, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBE2, "CBE2", "CBE2", 0x6, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
nds32_reg_set(CBE3, "CBE3", "CBE3", 0x7, NDS32_REG_TYPE_AUMR, 32);
|
|
||||||
|
|
||||||
nds32_reg_set(FPCSR, "fpcsr", "FPCSR", 0x7, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FPCFG, "fpcfg", "FPCFG", 0x7, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS0, "fs0", "FS0", 0, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS1, "fs1", "FS1", 1, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS2, "fs2", "FS2", 2, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS3, "fs3", "FS3", 3, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS4, "fs4", "FS4", 4, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS5, "fs5", "FS5", 5, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS6, "fs6", "FS6", 6, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS7, "fs7", "FS7", 7, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS8, "fs8", "FS8", 8, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS9, "fs9", "FS9", 9, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS10, "fs10", "FS10", 10, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS11, "fs11", "FS11", 11, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS12, "fs12", "FS12", 12, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS13, "fs13", "FS13", 13, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS14, "fs14", "FS14", 14, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS15, "fs15", "FS15", 15, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS16, "fs16", "FS16", 16, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS17, "fs17", "FS17", 17, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS18, "fs18", "FS18", 18, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS19, "fs19", "FS19", 19, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS20, "fs20", "FS20", 20, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS21, "fs21", "FS21", 21, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS22, "fs22", "FS22", 22, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS23, "fs23", "FS23", 23, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS24, "fs24", "FS24", 24, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS25, "fs25", "FS25", 25, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS26, "fs26", "FS26", 26, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS27, "fs27", "FS27", 27, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS28, "fs28", "FS28", 28, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS29, "fs29", "FS29", 29, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS30, "fs30", "FS30", 30, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FS31, "fs31", "FS31", 31, NDS32_REG_TYPE_FPU, 32);
|
|
||||||
nds32_reg_set(FD0, "fd0", "FD0", 0, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD1, "fd1", "FD1", 1, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD2, "fd2", "FD2", 2, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD3, "fd3", "FD3", 3, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD4, "fd4", "FD4", 4, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD5, "fd5", "FD5", 5, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD6, "fd6", "FD6", 6, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD7, "fd7", "FD7", 7, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD8, "fd8", "FD8", 8, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD9, "fd9", "FD9", 9, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD10, "fd10", "FD10", 10, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD11, "fd11", "FD11", 11, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD12, "fd12", "FD12", 12, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD13, "fd13", "FD13", 13, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD14, "fd14", "FD14", 14, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD15, "fd15", "FD15", 15, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD16, "fd16", "FD16", 16, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD17, "fd17", "FD17", 17, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD18, "fd18", "FD18", 18, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD19, "fd19", "FD19", 19, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD20, "fd20", "FD20", 20, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD21, "fd21", "FD21", 21, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD22, "fd22", "FD22", 22, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD23, "fd23", "FD23", 23, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD24, "fd24", "FD24", 24, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD25, "fd25", "FD25", 25, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD26, "fd26", "FD26", 26, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD27, "fd27", "FD27", 27, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD28, "fd28", "FD28", 28, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD29, "fd29", "FD29", 29, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD30, "fd30", "FD30", 30, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
nds32_reg_set(FD31, "fd31", "FD31", 31, NDS32_REG_TYPE_FPU, 64);
|
|
||||||
|
|
||||||
nds32_reg_init_done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t nds32_reg_sr_index(uint32_t number)
|
|
||||||
{
|
|
||||||
return nds32_regs[number].sr_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum nds32_reg_type_s nds32_reg_type(uint32_t number)
|
|
||||||
{
|
|
||||||
return nds32_regs[number].type;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t nds32_reg_size(uint32_t number)
|
|
||||||
{
|
|
||||||
return nds32_regs[number].size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *nds32_reg_simple_name(uint32_t number)
|
|
||||||
{
|
|
||||||
return nds32_regs[number].simple_mnemonic;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *nds32_reg_symbolic_name(uint32_t number)
|
|
||||||
{
|
|
||||||
return nds32_regs[number].symbolic_mnemonic;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nds32_reg_exception(uint32_t number, uint32_t value)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const struct nds32_reg_exception_s *ex_reg_value;
|
|
||||||
uint32_t field_value;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
while (nds32_ex_reg_values[i].reg_num != 0) {
|
|
||||||
ex_reg_value = nds32_ex_reg_values + i;
|
|
||||||
|
|
||||||
if (ex_reg_value->reg_num == number) {
|
|
||||||
field_value = (value >> ex_reg_value->ex_value_bit_pos) &
|
|
||||||
ex_reg_value->ex_value_mask;
|
|
||||||
if (field_value == ex_reg_value->ex_value) {
|
|
||||||
LOG_WARNING("It will generate exceptions as setting %" PRIu32 " to %s",
|
|
||||||
value, nds32_regs[number].simple_mnemonic);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,314 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_REG_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_REG_H
|
|
||||||
|
|
||||||
#define SRIDX(a, b, c) ((a << 7) | (b << 3) | c)
|
|
||||||
#define NDS32_REGISTER_DISABLE (0x0)
|
|
||||||
|
|
||||||
enum nds32_reg_number_s {
|
|
||||||
R0 = 0, /* general registers */
|
|
||||||
R1,
|
|
||||||
R2,
|
|
||||||
R3,
|
|
||||||
R4,
|
|
||||||
R5,
|
|
||||||
R6,
|
|
||||||
R7,
|
|
||||||
R8,
|
|
||||||
R9,
|
|
||||||
R10,
|
|
||||||
R11,
|
|
||||||
R12,
|
|
||||||
R13,
|
|
||||||
R14,
|
|
||||||
R15,
|
|
||||||
R16,
|
|
||||||
R17,
|
|
||||||
R18,
|
|
||||||
R19,
|
|
||||||
R20,
|
|
||||||
R21,
|
|
||||||
R22,
|
|
||||||
R23,
|
|
||||||
R24,
|
|
||||||
R25,
|
|
||||||
R26,
|
|
||||||
R27,
|
|
||||||
R28,
|
|
||||||
R29,
|
|
||||||
R30,
|
|
||||||
R31,
|
|
||||||
PC,
|
|
||||||
D0LO,
|
|
||||||
D0HI,
|
|
||||||
D1LO,
|
|
||||||
D1HI,
|
|
||||||
ITB,
|
|
||||||
IFC_LP,
|
|
||||||
CR0, /* system registers */
|
|
||||||
CR1,
|
|
||||||
CR2,
|
|
||||||
CR3,
|
|
||||||
CR4,
|
|
||||||
CR5,
|
|
||||||
CR6,
|
|
||||||
IR0,
|
|
||||||
IR1,
|
|
||||||
IR2,
|
|
||||||
IR3,
|
|
||||||
IR4,
|
|
||||||
IR5,
|
|
||||||
IR6,
|
|
||||||
IR7,
|
|
||||||
IR8,
|
|
||||||
IR9,
|
|
||||||
IR10,
|
|
||||||
IR11,
|
|
||||||
IR12,
|
|
||||||
IR13,
|
|
||||||
IR14,
|
|
||||||
IR15,
|
|
||||||
IR16,
|
|
||||||
IR17,
|
|
||||||
IR18,
|
|
||||||
IR19,
|
|
||||||
IR20,
|
|
||||||
IR21,
|
|
||||||
IR22,
|
|
||||||
IR23,
|
|
||||||
IR24,
|
|
||||||
IR25,
|
|
||||||
IR26,
|
|
||||||
IR27,
|
|
||||||
IR28,
|
|
||||||
IR29,
|
|
||||||
IR30,
|
|
||||||
MR0,
|
|
||||||
MR1,
|
|
||||||
MR2,
|
|
||||||
MR3,
|
|
||||||
MR4,
|
|
||||||
MR5,
|
|
||||||
MR6,
|
|
||||||
MR7,
|
|
||||||
MR8,
|
|
||||||
MR9,
|
|
||||||
MR10,
|
|
||||||
MR11,
|
|
||||||
DR0,
|
|
||||||
DR1,
|
|
||||||
DR2,
|
|
||||||
DR3,
|
|
||||||
DR4,
|
|
||||||
DR5,
|
|
||||||
DR6,
|
|
||||||
DR7,
|
|
||||||
DR8,
|
|
||||||
DR9,
|
|
||||||
DR10,
|
|
||||||
DR11,
|
|
||||||
DR12,
|
|
||||||
DR13,
|
|
||||||
DR14,
|
|
||||||
DR15,
|
|
||||||
DR16,
|
|
||||||
DR17,
|
|
||||||
DR18,
|
|
||||||
DR19,
|
|
||||||
DR20,
|
|
||||||
DR21,
|
|
||||||
DR22,
|
|
||||||
DR23,
|
|
||||||
DR24,
|
|
||||||
DR25,
|
|
||||||
DR26,
|
|
||||||
DR27,
|
|
||||||
DR28,
|
|
||||||
DR29,
|
|
||||||
DR30,
|
|
||||||
DR31,
|
|
||||||
DR32,
|
|
||||||
DR33,
|
|
||||||
DR34,
|
|
||||||
DR35,
|
|
||||||
DR36,
|
|
||||||
DR37,
|
|
||||||
DR38,
|
|
||||||
DR39,
|
|
||||||
DR40,
|
|
||||||
DR41,
|
|
||||||
DR42,
|
|
||||||
DR43,
|
|
||||||
DR44,
|
|
||||||
DR45,
|
|
||||||
DR46,
|
|
||||||
DR47,
|
|
||||||
DR48,
|
|
||||||
PFR0,
|
|
||||||
PFR1,
|
|
||||||
PFR2,
|
|
||||||
PFR3,
|
|
||||||
DMAR0,
|
|
||||||
DMAR1,
|
|
||||||
DMAR2,
|
|
||||||
DMAR3,
|
|
||||||
DMAR4,
|
|
||||||
DMAR5,
|
|
||||||
DMAR6,
|
|
||||||
DMAR7,
|
|
||||||
DMAR8,
|
|
||||||
DMAR9,
|
|
||||||
DMAR10,
|
|
||||||
RACR,
|
|
||||||
FUCPR,
|
|
||||||
IDR0,
|
|
||||||
IDR1,
|
|
||||||
SECUR0,
|
|
||||||
D0L24, /* audio registers */
|
|
||||||
D1L24,
|
|
||||||
I0,
|
|
||||||
I1,
|
|
||||||
I2,
|
|
||||||
I3,
|
|
||||||
I4,
|
|
||||||
I5,
|
|
||||||
I6,
|
|
||||||
I7,
|
|
||||||
M1,
|
|
||||||
M2,
|
|
||||||
M3,
|
|
||||||
M5,
|
|
||||||
M6,
|
|
||||||
M7,
|
|
||||||
MOD,
|
|
||||||
LBE,
|
|
||||||
LE,
|
|
||||||
LC,
|
|
||||||
ADM_VBASE,
|
|
||||||
SHFT_CTL0,
|
|
||||||
SHFT_CTL1,
|
|
||||||
CB_CTL,
|
|
||||||
CBB0,
|
|
||||||
CBB1,
|
|
||||||
CBB2,
|
|
||||||
CBB3,
|
|
||||||
CBE0,
|
|
||||||
CBE1,
|
|
||||||
CBE2,
|
|
||||||
CBE3,
|
|
||||||
FPCSR, /* fpu */
|
|
||||||
FPCFG,
|
|
||||||
FS0,
|
|
||||||
FS1,
|
|
||||||
FS2,
|
|
||||||
FS3,
|
|
||||||
FS4,
|
|
||||||
FS5,
|
|
||||||
FS6,
|
|
||||||
FS7,
|
|
||||||
FS8,
|
|
||||||
FS9,
|
|
||||||
FS10,
|
|
||||||
FS11,
|
|
||||||
FS12,
|
|
||||||
FS13,
|
|
||||||
FS14,
|
|
||||||
FS15,
|
|
||||||
FS16,
|
|
||||||
FS17,
|
|
||||||
FS18,
|
|
||||||
FS19,
|
|
||||||
FS20,
|
|
||||||
FS21,
|
|
||||||
FS22,
|
|
||||||
FS23,
|
|
||||||
FS24,
|
|
||||||
FS25,
|
|
||||||
FS26,
|
|
||||||
FS27,
|
|
||||||
FS28,
|
|
||||||
FS29,
|
|
||||||
FS30,
|
|
||||||
FS31,
|
|
||||||
FD0,
|
|
||||||
FD1,
|
|
||||||
FD2,
|
|
||||||
FD3,
|
|
||||||
FD4,
|
|
||||||
FD5,
|
|
||||||
FD6,
|
|
||||||
FD7,
|
|
||||||
FD8,
|
|
||||||
FD9,
|
|
||||||
FD10,
|
|
||||||
FD11,
|
|
||||||
FD12,
|
|
||||||
FD13,
|
|
||||||
FD14,
|
|
||||||
FD15,
|
|
||||||
FD16,
|
|
||||||
FD17,
|
|
||||||
FD18,
|
|
||||||
FD19,
|
|
||||||
FD20,
|
|
||||||
FD21,
|
|
||||||
FD22,
|
|
||||||
FD23,
|
|
||||||
FD24,
|
|
||||||
FD25,
|
|
||||||
FD26,
|
|
||||||
FD27,
|
|
||||||
FD28,
|
|
||||||
FD29,
|
|
||||||
FD30,
|
|
||||||
FD31,
|
|
||||||
|
|
||||||
TOTAL_REG_NUM,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum nds32_reg_type_s {
|
|
||||||
NDS32_REG_TYPE_GPR = 0,
|
|
||||||
NDS32_REG_TYPE_SPR,
|
|
||||||
NDS32_REG_TYPE_CR,
|
|
||||||
NDS32_REG_TYPE_IR,
|
|
||||||
NDS32_REG_TYPE_MR,
|
|
||||||
NDS32_REG_TYPE_DR,
|
|
||||||
NDS32_REG_TYPE_PFR,
|
|
||||||
NDS32_REG_TYPE_DMAR,
|
|
||||||
NDS32_REG_TYPE_RACR,
|
|
||||||
NDS32_REG_TYPE_IDR,
|
|
||||||
NDS32_REG_TYPE_AUMR,
|
|
||||||
NDS32_REG_TYPE_SECURE,
|
|
||||||
NDS32_REG_TYPE_FPU,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_reg_s {
|
|
||||||
const char *simple_mnemonic;
|
|
||||||
const char *symbolic_mnemonic;
|
|
||||||
uint32_t sr_index;
|
|
||||||
enum nds32_reg_type_s type;
|
|
||||||
uint8_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nds32_reg_exception_s {
|
|
||||||
uint32_t reg_num;
|
|
||||||
uint32_t ex_value_bit_pos;
|
|
||||||
uint32_t ex_value_mask;
|
|
||||||
uint32_t ex_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
void nds32_reg_init(void);
|
|
||||||
uint32_t nds32_reg_sr_index(uint32_t number);
|
|
||||||
enum nds32_reg_type_s nds32_reg_type(uint32_t number);
|
|
||||||
uint8_t nds32_reg_size(uint32_t number);
|
|
||||||
const char *nds32_reg_simple_name(uint32_t number);
|
|
||||||
const char *nds32_reg_symbolic_name(uint32_t number);
|
|
||||||
bool nds32_reg_exception(uint32_t number, uint32_t value);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_REG_H */
|
|
|
@ -1,67 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
#include "nds32_tlb.h"
|
|
||||||
|
|
||||||
int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address)
|
|
||||||
{
|
|
||||||
struct target *target = nds32->target;
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
|
|
||||||
return aice_read_tlb(aice, virtual_address, physical_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = {
|
|
||||||
/* 4K page */
|
|
||||||
{0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000},
|
|
||||||
/* 8K page */
|
|
||||||
{0xFF000000, 22, 0x00FFE000, 11, 0x00001FFF, 0xFFFFF000, 0xFFFFE000, 0xFFFFE000},
|
|
||||||
};
|
|
||||||
|
|
||||||
int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address)
|
|
||||||
{
|
|
||||||
struct target *target = nds32->target;
|
|
||||||
uint32_t value_mr1;
|
|
||||||
uint32_t load_address;
|
|
||||||
uint32_t l1_page_table_entry;
|
|
||||||
uint32_t l2_page_table_entry;
|
|
||||||
uint32_t page_size_index = nds32->mmu_config.default_min_page_size;
|
|
||||||
struct page_table_walker_info_s *page_table_info_p =
|
|
||||||
&(page_table_info[page_size_index]);
|
|
||||||
|
|
||||||
/* Read L1 Physical Page Table */
|
|
||||||
nds32_get_mapped_reg(nds32, MR1, &value_mr1);
|
|
||||||
load_address = (value_mr1 & page_table_info_p->l1_base_mask) |
|
|
||||||
((virtual_address & page_table_info_p->l1_offset_mask) >>
|
|
||||||
page_table_info_p->l1_offset_shift);
|
|
||||||
/* load_address is physical address */
|
|
||||||
nds32_read_buffer(target, load_address, 4, (uint8_t *)&l1_page_table_entry);
|
|
||||||
|
|
||||||
/* Read L2 Physical Page Table */
|
|
||||||
if (l1_page_table_entry & 0x1) /* L1_PTE not present */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
load_address = (l1_page_table_entry & page_table_info_p->l2_base_mask) |
|
|
||||||
((virtual_address & page_table_info_p->l2_offset_mask) >>
|
|
||||||
page_table_info_p->l2_offset_shift);
|
|
||||||
/* load_address is physical address */
|
|
||||||
nds32_read_buffer(target, load_address, 4, (uint8_t *)&l2_page_table_entry);
|
|
||||||
|
|
||||||
if ((l2_page_table_entry & 0x1) != 0x1) /* L2_PTE not valid */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
*physical_address = (l2_page_table_entry & page_table_info_p->ppn_mask) |
|
|
||||||
(virtual_address & page_table_info_p->va_offset_mask);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_TLB_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_TLB_H
|
|
||||||
|
|
||||||
#include "nds32.h"
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PAGE_SIZE_4K = 0,
|
|
||||||
PAGE_SIZE_8K,
|
|
||||||
PAGE_SIZE_NUM,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct page_table_walker_info_s {
|
|
||||||
|
|
||||||
uint32_t l1_offset_mask;
|
|
||||||
uint32_t l1_offset_shift;
|
|
||||||
uint32_t l2_offset_mask;
|
|
||||||
uint32_t l2_offset_shift;
|
|
||||||
uint32_t va_offset_mask;
|
|
||||||
uint32_t l1_base_mask;
|
|
||||||
uint32_t l2_base_mask;
|
|
||||||
uint32_t ppn_mask;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address);
|
|
||||||
extern int nds32_walk_page_table(struct nds32 *nds32, const target_addr_t virtual_address,
|
|
||||||
target_addr_t *physical_address);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_TLB_H */
|
|
|
@ -1,774 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <helper/time_support.h>
|
|
||||||
#include <helper/binarybuffer.h>
|
|
||||||
#include "breakpoints.h"
|
|
||||||
#include "nds32_insn.h"
|
|
||||||
#include "nds32_reg.h"
|
|
||||||
#include "nds32_edm.h"
|
|
||||||
#include "nds32_cmd.h"
|
|
||||||
#include "nds32_v2.h"
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
#include "target_type.h"
|
|
||||||
|
|
||||||
static int nds32_v2_register_mapping(struct nds32 *nds32, int reg_no)
|
|
||||||
{
|
|
||||||
uint32_t max_level = nds32->max_interrupt_level;
|
|
||||||
uint32_t cur_level = nds32->current_interrupt_level;
|
|
||||||
|
|
||||||
if ((cur_level >= 1) && (cur_level < max_level)) {
|
|
||||||
if (reg_no == IR0) {
|
|
||||||
LOG_DEBUG("Map PSW to IPSW");
|
|
||||||
return IR1;
|
|
||||||
} else if (reg_no == PC) {
|
|
||||||
LOG_DEBUG("Map PC to IPC");
|
|
||||||
return IR9;
|
|
||||||
}
|
|
||||||
} else if ((cur_level >= 2) && (cur_level < max_level)) {
|
|
||||||
if (reg_no == R26) {
|
|
||||||
LOG_DEBUG("Mapping P0 to P_P0");
|
|
||||||
return IR12;
|
|
||||||
} else if (reg_no == R27) {
|
|
||||||
LOG_DEBUG("Mapping P1 to P_P1");
|
|
||||||
return IR13;
|
|
||||||
} else if (reg_no == IR1) {
|
|
||||||
LOG_DEBUG("Mapping IPSW to P_IPSW");
|
|
||||||
return IR2;
|
|
||||||
} else if (reg_no == IR4) {
|
|
||||||
LOG_DEBUG("Mapping EVA to P_EVA");
|
|
||||||
return IR5;
|
|
||||||
} else if (reg_no == IR6) {
|
|
||||||
LOG_DEBUG("Mapping ITYPE to P_ITYPE");
|
|
||||||
return IR7;
|
|
||||||
} else if (reg_no == IR9) {
|
|
||||||
LOG_DEBUG("Mapping IPC to P_IPC");
|
|
||||||
return IR10;
|
|
||||||
}
|
|
||||||
} else if (cur_level == max_level) {
|
|
||||||
if (reg_no == PC) {
|
|
||||||
LOG_DEBUG("Mapping PC to O_IPC");
|
|
||||||
return IR11;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg_no;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_get_debug_reason(struct nds32 *nds32, uint32_t *reason)
|
|
||||||
{
|
|
||||||
uint32_t val_itype;
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
|
|
||||||
aice_read_register(aice, IR6, &val_itype);
|
|
||||||
|
|
||||||
*reason = val_itype & 0x0F;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_activate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
int32_t hbr_index = 0;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT) {
|
|
||||||
/* already set at nds32_v2_add_breakpoint() */
|
|
||||||
continue;
|
|
||||||
} else if (bp->type == BKPT_HARD) {
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
|
|
||||||
/* set value */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
|
|
||||||
|
|
||||||
if (nds32_v2->nds32.memory.address_translation)
|
|
||||||
/* enable breakpoint (virtual address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
|
|
||||||
else
|
|
||||||
/* enable breakpoint (physical address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
|
||||||
bp->address);
|
|
||||||
|
|
||||||
hbr_index++;
|
|
||||||
} else {
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_deactivate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
int32_t hbr_index = 0;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT)
|
|
||||||
continue;
|
|
||||||
else if (bp->type == BKPT_HARD)
|
|
||||||
/* disable breakpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
|
||||||
bp->address);
|
|
||||||
|
|
||||||
hbr_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_activate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
struct watchpoint *wp;
|
|
||||||
int32_t wp_num = nds32_v2->next_hbr_index;
|
|
||||||
uint32_t wp_config = 0;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
|
|
||||||
wp_num--;
|
|
||||||
wp->mask = wp->length - 1;
|
|
||||||
if ((wp->address % wp->length) != 0)
|
|
||||||
wp->mask = (wp->mask << 1) + 1;
|
|
||||||
|
|
||||||
if (wp->rw == WPT_READ)
|
|
||||||
wp_config = 0x3;
|
|
||||||
else if (wp->rw == WPT_WRITE)
|
|
||||||
wp_config = 0x5;
|
|
||||||
else if (wp->rw == WPT_ACCESS)
|
|
||||||
wp_config = 0x7;
|
|
||||||
|
|
||||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
|
||||||
if (nds32_v2->nds32.memory.address_translation == false)
|
|
||||||
wp_config |= 0x8;
|
|
||||||
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
|
||||||
wp->address - (wp->address % wp->length));
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
|
||||||
/* enable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
|
||||||
/* set value */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32, wp_num,
|
|
||||||
wp->address, wp->mask);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_deactivate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
int32_t wp_num = nds32_v2->next_hbr_index;
|
|
||||||
struct watchpoint *wp;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
wp_num--;
|
|
||||||
/* disable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32,
|
|
||||||
wp_num, wp->address, wp->mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_check_interrupt_stack(struct nds32_v2_common *nds32_v2)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
uint32_t val_ir0;
|
|
||||||
uint32_t val_ir1;
|
|
||||||
uint32_t val_ir2;
|
|
||||||
uint32_t modified_psw;
|
|
||||||
|
|
||||||
/* Save interrupt level */
|
|
||||||
aice_read_register(aice, IR0, &val_ir0); /* get $IR0 directly */
|
|
||||||
|
|
||||||
/* backup $IR0 */
|
|
||||||
nds32_v2->backup_ir0 = val_ir0;
|
|
||||||
|
|
||||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
|
||||||
|
|
||||||
if (nds32_reach_max_interrupt_level(nds32)) {
|
|
||||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
|
||||||
nds32->current_interrupt_level);
|
|
||||||
|
|
||||||
/* decrease interrupt level */
|
|
||||||
modified_psw = val_ir0 - 0x2;
|
|
||||||
|
|
||||||
/* disable GIE, IT, DT, HSS */
|
|
||||||
modified_psw &= (~0x8C1);
|
|
||||||
|
|
||||||
aice_write_register(aice, IR0, modified_psw);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* There is a case that single step also trigger another interrupt,
|
|
||||||
then HSS bit in psw(ir0) will push to ipsw(ir1).
|
|
||||||
Then hit debug interrupt HSS bit in ipsw(ir1) will push to (p_ipsw)ir2
|
|
||||||
Therefore, HSS bit in p_ipsw(ir2) also need clear.
|
|
||||||
|
|
||||||
Only update $ir2 as current interrupt level is 2, because $ir2 will be random
|
|
||||||
value if the target never reaches interrupt level 2. */
|
|
||||||
if ((nds32->max_interrupt_level == 3) && (nds32->current_interrupt_level == 2)) {
|
|
||||||
aice_read_register(aice, IR2, &val_ir2); /* get $IR2 directly */
|
|
||||||
val_ir2 &= ~(0x01 << 11);
|
|
||||||
aice_write_register(aice, IR2, val_ir2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get original DT bit and set to current state let debugger has same memory view
|
|
||||||
PSW.IT MUST be turned off. Otherwise, DIM could not operate normally. */
|
|
||||||
aice_read_register(aice, IR1, &val_ir1);
|
|
||||||
modified_psw = val_ir0 | (val_ir1 & 0x80);
|
|
||||||
aice_write_register(aice, IR0, modified_psw);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_restore_interrupt_stack(struct nds32_v2_common *nds32_v2)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
|
|
||||||
/* restore origin $IR0 */
|
|
||||||
aice_write_register(aice, IR0, nds32_v2->backup_ir0);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save processor state. This is called after a HALT instruction
|
|
||||||
* succeeds, and on other occasions the processor enters debug mode
|
|
||||||
* (breakpoint, watchpoint, etc).
|
|
||||||
*/
|
|
||||||
static int nds32_v2_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("nds32_v2_debug_entry");
|
|
||||||
|
|
||||||
if (nds32->virtual_hosting)
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Virtual hosting is not supported "
|
|
||||||
"under V1/V2 architecture. -->");
|
|
||||||
|
|
||||||
enum target_state backup_state = nds32->target->state;
|
|
||||||
nds32->target->state = TARGET_HALTED;
|
|
||||||
|
|
||||||
if (nds32->init_arch_info_after_halted == false) {
|
|
||||||
/* init architecture info according to config registers */
|
|
||||||
CHECK_RETVAL(nds32_config(nds32));
|
|
||||||
|
|
||||||
nds32->init_arch_info_after_halted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* REVISIT entire cache should already be invalid !!! */
|
|
||||||
register_cache_invalidate(nds32->core_cache);
|
|
||||||
|
|
||||||
/* deactivate all hardware breakpoints */
|
|
||||||
CHECK_RETVAL(nds32_v2_deactivate_hardware_breakpoint(nds32->target));
|
|
||||||
|
|
||||||
if (enable_watchpoint)
|
|
||||||
CHECK_RETVAL(nds32_v2_deactivate_hardware_watchpoint(nds32->target));
|
|
||||||
|
|
||||||
if (nds32_examine_debug_reason(nds32) != ERROR_OK) {
|
|
||||||
nds32->target->state = backup_state;
|
|
||||||
|
|
||||||
/* re-activate all hardware breakpoints & watchpoints */
|
|
||||||
CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target));
|
|
||||||
|
|
||||||
if (enable_watchpoint) {
|
|
||||||
/* activate all watchpoints */
|
|
||||||
CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check interrupt level before .full_context(), because
|
|
||||||
* get_mapped_reg() in nds32_full_context() needs current_interrupt_level
|
|
||||||
* information */
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
|
|
||||||
nds32_v2_check_interrupt_stack(nds32_v2);
|
|
||||||
|
|
||||||
/* Save registers. */
|
|
||||||
nds32_full_context(nds32);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* target request support */
|
|
||||||
static int nds32_v2_target_request_data(struct target *target,
|
|
||||||
uint32_t size, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
/* AndesCore could use DTR register to communicate with OpenOCD
|
|
||||||
* to output messages
|
|
||||||
* Target data will be put in buffer
|
|
||||||
* The format of DTR is as follow
|
|
||||||
* DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd
|
|
||||||
* target_req_cmd has three possible values:
|
|
||||||
* TARGET_REQ_TRACEMSG
|
|
||||||
* TARGET_REQ_DEBUGMSG
|
|
||||||
* TARGET_REQ_DEBUGCHAR
|
|
||||||
* if size == 0, target will call target_asciimsg(),
|
|
||||||
* else call target_hexmsg()
|
|
||||||
*/
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore processor state.
|
|
||||||
*/
|
|
||||||
static int nds32_v2_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("nds32_v2_leave_debug_state");
|
|
||||||
|
|
||||||
struct target *target = nds32->target;
|
|
||||||
|
|
||||||
/* activate all hardware breakpoints */
|
|
||||||
CHECK_RETVAL(nds32_v2_activate_hardware_breakpoint(nds32->target));
|
|
||||||
|
|
||||||
if (enable_watchpoint) {
|
|
||||||
/* activate all watchpoints */
|
|
||||||
CHECK_RETVAL(nds32_v2_activate_hardware_watchpoint(nds32->target));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore interrupt stack */
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(nds32->target);
|
|
||||||
nds32_v2_restore_interrupt_stack(nds32_v2);
|
|
||||||
|
|
||||||
/* restore PSW, PC, and R0 ... after flushing any modified
|
|
||||||
* registers.
|
|
||||||
*/
|
|
||||||
CHECK_RETVAL(nds32_restore_context(target));
|
|
||||||
|
|
||||||
register_cache_invalidate(nds32->core_cache);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_deassert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
CHECK_RETVAL(nds32_poll(target));
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
|
||||||
/* reset only */
|
|
||||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
|
||||||
target_name(target));
|
|
||||||
retval = target_halt(target);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_checksum_memory(struct target *target,
|
|
||||||
target_addr_t address, uint32_t count, uint32_t *checksum)
|
|
||||||
{
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_add_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
|
||||||
"breakpoints/watchpoints! The limit of "
|
|
||||||
"combined hardware breakpoints/watchpoints "
|
|
||||||
"is %" PRId32 ". -->", nds32_v2->n_hbr);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v2->next_hbr_index++;
|
|
||||||
|
|
||||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
|
||||||
if (result != ERROR_OK) {
|
|
||||||
/* auto convert to hardware breakpoint if failed */
|
|
||||||
if (nds32->auto_convert_hw_bp) {
|
|
||||||
/* convert to hardware breakpoint */
|
|
||||||
breakpoint->type = BKPT_HARD;
|
|
||||||
|
|
||||||
return nds32_v2_add_breakpoint(target, breakpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_remove_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
if (nds32_v2->next_hbr_index <= 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v2->next_hbr_index--;
|
|
||||||
|
|
||||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_add_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v2->n_hbr <= nds32_v2->next_hbr_index) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
|
||||||
"breakpoints/watchpoints! The limit of "
|
|
||||||
"combined hardware breakpoints/watchpoints is %" PRId32 ". -->", nds32_v2->n_hbr);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware watchpoint */
|
|
||||||
nds32_v2->next_hbr_index++;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_remove_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
|
|
||||||
if (nds32_v2->next_hbr_index <= 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v2->next_hbr_index--;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_get_exception_address(struct nds32 *nds32,
|
|
||||||
uint32_t *address, uint32_t reason)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
|
|
||||||
aice_read_register(aice, IR4, address); /* read $EVA directly */
|
|
||||||
|
|
||||||
/* TODO: hit multiple watchpoints */
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* find out which watchpoint hits
|
|
||||||
* get exception address and compare the address to watchpoints
|
|
||||||
*/
|
|
||||||
static int nds32_v2_hit_watchpoint(struct target *target,
|
|
||||||
struct watchpoint **hit_watchpoint)
|
|
||||||
{
|
|
||||||
uint32_t exception_address;
|
|
||||||
struct watchpoint *wp;
|
|
||||||
static struct watchpoint scan_all_watchpoint;
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
|
|
||||||
scan_all_watchpoint.address = 0;
|
|
||||||
scan_all_watchpoint.rw = WPT_WRITE;
|
|
||||||
scan_all_watchpoint.next = 0;
|
|
||||||
scan_all_watchpoint.unique_id = 0x5CA8;
|
|
||||||
|
|
||||||
exception_address = nds32->watched_address;
|
|
||||||
|
|
||||||
if (exception_address == 0) {
|
|
||||||
/* send watch:0 to tell GDB to do software scan for hitting multiple watchpoints */
|
|
||||||
*hit_watchpoint = &scan_all_watchpoint;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
if (((exception_address ^ wp->address) & (~wp->mask)) == 0) {
|
|
||||||
/* TODO: dispel false match */
|
|
||||||
*hit_watchpoint = wp;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_run_algorithm(struct target *target,
|
|
||||||
int num_mem_params,
|
|
||||||
struct mem_param *mem_params,
|
|
||||||
int num_reg_params,
|
|
||||||
struct reg_param *reg_params,
|
|
||||||
target_addr_t entry_point,
|
|
||||||
target_addr_t exit_point,
|
|
||||||
int timeout_ms,
|
|
||||||
void *arch_info)
|
|
||||||
{
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_target_create(struct target *target, Jim_Interp *interp)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2;
|
|
||||||
|
|
||||||
nds32_v2 = calloc(1, sizeof(*nds32_v2));
|
|
||||||
if (!nds32_v2)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
nds32_v2->nds32.register_map = nds32_v2_register_mapping;
|
|
||||||
nds32_v2->nds32.get_debug_reason = nds32_v2_get_debug_reason;
|
|
||||||
nds32_v2->nds32.enter_debug_state = nds32_v2_debug_entry;
|
|
||||||
nds32_v2->nds32.leave_debug_state = nds32_v2_leave_debug_state;
|
|
||||||
nds32_v2->nds32.get_watched_address = nds32_v2_get_exception_address;
|
|
||||||
|
|
||||||
nds32_init_arch_info(target, &(nds32_v2->nds32));
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_init_target(struct command_context *cmd_ctx,
|
|
||||||
struct target *target)
|
|
||||||
{
|
|
||||||
/* Initialize anything we can set up without talking to the target */
|
|
||||||
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
|
|
||||||
nds32_init(nds32);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* talk to the target and set things up */
|
|
||||||
static int nds32_v2_examine(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v2_common *nds32_v2 = target_to_nds32_v2(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v2->nds32);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
|
|
||||||
if (!target_was_examined(target)) {
|
|
||||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
|
||||||
|
|
||||||
if (nds32->reset_halt_as_examine)
|
|
||||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t edm_cfg;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
|
||||||
|
|
||||||
/* get the number of hardware breakpoints */
|
|
||||||
nds32_v2->n_hbr = (edm_cfg & 0x7) + 1;
|
|
||||||
|
|
||||||
nds32_v2->next_hbr_index = 0;
|
|
||||||
|
|
||||||
LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target),
|
|
||||||
nds32_v2->n_hbr);
|
|
||||||
|
|
||||||
nds32->target->state = TARGET_RUNNING;
|
|
||||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
|
||||||
|
|
||||||
target_set_examined(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_translate_address(struct target *target, target_addr_t *address)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
target_addr_t physical_address;
|
|
||||||
|
|
||||||
/* Following conditions need to do address translation
|
|
||||||
* 1. BUS mode
|
|
||||||
* 2. CPU mode under maximum interrupt level */
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_BUS) ||
|
|
||||||
((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
nds32_reach_max_interrupt_level(nds32))) {
|
|
||||||
if (target->type->virt2phys(target, *address, &physical_address) == ERROR_OK)
|
|
||||||
*address = physical_address;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_read_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
nds32_v2_translate_address(target, &address);
|
|
||||||
|
|
||||||
return nds32_read_buffer(target, address, size, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_write_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
nds32_v2_translate_address(target, &address);
|
|
||||||
|
|
||||||
return nds32_write_buffer(target, address, size, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_read_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
nds32_v2_translate_address(target, &address);
|
|
||||||
|
|
||||||
return nds32_read_memory(target, address, size, count, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v2_write_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
nds32_v2_translate_address(target, &address);
|
|
||||||
|
|
||||||
return nds32_write_memory(target, address, size, count, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds methods for V2 targets. */
|
|
||||||
struct target_type nds32_v2_target = {
|
|
||||||
.name = "nds32_v2",
|
|
||||||
|
|
||||||
.poll = nds32_poll,
|
|
||||||
.arch_state = nds32_arch_state,
|
|
||||||
|
|
||||||
.target_request_data = nds32_v2_target_request_data,
|
|
||||||
|
|
||||||
.halt = nds32_halt,
|
|
||||||
.resume = nds32_resume,
|
|
||||||
.step = nds32_step,
|
|
||||||
|
|
||||||
.assert_reset = nds32_assert_reset,
|
|
||||||
.deassert_reset = nds32_v2_deassert_reset,
|
|
||||||
|
|
||||||
/* register access */
|
|
||||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
|
||||||
|
|
||||||
/* memory access */
|
|
||||||
.read_buffer = nds32_v2_read_buffer,
|
|
||||||
.write_buffer = nds32_v2_write_buffer,
|
|
||||||
.read_memory = nds32_v2_read_memory,
|
|
||||||
.write_memory = nds32_v2_write_memory,
|
|
||||||
|
|
||||||
.checksum_memory = nds32_v2_checksum_memory,
|
|
||||||
|
|
||||||
/* breakpoint/watchpoint */
|
|
||||||
.add_breakpoint = nds32_v2_add_breakpoint,
|
|
||||||
.remove_breakpoint = nds32_v2_remove_breakpoint,
|
|
||||||
.add_watchpoint = nds32_v2_add_watchpoint,
|
|
||||||
.remove_watchpoint = nds32_v2_remove_watchpoint,
|
|
||||||
.hit_watchpoint = nds32_v2_hit_watchpoint,
|
|
||||||
|
|
||||||
/* MMU */
|
|
||||||
.mmu = nds32_mmu,
|
|
||||||
.virt2phys = nds32_virtual_to_physical,
|
|
||||||
.read_phys_memory = nds32_read_phys_memory,
|
|
||||||
.write_phys_memory = nds32_write_phys_memory,
|
|
||||||
|
|
||||||
.run_algorithm = nds32_v2_run_algorithm,
|
|
||||||
|
|
||||||
.commands = nds32_command_handlers,
|
|
||||||
.target_create = nds32_v2_target_create,
|
|
||||||
.init_target = nds32_v2_init_target,
|
|
||||||
.examine = nds32_v2_examine,
|
|
||||||
};
|
|
|
@ -1,31 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_V2_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_V2_H
|
|
||||||
|
|
||||||
#include "nds32.h"
|
|
||||||
|
|
||||||
struct nds32_v2_common {
|
|
||||||
struct nds32 nds32;
|
|
||||||
|
|
||||||
uint32_t backup_ir0;
|
|
||||||
|
|
||||||
/** number of hardware breakpoints */
|
|
||||||
int32_t n_hbr;
|
|
||||||
|
|
||||||
/** next hardware breakpoint index */
|
|
||||||
/** increase from low index to high index */
|
|
||||||
int32_t next_hbr_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct nds32_v2_common *target_to_nds32_v2(struct target *target)
|
|
||||||
{
|
|
||||||
return container_of(target->arch_info, struct nds32_v2_common, nds32);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_V2_H */
|
|
|
@ -1,510 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "breakpoints.h"
|
|
||||||
#include "nds32_cmd.h"
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
#include "nds32_v3.h"
|
|
||||||
#include "nds32_v3_common.h"
|
|
||||||
|
|
||||||
static int nds32_v3_activate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
int32_t hbr_index = nds32_v3->next_hbr_index;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT) {
|
|
||||||
/* already set at nds32_v3_add_breakpoint() */
|
|
||||||
continue;
|
|
||||||
} else if (bp->type == BKPT_HARD) {
|
|
||||||
hbr_index--;
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + hbr_index, bp->address);
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + hbr_index, 0);
|
|
||||||
/* set value */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + hbr_index, 0);
|
|
||||||
|
|
||||||
if (nds32_v3->nds32.memory.address_translation)
|
|
||||||
/* enable breakpoint (virtual address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x2);
|
|
||||||
else
|
|
||||||
/* enable breakpoint (physical address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0xA);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
|
||||||
bp->address);
|
|
||||||
} else {
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_deactivate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
int32_t hbr_index = nds32_v3->next_hbr_index;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT) {
|
|
||||||
continue;
|
|
||||||
} else if (bp->type == BKPT_HARD) {
|
|
||||||
hbr_index--;
|
|
||||||
/* disable breakpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + hbr_index, 0x0);
|
|
||||||
} else {
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware BP %" PRId32 " at %08" TARGET_PRIxADDR, hbr_index,
|
|
||||||
bp->address);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_activate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct watchpoint *wp;
|
|
||||||
int32_t wp_num = 0;
|
|
||||||
uint32_t wp_config = 0;
|
|
||||||
bool ld_stop, st_stop;
|
|
||||||
|
|
||||||
if (nds32_v3->nds32.global_stop)
|
|
||||||
ld_stop = st_stop = false;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
|
|
||||||
if (wp_num < nds32_v3->used_n_wp) {
|
|
||||||
wp->mask = wp->length - 1;
|
|
||||||
if ((wp->address % wp->length) != 0)
|
|
||||||
wp->mask = (wp->mask << 1) + 1;
|
|
||||||
|
|
||||||
if (wp->rw == WPT_READ)
|
|
||||||
wp_config = 0x3;
|
|
||||||
else if (wp->rw == WPT_WRITE)
|
|
||||||
wp_config = 0x5;
|
|
||||||
else if (wp->rw == WPT_ACCESS)
|
|
||||||
wp_config = 0x7;
|
|
||||||
|
|
||||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
|
||||||
if (nds32_v3->nds32.memory.address_translation == false)
|
|
||||||
wp_config |= 0x8;
|
|
||||||
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
|
||||||
wp->address - (wp->address % wp->length));
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
|
||||||
/* enable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
|
||||||
/* set value */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPV0 + wp_num, 0);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR " mask %08" PRIx32,
|
|
||||||
wp_num, wp->address, wp->mask);
|
|
||||||
|
|
||||||
wp_num++;
|
|
||||||
} else if (nds32_v3->nds32.global_stop) {
|
|
||||||
if (wp->rw == WPT_READ)
|
|
||||||
ld_stop = true;
|
|
||||||
else if (wp->rw == WPT_WRITE)
|
|
||||||
st_stop = true;
|
|
||||||
else if (wp->rw == WPT_ACCESS)
|
|
||||||
ld_stop = st_stop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds32_v3->nds32.global_stop) {
|
|
||||||
uint32_t edm_ctl;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
|
||||||
if (ld_stop)
|
|
||||||
edm_ctl |= 0x10;
|
|
||||||
if (st_stop)
|
|
||||||
edm_ctl |= 0x20;
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_deactivate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
int32_t wp_num = 0;
|
|
||||||
struct watchpoint *wp;
|
|
||||||
bool clean_global_stop = false;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
|
|
||||||
if (wp_num < nds32_v3->used_n_wp) {
|
|
||||||
/* disable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
|
||||||
" mask %08" PRIx32, wp_num,
|
|
||||||
wp->address, wp->mask);
|
|
||||||
wp_num++;
|
|
||||||
} else if (nds32_v3->nds32.global_stop) {
|
|
||||||
clean_global_stop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clean_global_stop) {
|
|
||||||
uint32_t edm_ctl;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
|
||||||
edm_ctl = edm_ctl & (~0x30);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_check_interrupt_stack(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
uint32_t val_ir0;
|
|
||||||
uint32_t value;
|
|
||||||
|
|
||||||
/* Save interrupt level */
|
|
||||||
nds32_get_mapped_reg(nds32, IR0, &val_ir0);
|
|
||||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
|
||||||
|
|
||||||
if (nds32_reach_max_interrupt_level(nds32))
|
|
||||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
|
||||||
nds32->current_interrupt_level);
|
|
||||||
|
|
||||||
/* backup $ir4 & $ir6 to avoid suppressed exception overwrite */
|
|
||||||
nds32_get_mapped_reg(nds32, IR4, &value);
|
|
||||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_restore_interrupt_stack(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
uint32_t value;
|
|
||||||
|
|
||||||
/* get backup value from cache */
|
|
||||||
/* then set back to make the register dirty */
|
|
||||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR0, value);
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, IR4, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR4, value);
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR6, value);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_deassert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
bool switch_to_v3_stack = false;
|
|
||||||
uint32_t value_edm_ctl;
|
|
||||||
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
|
|
||||||
if (((value_edm_ctl >> 6) & 0x1) == 0) { /* reset to V2 EDM mode */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, value_edm_ctl | (0x1 << 6));
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &value_edm_ctl);
|
|
||||||
if (((value_edm_ctl >> 6) & 0x1) == 1)
|
|
||||||
switch_to_v3_stack = true;
|
|
||||||
} else
|
|
||||||
switch_to_v3_stack = false;
|
|
||||||
|
|
||||||
CHECK_RETVAL(nds32_poll(target));
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
|
||||||
/* reset only */
|
|
||||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
|
||||||
target_name(target));
|
|
||||||
retval = target_halt(target);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* reset-halt */
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
|
||||||
uint32_t value;
|
|
||||||
uint32_t interrupt_level;
|
|
||||||
|
|
||||||
if (switch_to_v3_stack == true) {
|
|
||||||
/* PSW.INTL-- */
|
|
||||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
|
||||||
interrupt_level = (value >> 1) & 0x3;
|
|
||||||
interrupt_level--;
|
|
||||||
value &= ~(0x6);
|
|
||||||
value |= (interrupt_level << 1);
|
|
||||||
value |= 0x400; /* set PSW.DEX */
|
|
||||||
nds32_set_mapped_reg(nds32, IR0, value);
|
|
||||||
|
|
||||||
/* copy IPC to OIPC */
|
|
||||||
if ((interrupt_level + 1) < nds32->max_interrupt_level) {
|
|
||||||
nds32_get_mapped_reg(nds32, IR9, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR11, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_add_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many "
|
|
||||||
"hardware breakpoints/watchpoints! "
|
|
||||||
"The limit of combined hardware "
|
|
||||||
"breakpoints/watchpoints is %" PRId32 ". -->",
|
|
||||||
nds32_v3->n_hbr);
|
|
||||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
|
||||||
"hardware breakpoint: %" PRId32 ", hardware "
|
|
||||||
"watchpoints: %" PRId32 ". -->",
|
|
||||||
nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
|
|
||||||
nds32_v3->used_n_wp);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v3->next_hbr_index++;
|
|
||||||
|
|
||||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
|
||||||
if (result != ERROR_OK) {
|
|
||||||
/* auto convert to hardware breakpoint if failed */
|
|
||||||
if (nds32->auto_convert_hw_bp) {
|
|
||||||
/* convert to hardware breakpoint */
|
|
||||||
breakpoint->type = BKPT_HARD;
|
|
||||||
|
|
||||||
return nds32_v3_add_breakpoint(target, breakpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_remove_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
if (nds32_v3->next_hbr_index <= 0)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v3->next_hbr_index--;
|
|
||||||
|
|
||||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_add_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v3->n_hbr <= nds32_v3->next_hbr_index) {
|
|
||||||
/* No hardware resource */
|
|
||||||
if (nds32_v3->nds32.global_stop) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
|
||||||
"watchpoints exceeds the hardware "
|
|
||||||
"resources. Stop at every load/store "
|
|
||||||
"instruction to check for watchpoint matches. -->");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
|
||||||
"breakpoints/watchpoints! The limit of combined "
|
|
||||||
"hardware breakpoints/watchpoints is %" PRId32 ". -->",
|
|
||||||
nds32_v3->n_hbr);
|
|
||||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
|
||||||
"hardware breakpoint: %" PRId32 ", hardware "
|
|
||||||
"watchpoints: %" PRId32 ". -->",
|
|
||||||
nds32_v3->next_hbr_index - nds32_v3->used_n_wp,
|
|
||||||
nds32_v3->used_n_wp);
|
|
||||||
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware watchpoint */
|
|
||||||
nds32_v3->next_hbr_index++;
|
|
||||||
nds32_v3->used_n_wp++;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_remove_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
|
|
||||||
if (nds32_v3->next_hbr_index <= 0) {
|
|
||||||
if (nds32_v3->nds32.global_stop)
|
|
||||||
return ERROR_OK;
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v3->next_hbr_index--;
|
|
||||||
nds32_v3->used_n_wp--;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct nds32_v3_common_callback nds32_v3_common_callback = {
|
|
||||||
.check_interrupt_stack = nds32_v3_check_interrupt_stack,
|
|
||||||
.restore_interrupt_stack = nds32_v3_restore_interrupt_stack,
|
|
||||||
.activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint,
|
|
||||||
.activate_hardware_watchpoint = nds32_v3_activate_hardware_watchpoint,
|
|
||||||
.deactivate_hardware_breakpoint = nds32_v3_deactivate_hardware_breakpoint,
|
|
||||||
.deactivate_hardware_watchpoint = nds32_v3_deactivate_hardware_watchpoint,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int nds32_v3_target_create(struct target *target, Jim_Interp *interp)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3;
|
|
||||||
|
|
||||||
nds32_v3 = calloc(1, sizeof(*nds32_v3));
|
|
||||||
if (!nds32_v3)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
nds32_v3_common_register_callback(&nds32_v3_common_callback);
|
|
||||||
nds32_v3_target_create_common(target, &(nds32_v3->nds32));
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* talk to the target and set things up */
|
|
||||||
static int nds32_v3_examine(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3_common *nds32_v3 = target_to_nds32_v3(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v3->nds32);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
|
|
||||||
if (!target_was_examined(target)) {
|
|
||||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
|
||||||
|
|
||||||
if (nds32->reset_halt_as_examine)
|
|
||||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t edm_cfg;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
|
||||||
|
|
||||||
/* get the number of hardware breakpoints */
|
|
||||||
nds32_v3->n_hbr = (edm_cfg & 0x7) + 1;
|
|
||||||
|
|
||||||
/* low interference profiling */
|
|
||||||
if (edm_cfg & 0x100)
|
|
||||||
nds32_v3->low_interference_profile = true;
|
|
||||||
else
|
|
||||||
nds32_v3->low_interference_profile = false;
|
|
||||||
|
|
||||||
nds32_v3->next_hbr_index = 0;
|
|
||||||
nds32_v3->used_n_wp = 0;
|
|
||||||
|
|
||||||
LOG_INFO("%s: total hardware breakpoint %" PRId32, target_name(target),
|
|
||||||
nds32_v3->n_hbr);
|
|
||||||
|
|
||||||
nds32->target->state = TARGET_RUNNING;
|
|
||||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
|
||||||
|
|
||||||
target_set_examined(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds methods for Andes1337 targets. */
|
|
||||||
struct target_type nds32_v3_target = {
|
|
||||||
.name = "nds32_v3",
|
|
||||||
|
|
||||||
.poll = nds32_poll,
|
|
||||||
.arch_state = nds32_arch_state,
|
|
||||||
|
|
||||||
.target_request_data = nds32_v3_target_request_data,
|
|
||||||
|
|
||||||
.halt = nds32_halt,
|
|
||||||
.resume = nds32_resume,
|
|
||||||
.step = nds32_step,
|
|
||||||
|
|
||||||
.assert_reset = nds32_assert_reset,
|
|
||||||
.deassert_reset = nds32_v3_deassert_reset,
|
|
||||||
|
|
||||||
/* register access */
|
|
||||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
|
||||||
|
|
||||||
/* memory access */
|
|
||||||
.read_buffer = nds32_v3_read_buffer,
|
|
||||||
.write_buffer = nds32_v3_write_buffer,
|
|
||||||
.read_memory = nds32_v3_read_memory,
|
|
||||||
.write_memory = nds32_v3_write_memory,
|
|
||||||
|
|
||||||
.checksum_memory = nds32_v3_checksum_memory,
|
|
||||||
|
|
||||||
/* breakpoint/watchpoint */
|
|
||||||
.add_breakpoint = nds32_v3_add_breakpoint,
|
|
||||||
.remove_breakpoint = nds32_v3_remove_breakpoint,
|
|
||||||
.add_watchpoint = nds32_v3_add_watchpoint,
|
|
||||||
.remove_watchpoint = nds32_v3_remove_watchpoint,
|
|
||||||
.hit_watchpoint = nds32_v3_hit_watchpoint,
|
|
||||||
|
|
||||||
/* MMU */
|
|
||||||
.mmu = nds32_mmu,
|
|
||||||
.virt2phys = nds32_virtual_to_physical,
|
|
||||||
.read_phys_memory = nds32_read_phys_memory,
|
|
||||||
.write_phys_memory = nds32_write_phys_memory,
|
|
||||||
|
|
||||||
.run_algorithm = nds32_v3_run_algorithm,
|
|
||||||
|
|
||||||
.commands = nds32_command_handlers,
|
|
||||||
.target_create = nds32_v3_target_create,
|
|
||||||
.init_target = nds32_v3_init_target,
|
|
||||||
.examine = nds32_v3_examine,
|
|
||||||
|
|
||||||
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
|
||||||
.gdb_fileio_end = nds32_gdb_fileio_end,
|
|
||||||
|
|
||||||
.profiling = nds32_profiling,
|
|
||||||
};
|
|
|
@ -1,34 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_V3_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_V3_H
|
|
||||||
|
|
||||||
#include "nds32.h"
|
|
||||||
|
|
||||||
struct nds32_v3_common {
|
|
||||||
struct nds32 nds32;
|
|
||||||
|
|
||||||
/** number of hardware breakpoints */
|
|
||||||
int32_t n_hbr;
|
|
||||||
|
|
||||||
/** number of used hardware watchpoints */
|
|
||||||
int32_t used_n_wp;
|
|
||||||
|
|
||||||
/** next hardware breakpoint index */
|
|
||||||
int32_t next_hbr_index;
|
|
||||||
|
|
||||||
/** low interference profiling */
|
|
||||||
bool low_interference_profile;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct nds32_v3_common *target_to_nds32_v3(struct target *target)
|
|
||||||
{
|
|
||||||
return container_of(target->arch_info, struct nds32_v3_common, nds32);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_V3_H */
|
|
|
@ -1,664 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "breakpoints.h"
|
|
||||||
#include "nds32_reg.h"
|
|
||||||
#include "nds32_disassembler.h"
|
|
||||||
#include "nds32.h"
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
#include "nds32_v3_common.h"
|
|
||||||
|
|
||||||
static struct nds32_v3_common_callback *v3_common_callback;
|
|
||||||
|
|
||||||
static int nds32_v3_register_mapping(struct nds32 *nds32, int reg_no)
|
|
||||||
{
|
|
||||||
if (reg_no == PC)
|
|
||||||
return IR11;
|
|
||||||
|
|
||||||
return reg_no;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_get_debug_reason(struct nds32 *nds32, uint32_t *reason)
|
|
||||||
{
|
|
||||||
uint32_t edmsw;
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw);
|
|
||||||
|
|
||||||
*reason = (edmsw >> 12) & 0x0F;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save processor state. This is called after a HALT instruction
|
|
||||||
* succeeds, and on other occasions the processor enters debug mode
|
|
||||||
* (breakpoint, watchpoint, etc).
|
|
||||||
*/
|
|
||||||
static int nds32_v3_debug_entry(struct nds32 *nds32, bool enable_watchpoint)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("nds32_v3_debug_entry");
|
|
||||||
|
|
||||||
enum target_state backup_state = nds32->target->state;
|
|
||||||
nds32->target->state = TARGET_HALTED;
|
|
||||||
|
|
||||||
if (nds32->init_arch_info_after_halted == false) {
|
|
||||||
/* init architecture info according to config registers */
|
|
||||||
CHECK_RETVAL(nds32_config(nds32));
|
|
||||||
|
|
||||||
nds32->init_arch_info_after_halted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* REVISIT entire cache should already be invalid !!! */
|
|
||||||
register_cache_invalidate(nds32->core_cache);
|
|
||||||
|
|
||||||
/* deactivate all hardware breakpoints */
|
|
||||||
CHECK_RETVAL(v3_common_callback->deactivate_hardware_breakpoint(nds32->target));
|
|
||||||
|
|
||||||
if (enable_watchpoint)
|
|
||||||
CHECK_RETVAL(v3_common_callback->deactivate_hardware_watchpoint(nds32->target));
|
|
||||||
|
|
||||||
struct breakpoint *syscall_break = &(nds32->syscall_break);
|
|
||||||
if (nds32->virtual_hosting) {
|
|
||||||
if (syscall_break->is_set) {
|
|
||||||
/** disable virtual hosting */
|
|
||||||
|
|
||||||
/* remove breakpoint at syscall entry */
|
|
||||||
target_remove_breakpoint(nds32->target, syscall_break);
|
|
||||||
syscall_break->is_set = false;
|
|
||||||
|
|
||||||
uint32_t value_pc;
|
|
||||||
nds32_get_mapped_reg(nds32, PC, &value_pc);
|
|
||||||
if (value_pc == syscall_break->address)
|
|
||||||
/** process syscall for virtual hosting */
|
|
||||||
nds32->hit_syscall = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds32_examine_debug_reason(nds32) != ERROR_OK) {
|
|
||||||
nds32->target->state = backup_state;
|
|
||||||
|
|
||||||
/* re-activate all hardware breakpoints & watchpoints */
|
|
||||||
CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(nds32->target));
|
|
||||||
|
|
||||||
if (enable_watchpoint)
|
|
||||||
CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(nds32->target));
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save registers. */
|
|
||||||
nds32_full_context(nds32);
|
|
||||||
|
|
||||||
/* check interrupt level */
|
|
||||||
v3_common_callback->check_interrupt_stack(nds32);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restore processor state.
|
|
||||||
*/
|
|
||||||
static int nds32_v3_leave_debug_state(struct nds32 *nds32, bool enable_watchpoint)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("nds32_v3_leave_debug_state");
|
|
||||||
|
|
||||||
struct target *target = nds32->target;
|
|
||||||
|
|
||||||
/* activate all hardware breakpoints */
|
|
||||||
CHECK_RETVAL(v3_common_callback->activate_hardware_breakpoint(target));
|
|
||||||
|
|
||||||
if (enable_watchpoint) {
|
|
||||||
/* activate all watchpoints */
|
|
||||||
CHECK_RETVAL(v3_common_callback->activate_hardware_watchpoint(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore interrupt stack */
|
|
||||||
v3_common_callback->restore_interrupt_stack(nds32);
|
|
||||||
|
|
||||||
/* REVISIT once we start caring about MMU and cache state,
|
|
||||||
* address it here ...
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* restore PSW, PC, and R0 ... after flushing any modified
|
|
||||||
* registers.
|
|
||||||
*/
|
|
||||||
CHECK_RETVAL(nds32_restore_context(target));
|
|
||||||
|
|
||||||
if (nds32->virtual_hosting) {
|
|
||||||
/** enable virtual hosting */
|
|
||||||
uint32_t value_ir3;
|
|
||||||
uint32_t entry_size;
|
|
||||||
uint32_t syscall_address;
|
|
||||||
|
|
||||||
/* get syscall entry address */
|
|
||||||
nds32_get_mapped_reg(nds32, IR3, &value_ir3);
|
|
||||||
entry_size = 0x4 << (((value_ir3 >> 14) & 0x3) << 1);
|
|
||||||
syscall_address = (value_ir3 & 0xFFFF0000) + entry_size * 8; /* The index of SYSCALL is 8 */
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
/* single step to skip syscall entry */
|
|
||||||
/* use IRET to skip syscall */
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
uint32_t value_ir9;
|
|
||||||
uint32_t value_ir6;
|
|
||||||
uint32_t syscall_id;
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, IR6, &value_ir6);
|
|
||||||
syscall_id = (value_ir6 >> 16) & 0x7FFF;
|
|
||||||
|
|
||||||
if (syscall_id == NDS32_SYSCALL_EXIT) {
|
|
||||||
/* If target hits exit syscall, do not use IRET to skip handler. */
|
|
||||||
aice_step(aice);
|
|
||||||
} else {
|
|
||||||
/* use api->read/write_reg to skip nds32 register cache */
|
|
||||||
uint32_t value_dimbr;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_DIMBR, &value_dimbr);
|
|
||||||
aice_write_register(aice, IR11, value_dimbr + 0xC);
|
|
||||||
|
|
||||||
aice_read_register(aice, IR9, &value_ir9);
|
|
||||||
value_ir9 += 4; /* syscall is always 4 bytes */
|
|
||||||
aice_write_register(aice, IR9, value_ir9);
|
|
||||||
|
|
||||||
/* backup hardware breakpoint 0 */
|
|
||||||
uint32_t backup_bpa, backup_bpam, backup_bpc;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPA0, &backup_bpa);
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPAM0, &backup_bpam);
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0, &backup_bpc);
|
|
||||||
|
|
||||||
/* use hardware breakpoint 0 to stop cpu after skipping syscall */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, value_ir9);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, 0);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, 0xA);
|
|
||||||
|
|
||||||
/* Execute two IRET.
|
|
||||||
* First IRET is used to quit debug mode.
|
|
||||||
* Second IRET is used to quit current syscall. */
|
|
||||||
uint32_t dim_inst[4] = {NOP, NOP, IRET, IRET};
|
|
||||||
aice_execute(aice, dim_inst, 4);
|
|
||||||
|
|
||||||
/* restore origin hardware breakpoint 0 */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0, backup_bpa);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0, backup_bpam);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0, backup_bpc);
|
|
||||||
}
|
|
||||||
|
|
||||||
nds32->hit_syscall = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* insert breakpoint at syscall entry */
|
|
||||||
struct breakpoint *syscall_break = &(nds32->syscall_break);
|
|
||||||
|
|
||||||
syscall_break->address = syscall_address;
|
|
||||||
syscall_break->type = BKPT_SOFT;
|
|
||||||
syscall_break->is_set = true;
|
|
||||||
target_add_breakpoint(target, syscall_break);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3_get_exception_address(struct nds32 *nds32,
|
|
||||||
uint32_t *address, uint32_t reason)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("nds32_v3_get_exception_address");
|
|
||||||
|
|
||||||
struct aice_port_s *aice = target_to_aice(nds32->target);
|
|
||||||
struct target *target = nds32->target;
|
|
||||||
uint32_t edmsw;
|
|
||||||
uint32_t edm_cfg;
|
|
||||||
uint32_t match_bits;
|
|
||||||
uint32_t match_count;
|
|
||||||
int32_t i;
|
|
||||||
static int32_t number_of_hard_break;
|
|
||||||
uint32_t bp_control;
|
|
||||||
|
|
||||||
if (number_of_hard_break == 0) {
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
|
||||||
number_of_hard_break = (edm_cfg & 0x7) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDMSW, &edmsw);
|
|
||||||
/* clear matching bits (write-one-clear) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDMSW, edmsw);
|
|
||||||
match_bits = (edmsw >> 4) & 0xFF;
|
|
||||||
match_count = 0;
|
|
||||||
for (i = 0 ; i < number_of_hard_break ; i++) {
|
|
||||||
if (match_bits & (1 << i)) {
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPA0 + i, address);
|
|
||||||
match_count++;
|
|
||||||
|
|
||||||
/* If target hits multiple read/access watchpoint,
|
|
||||||
* select the first one. */
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &bp_control);
|
|
||||||
if (0x3 == (bp_control & 0x3)) {
|
|
||||||
match_count = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_count > 1) { /* multiple hits */
|
|
||||||
*address = 0;
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (match_count == 1) {
|
|
||||||
uint32_t val_pc;
|
|
||||||
uint32_t opcode;
|
|
||||||
struct nds32_instruction instruction;
|
|
||||||
struct watchpoint *wp;
|
|
||||||
bool hit;
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, PC, &val_pc);
|
|
||||||
|
|
||||||
if ((reason == NDS32_DEBUG_DATA_ADDR_WATCHPOINT_NEXT_PRECISE) ||
|
|
||||||
(reason == NDS32_DEBUG_DATA_VALUE_WATCHPOINT_NEXT_PRECISE)) {
|
|
||||||
if (edmsw & 0x4) /* check EDMSW.IS_16BIT */
|
|
||||||
val_pc -= 2;
|
|
||||||
else
|
|
||||||
val_pc -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
nds32_read_opcode(nds32, val_pc, &opcode);
|
|
||||||
nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction);
|
|
||||||
|
|
||||||
LOG_DEBUG("PC: 0x%08" PRIx32 ", access start: 0x%08" PRIx32 ", end: 0x%08" PRIx32,
|
|
||||||
val_pc, instruction.access_start, instruction.access_end);
|
|
||||||
|
|
||||||
/* check if multiple hits in the access range */
|
|
||||||
uint32_t in_range_watch_count = 0;
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
if ((instruction.access_start <= wp->address) &&
|
|
||||||
(wp->address < instruction.access_end))
|
|
||||||
in_range_watch_count++;
|
|
||||||
}
|
|
||||||
if (in_range_watch_count > 1) {
|
|
||||||
/* Hit LSMW instruction. */
|
|
||||||
*address = 0;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dispel false match */
|
|
||||||
hit = false;
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
if (((*address ^ wp->address) & (~wp->mask)) == 0) {
|
|
||||||
uint32_t watch_start;
|
|
||||||
uint32_t watch_end;
|
|
||||||
|
|
||||||
watch_start = wp->address;
|
|
||||||
watch_end = wp->address + wp->length;
|
|
||||||
|
|
||||||
if ((watch_end <= instruction.access_start) ||
|
|
||||||
(instruction.access_end <= watch_start))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
hit = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit)
|
|
||||||
return ERROR_OK;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
} else if (match_count == 0) {
|
|
||||||
/* global stop is precise exception */
|
|
||||||
if ((reason == NDS32_DEBUG_LOAD_STORE_GLOBAL_STOP) && nds32->global_stop) {
|
|
||||||
/* parse instruction to get correct access address */
|
|
||||||
uint32_t val_pc;
|
|
||||||
uint32_t opcode;
|
|
||||||
struct nds32_instruction instruction;
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, PC, &val_pc);
|
|
||||||
nds32_read_opcode(nds32, val_pc, &opcode);
|
|
||||||
nds32_evaluate_opcode(nds32, opcode, val_pc, &instruction);
|
|
||||||
|
|
||||||
*address = instruction.access_start;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*address = 0xFFFFFFFF;
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback)
|
|
||||||
{
|
|
||||||
v3_common_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** target_type functions: */
|
|
||||||
/* target request support */
|
|
||||||
int nds32_v3_target_request_data(struct target *target,
|
|
||||||
uint32_t size, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
/* AndesCore could use DTR register to communicate with OpenOCD
|
|
||||||
* to output messages
|
|
||||||
* Target data will be put in buffer
|
|
||||||
* The format of DTR is as follow
|
|
||||||
* DTR[31:16] => length, DTR[15:8] => size, DTR[7:0] => target_req_cmd
|
|
||||||
* target_req_cmd has three possible values:
|
|
||||||
* TARGET_REQ_TRACEMSG
|
|
||||||
* TARGET_REQ_DEBUGMSG
|
|
||||||
* TARGET_REQ_DEBUGCHAR
|
|
||||||
* if size == 0, target will call target_asciimsg(),
|
|
||||||
* else call target_hexmsg()
|
|
||||||
*/
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_checksum_memory(struct target *target,
|
|
||||||
target_addr_t address, uint32_t count, uint32_t *checksum)
|
|
||||||
{
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* find out which watchpoint hits
|
|
||||||
* get exception address and compare the address to watchpoints
|
|
||||||
*/
|
|
||||||
int nds32_v3_hit_watchpoint(struct target *target,
|
|
||||||
struct watchpoint **hit_watchpoint)
|
|
||||||
{
|
|
||||||
static struct watchpoint scan_all_watchpoint;
|
|
||||||
|
|
||||||
uint32_t exception_address;
|
|
||||||
struct watchpoint *wp;
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
|
|
||||||
exception_address = nds32->watched_address;
|
|
||||||
|
|
||||||
if (exception_address == 0xFFFFFFFF)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (exception_address == 0) {
|
|
||||||
scan_all_watchpoint.address = 0;
|
|
||||||
scan_all_watchpoint.rw = WPT_WRITE;
|
|
||||||
scan_all_watchpoint.next = 0;
|
|
||||||
scan_all_watchpoint.unique_id = 0x5CA8;
|
|
||||||
|
|
||||||
*hit_watchpoint = &scan_all_watchpoint;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
if (((exception_address ^ wp->address) & (~wp->mask)) == 0) {
|
|
||||||
*hit_watchpoint = wp;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
nds32->register_map = nds32_v3_register_mapping;
|
|
||||||
nds32->get_debug_reason = nds32_v3_get_debug_reason;
|
|
||||||
nds32->enter_debug_state = nds32_v3_debug_entry;
|
|
||||||
nds32->leave_debug_state = nds32_v3_leave_debug_state;
|
|
||||||
nds32->get_watched_address = nds32_v3_get_exception_address;
|
|
||||||
|
|
||||||
/* Init target->arch_info in nds32_init_arch_info().
|
|
||||||
* After this, user could use target_to_nds32() to get nds32 object */
|
|
||||||
nds32_init_arch_info(target, nds32);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_run_algorithm(struct target *target,
|
|
||||||
int num_mem_params,
|
|
||||||
struct mem_param *mem_params,
|
|
||||||
int num_reg_params,
|
|
||||||
struct reg_param *reg_params,
|
|
||||||
target_addr_t entry_point,
|
|
||||||
target_addr_t exit_point,
|
|
||||||
int timeout_ms,
|
|
||||||
void *arch_info)
|
|
||||||
{
|
|
||||||
LOG_WARNING("Not implemented: %s", __func__);
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_read_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_addr_t physical_address;
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
/* When DEX is set to one, hardware will enforce the following behavior without
|
|
||||||
* modifying the corresponding control bits in PSW.
|
|
||||||
*
|
|
||||||
* Disable all interrupts
|
|
||||||
* Become superuser mode
|
|
||||||
* Turn off IT/DT
|
|
||||||
* Use MMU_CFG.DE as the data access endian
|
|
||||||
* Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
|
|
||||||
* Disable audio special features
|
|
||||||
* Disable inline function call
|
|
||||||
*
|
|
||||||
* Because hardware will turn off IT/DT by default, it MUST translate virtual address
|
|
||||||
* to physical address.
|
|
||||||
*/
|
|
||||||
if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
|
||||||
address = physical_address;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
int result;
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
/* give arbitrary initial value to avoid warning messages */
|
|
||||||
enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
/* Use bus mode to access memory during virtual hosting */
|
|
||||||
origin_access_channel = memory->access_channel;
|
|
||||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
|
||||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = nds32_read_buffer(target, address, size, buffer);
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
/* Restore access_channel after virtual hosting */
|
|
||||||
memory->access_channel = origin_access_channel;
|
|
||||||
aice_memory_access(aice, origin_access_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_write_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_addr_t physical_address;
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
/* When DEX is set to one, hardware will enforce the following behavior without
|
|
||||||
* modifying the corresponding control bits in PSW.
|
|
||||||
*
|
|
||||||
* Disable all interrupts
|
|
||||||
* Become superuser mode
|
|
||||||
* Turn off IT/DT
|
|
||||||
* Use MMU_CFG.DE as the data access endian
|
|
||||||
* Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
|
|
||||||
* Disable audio special features
|
|
||||||
* Disable inline function call
|
|
||||||
*
|
|
||||||
* Because hardware will turn off IT/DT by default, it MUST translate virtual address
|
|
||||||
* to physical address.
|
|
||||||
*/
|
|
||||||
if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
|
||||||
address = physical_address;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
enum nds_memory_access origin_access_channel;
|
|
||||||
origin_access_channel = memory->access_channel;
|
|
||||||
|
|
||||||
/* If target has no cache, use BUS mode to access memory. */
|
|
||||||
if ((memory->dcache.line_size == 0)
|
|
||||||
|| (memory->dcache.enable == false)) {
|
|
||||||
/* There is no Dcache or Dcache is disabled. */
|
|
||||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
|
||||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
int result;
|
|
||||||
result = nds32_gdb_fileio_write_memory(nds32, address, size, buffer);
|
|
||||||
|
|
||||||
if (origin_access_channel == NDS_MEMORY_ACC_CPU) {
|
|
||||||
memory->access_channel = NDS_MEMORY_ACC_CPU;
|
|
||||||
aice_memory_access(aice, NDS_MEMORY_ACC_CPU);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nds32_write_buffer(target, address, size, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_read_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_addr_t physical_address;
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
/* When DEX is set to one, hardware will enforce the following behavior without
|
|
||||||
* modifying the corresponding control bits in PSW.
|
|
||||||
*
|
|
||||||
* Disable all interrupts
|
|
||||||
* Become superuser mode
|
|
||||||
* Turn off IT/DT
|
|
||||||
* Use MMU_CFG.DE as the data access endian
|
|
||||||
* Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
|
|
||||||
* Disable audio special features
|
|
||||||
* Disable inline function call
|
|
||||||
*
|
|
||||||
* Because hardware will turn off IT/DT by default, it MUST translate virtual address
|
|
||||||
* to physical address.
|
|
||||||
*/
|
|
||||||
if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
|
||||||
address = physical_address;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
/* give arbitrary initial value to avoid warning messages */
|
|
||||||
enum nds_memory_access origin_access_channel = NDS_MEMORY_ACC_CPU;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
/* Use bus mode to access memory during virtual hosting */
|
|
||||||
origin_access_channel = memory->access_channel;
|
|
||||||
memory->access_channel = NDS_MEMORY_ACC_BUS;
|
|
||||||
aice_memory_access(aice, NDS_MEMORY_ACC_BUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = nds32_read_memory(target, address, size, count, buffer);
|
|
||||||
|
|
||||||
if (nds32->hit_syscall) {
|
|
||||||
/* Restore access_channel after virtual hosting */
|
|
||||||
memory->access_channel = origin_access_channel;
|
|
||||||
aice_memory_access(aice, origin_access_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_write_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
|
||||||
{
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
struct nds32_memory *memory = &(nds32->memory);
|
|
||||||
|
|
||||||
if ((memory->access_channel == NDS_MEMORY_ACC_CPU) &&
|
|
||||||
(target->state != TARGET_HALTED)) {
|
|
||||||
LOG_WARNING("target was not halted");
|
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_addr_t physical_address;
|
|
||||||
/* BUG: If access range crosses multiple pages, the translation will not correct
|
|
||||||
* for second page or so. */
|
|
||||||
|
|
||||||
/* When DEX is set to one, hardware will enforce the following behavior without
|
|
||||||
* modifying the corresponding control bits in PSW.
|
|
||||||
*
|
|
||||||
* Disable all interrupts
|
|
||||||
* Become superuser mode
|
|
||||||
* Turn off IT/DT
|
|
||||||
* Use MMU_CFG.DE as the data access endian
|
|
||||||
* Use MMU_CFG.DRDE as the device register access endian if MMU_CTL.DREE is asserted
|
|
||||||
* Disable audio special features
|
|
||||||
* Disable inline function call
|
|
||||||
*
|
|
||||||
* Because hardware will turn off IT/DT by default, it MUST translate virtual address
|
|
||||||
* to physical address.
|
|
||||||
*/
|
|
||||||
if (target->type->virt2phys(target, address, &physical_address) == ERROR_OK)
|
|
||||||
address = physical_address;
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return nds32_write_memory(target, address, size, count, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nds32_v3_init_target(struct command_context *cmd_ctx,
|
|
||||||
struct target *target)
|
|
||||||
{
|
|
||||||
/* Initialize anything we can set up without talking to the target */
|
|
||||||
struct nds32 *nds32 = target_to_nds32(target);
|
|
||||||
|
|
||||||
nds32_init(nds32);
|
|
||||||
|
|
||||||
target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
|
|
||||||
target->fileio_info->identifier = NULL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_V3_COMMON_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_V3_COMMON_H
|
|
||||||
|
|
||||||
#include "target.h"
|
|
||||||
|
|
||||||
struct nds32_v3_common_callback {
|
|
||||||
int (*check_interrupt_stack)(struct nds32 *nds32);
|
|
||||||
int (*restore_interrupt_stack)(struct nds32 *nds32);
|
|
||||||
int (*activate_hardware_breakpoint)(struct target *target);
|
|
||||||
int (*activate_hardware_watchpoint)(struct target *target);
|
|
||||||
int (*deactivate_hardware_breakpoint)(struct target *target);
|
|
||||||
int (*deactivate_hardware_watchpoint)(struct target *target);
|
|
||||||
};
|
|
||||||
|
|
||||||
void nds32_v3_common_register_callback(struct nds32_v3_common_callback *callback);
|
|
||||||
int nds32_v3_target_request_data(struct target *target,
|
|
||||||
uint32_t size, uint8_t *buffer);
|
|
||||||
int nds32_v3_checksum_memory(struct target *target,
|
|
||||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
|
||||||
int nds32_v3_hit_watchpoint(struct target *target,
|
|
||||||
struct watchpoint **hit_watchpoint);
|
|
||||||
int nds32_v3_target_create_common(struct target *target, struct nds32 *nds32);
|
|
||||||
int nds32_v3_run_algorithm(struct target *target,
|
|
||||||
int num_mem_params,
|
|
||||||
struct mem_param *mem_params,
|
|
||||||
int num_reg_params,
|
|
||||||
struct reg_param *reg_params,
|
|
||||||
target_addr_t entry_point,
|
|
||||||
target_addr_t exit_point,
|
|
||||||
int timeout_ms,
|
|
||||||
void *arch_info);
|
|
||||||
int nds32_v3_read_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint8_t *buffer);
|
|
||||||
int nds32_v3_write_buffer(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, const uint8_t *buffer);
|
|
||||||
int nds32_v3_read_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer);
|
|
||||||
int nds32_v3_write_memory(struct target *target, target_addr_t address,
|
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer);
|
|
||||||
int nds32_v3_init_target(struct command_context *cmd_ctx,
|
|
||||||
struct target *target);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_V3_COMMON_H */
|
|
|
@ -1,495 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "breakpoints.h"
|
|
||||||
#include "nds32_cmd.h"
|
|
||||||
#include "nds32_aice.h"
|
|
||||||
#include "nds32_v3m.h"
|
|
||||||
#include "nds32_v3_common.h"
|
|
||||||
|
|
||||||
static int nds32_v3m_activate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
unsigned brp_num = nds32_v3m->n_hbr - 1;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT) {
|
|
||||||
/* already set at nds32_v3m_add_breakpoint() */
|
|
||||||
continue;
|
|
||||||
} else if (bp->type == BKPT_HARD) {
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + brp_num, bp->address);
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + brp_num, 0);
|
|
||||||
|
|
||||||
if (nds32_v3m->nds32.memory.address_translation)
|
|
||||||
/* enable breakpoint (virtual address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x2);
|
|
||||||
else
|
|
||||||
/* enable breakpoint (physical address) */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0xA);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
|
|
||||||
bp->address);
|
|
||||||
|
|
||||||
brp_num--;
|
|
||||||
} else {
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_deactivate_hardware_breakpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct breakpoint *bp;
|
|
||||||
unsigned brp_num = nds32_v3m->n_hbr - 1;
|
|
||||||
|
|
||||||
for (bp = target->breakpoints; bp; bp = bp->next) {
|
|
||||||
if (bp->type == BKPT_SOFT)
|
|
||||||
continue;
|
|
||||||
else if (bp->type == BKPT_HARD)
|
|
||||||
/* disable breakpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + brp_num, 0x0);
|
|
||||||
else
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware BP %u at %08" TARGET_PRIxADDR, brp_num,
|
|
||||||
bp->address);
|
|
||||||
|
|
||||||
brp_num--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_activate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct watchpoint *wp;
|
|
||||||
int32_t wp_num = 0;
|
|
||||||
uint32_t wp_config = 0;
|
|
||||||
bool ld_stop, st_stop;
|
|
||||||
|
|
||||||
if (nds32_v3m->nds32.global_stop)
|
|
||||||
ld_stop = st_stop = false;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
|
|
||||||
if (wp_num < nds32_v3m->used_n_wp) {
|
|
||||||
wp->mask = wp->length - 1;
|
|
||||||
if ((wp->address % wp->length) != 0)
|
|
||||||
wp->mask = (wp->mask << 1) + 1;
|
|
||||||
|
|
||||||
if (wp->rw == WPT_READ)
|
|
||||||
wp_config = 0x3;
|
|
||||||
else if (wp->rw == WPT_WRITE)
|
|
||||||
wp_config = 0x5;
|
|
||||||
else if (wp->rw == WPT_ACCESS)
|
|
||||||
wp_config = 0x7;
|
|
||||||
|
|
||||||
/* set/unset physical address bit of BPCn according to PSW.DT */
|
|
||||||
if (nds32_v3m->nds32.memory.address_translation == false)
|
|
||||||
wp_config |= 0x8;
|
|
||||||
|
|
||||||
/* set address */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPA0 + wp_num,
|
|
||||||
wp->address - (wp->address % wp->length));
|
|
||||||
/* set mask */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPAM0 + wp_num, wp->mask);
|
|
||||||
/* enable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, wp_config);
|
|
||||||
|
|
||||||
LOG_DEBUG("Add hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
|
||||||
" mask %08" PRIx32, wp_num, wp->address, wp->mask);
|
|
||||||
|
|
||||||
wp_num++;
|
|
||||||
} else if (nds32_v3m->nds32.global_stop) {
|
|
||||||
if (wp->rw == WPT_READ)
|
|
||||||
ld_stop = true;
|
|
||||||
else if (wp->rw == WPT_WRITE)
|
|
||||||
st_stop = true;
|
|
||||||
else if (wp->rw == WPT_ACCESS)
|
|
||||||
ld_stop = st_stop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds32_v3m->nds32.global_stop) {
|
|
||||||
uint32_t edm_ctl;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
|
||||||
if (ld_stop)
|
|
||||||
edm_ctl |= 0x10;
|
|
||||||
if (st_stop)
|
|
||||||
edm_ctl |= 0x20;
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_deactivate_hardware_watchpoint(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
struct watchpoint *wp;
|
|
||||||
int32_t wp_num = 0;
|
|
||||||
bool clean_global_stop = false;
|
|
||||||
|
|
||||||
for (wp = target->watchpoints; wp; wp = wp->next) {
|
|
||||||
|
|
||||||
if (wp_num < nds32_v3m->used_n_wp) {
|
|
||||||
/* disable watchpoint */
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + wp_num, 0x0);
|
|
||||||
|
|
||||||
LOG_DEBUG("Remove hardware watchpoint %" PRId32 " at %08" TARGET_PRIxADDR
|
|
||||||
" mask %08" PRIx32, wp_num, wp->address, wp->mask);
|
|
||||||
wp_num++;
|
|
||||||
} else if (nds32_v3m->nds32.global_stop) {
|
|
||||||
clean_global_stop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clean_global_stop) {
|
|
||||||
uint32_t edm_ctl;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CTL, &edm_ctl);
|
|
||||||
edm_ctl = edm_ctl & (~0x30);
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_EDM_CTL, edm_ctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_check_interrupt_stack(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
uint32_t val_ir0;
|
|
||||||
uint32_t value;
|
|
||||||
|
|
||||||
/* Save interrupt level */
|
|
||||||
nds32_get_mapped_reg(nds32, IR0, &val_ir0);
|
|
||||||
nds32->current_interrupt_level = (val_ir0 >> 1) & 0x3;
|
|
||||||
|
|
||||||
if (nds32_reach_max_interrupt_level(nds32))
|
|
||||||
LOG_ERROR("<-- TARGET ERROR! Reaching the max interrupt stack level %" PRIu32 ". -->",
|
|
||||||
nds32->current_interrupt_level);
|
|
||||||
|
|
||||||
/* backup $ir6 to avoid suppressed exception overwrite */
|
|
||||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_restore_interrupt_stack(struct nds32 *nds32)
|
|
||||||
{
|
|
||||||
uint32_t value;
|
|
||||||
|
|
||||||
/* get backup value from cache */
|
|
||||||
/* then set back to make the register dirty */
|
|
||||||
nds32_get_mapped_reg(nds32, IR0, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR0, value);
|
|
||||||
|
|
||||||
nds32_get_mapped_reg(nds32, IR6, &value);
|
|
||||||
nds32_set_mapped_reg(nds32, IR6, value);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_deassert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
CHECK_RETVAL(nds32_poll(target));
|
|
||||||
|
|
||||||
if (target->state != TARGET_HALTED) {
|
|
||||||
/* reset only */
|
|
||||||
LOG_WARNING("%s: ran after reset and before halt ...",
|
|
||||||
target_name(target));
|
|
||||||
retval = target_halt(target);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_add_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v3m->nds32);
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v3m->next_hbr_index < nds32_v3m->next_hwp_index) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many "
|
|
||||||
"hardware breakpoints/watchpoints! "
|
|
||||||
"The limit of combined hardware "
|
|
||||||
"breakpoints/watchpoints is %" PRId32 ". -->",
|
|
||||||
nds32_v3m->n_hbr);
|
|
||||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
|
||||||
"hardware breakpoint: %" PRId32 ", hardware "
|
|
||||||
"watchpoints: %" PRId32 ". -->",
|
|
||||||
nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
|
|
||||||
nds32_v3m->used_n_wp);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v3m->next_hbr_index--;
|
|
||||||
|
|
||||||
/* hardware breakpoint insertion occurs before 'continue' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
result = nds32_add_software_breakpoint(target, breakpoint);
|
|
||||||
if (result != ERROR_OK) {
|
|
||||||
/* auto convert to hardware breakpoint if failed */
|
|
||||||
if (nds32->auto_convert_hw_bp) {
|
|
||||||
/* convert to hardware breakpoint */
|
|
||||||
breakpoint->type = BKPT_HARD;
|
|
||||||
|
|
||||||
return nds32_v3m_add_breakpoint(target, breakpoint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_remove_breakpoint(struct target *target,
|
|
||||||
struct breakpoint *breakpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
|
|
||||||
if (breakpoint->type == BKPT_HARD) {
|
|
||||||
if (nds32_v3m->next_hbr_index >= nds32_v3m->n_hbr - 1)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* update next place to put hardware breakpoint */
|
|
||||||
nds32_v3m->next_hbr_index++;
|
|
||||||
|
|
||||||
/* hardware breakpoint removal occurs after 'halted' actually */
|
|
||||||
return ERROR_OK;
|
|
||||||
} else if (breakpoint->type == BKPT_SOFT) {
|
|
||||||
return nds32_remove_software_breakpoint(target, breakpoint);
|
|
||||||
} else /* unrecognized breakpoint type */
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_add_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
|
|
||||||
/* check hardware resource */
|
|
||||||
if (nds32_v3m->next_hwp_index >= nds32_v3m->n_hwp) {
|
|
||||||
/* No hardware resource */
|
|
||||||
if (nds32_v3m->nds32.global_stop) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
|
||||||
"watchpoints exceeds the hardware "
|
|
||||||
"resources. Stop at every load/store "
|
|
||||||
"instruction to check for watchpoint matches. -->");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
|
||||||
"watchpoints! The limit of hardware watchpoints "
|
|
||||||
"is %" PRId32 ". -->", nds32_v3m->n_hwp);
|
|
||||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
|
||||||
"hardware watchpoint: %" PRId32 ". -->",
|
|
||||||
nds32_v3m->used_n_wp);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nds32_v3m->next_hwp_index > nds32_v3m->next_hbr_index) {
|
|
||||||
/* No hardware resource */
|
|
||||||
if (nds32_v3m->nds32.global_stop) {
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! The number of "
|
|
||||||
"watchpoints exceeds the hardware "
|
|
||||||
"resources. Stop at every load/store "
|
|
||||||
"instruction to check for watchpoint matches. -->");
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WARNING("<-- TARGET WARNING! Insert too many hardware "
|
|
||||||
"breakpoints/watchpoints! The limit of combined "
|
|
||||||
"hardware breakpoints/watchpoints is %" PRId32 ". -->",
|
|
||||||
nds32_v3m->n_hbr);
|
|
||||||
LOG_WARNING("<-- TARGET STATUS: Inserted number of "
|
|
||||||
"hardware breakpoint: %" PRId32 ", hardware "
|
|
||||||
"watchpoints: %" PRId32 ". -->",
|
|
||||||
nds32_v3m->n_hbr - nds32_v3m->next_hbr_index - 1,
|
|
||||||
nds32_v3m->used_n_wp);
|
|
||||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware watchpoint */
|
|
||||||
nds32_v3m->next_hwp_index++;
|
|
||||||
nds32_v3m->used_n_wp++;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nds32_v3m_remove_watchpoint(struct target *target,
|
|
||||||
struct watchpoint *watchpoint)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
|
|
||||||
if (nds32_v3m->next_hwp_index <= 0) {
|
|
||||||
if (nds32_v3m->nds32.global_stop)
|
|
||||||
return ERROR_OK;
|
|
||||||
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update next place to put hardware watchpoint */
|
|
||||||
nds32_v3m->next_hwp_index--;
|
|
||||||
nds32_v3m->used_n_wp--;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct nds32_v3_common_callback nds32_v3m_common_callback = {
|
|
||||||
.check_interrupt_stack = nds32_v3m_check_interrupt_stack,
|
|
||||||
.restore_interrupt_stack = nds32_v3m_restore_interrupt_stack,
|
|
||||||
.activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint,
|
|
||||||
.activate_hardware_watchpoint = nds32_v3m_activate_hardware_watchpoint,
|
|
||||||
.deactivate_hardware_breakpoint = nds32_v3m_deactivate_hardware_breakpoint,
|
|
||||||
.deactivate_hardware_watchpoint = nds32_v3m_deactivate_hardware_watchpoint,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int nds32_v3m_target_create(struct target *target, Jim_Interp *interp)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m;
|
|
||||||
|
|
||||||
nds32_v3m = calloc(1, sizeof(*nds32_v3m));
|
|
||||||
if (!nds32_v3m)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
nds32_v3_common_register_callback(&nds32_v3m_common_callback);
|
|
||||||
nds32_v3_target_create_common(target, &(nds32_v3m->nds32));
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* talk to the target and set things up */
|
|
||||||
static int nds32_v3m_examine(struct target *target)
|
|
||||||
{
|
|
||||||
struct nds32_v3m_common *nds32_v3m = target_to_nds32_v3m(target);
|
|
||||||
struct nds32 *nds32 = &(nds32_v3m->nds32);
|
|
||||||
struct aice_port_s *aice = target_to_aice(target);
|
|
||||||
|
|
||||||
if (!target_was_examined(target)) {
|
|
||||||
CHECK_RETVAL(nds32_edm_config(nds32));
|
|
||||||
|
|
||||||
if (nds32->reset_halt_as_examine)
|
|
||||||
CHECK_RETVAL(nds32_reset_halt(nds32));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t edm_cfg;
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_EDM_CFG, &edm_cfg);
|
|
||||||
|
|
||||||
/* get the number of hardware breakpoints */
|
|
||||||
nds32_v3m->n_hbr = (edm_cfg & 0x7) + 1;
|
|
||||||
nds32_v3m->used_n_wp = 0;
|
|
||||||
|
|
||||||
/* get the number of hardware watchpoints */
|
|
||||||
/* If the WP field is hardwired to zero, it means this is a
|
|
||||||
* simple breakpoint. Otherwise, if the WP field is writable
|
|
||||||
* then it means this is a regular watchpoints. */
|
|
||||||
nds32_v3m->n_hwp = 0;
|
|
||||||
for (int32_t i = 0 ; i < nds32_v3m->n_hbr ; i++) {
|
|
||||||
/** check the hardware breakpoint is simple or not */
|
|
||||||
uint32_t tmp_value;
|
|
||||||
aice_write_debug_reg(aice, NDS_EDM_SR_BPC0 + i, 0x1);
|
|
||||||
aice_read_debug_reg(aice, NDS_EDM_SR_BPC0 + i, &tmp_value);
|
|
||||||
|
|
||||||
if (tmp_value)
|
|
||||||
nds32_v3m->n_hwp++;
|
|
||||||
}
|
|
||||||
/* hardware breakpoint is inserted from high index to low index */
|
|
||||||
nds32_v3m->next_hbr_index = nds32_v3m->n_hbr - 1;
|
|
||||||
/* hardware watchpoint is inserted from low index to high index */
|
|
||||||
nds32_v3m->next_hwp_index = 0;
|
|
||||||
|
|
||||||
LOG_INFO("%s: total hardware breakpoint %" PRId32 " (simple breakpoint %" PRId32 ")",
|
|
||||||
target_name(target), nds32_v3m->n_hbr, nds32_v3m->n_hbr - nds32_v3m->n_hwp);
|
|
||||||
LOG_INFO("%s: total hardware watchpoint %" PRId32, target_name(target), nds32_v3m->n_hwp);
|
|
||||||
|
|
||||||
nds32->target->state = TARGET_RUNNING;
|
|
||||||
nds32->target->debug_reason = DBG_REASON_NOTHALTED;
|
|
||||||
|
|
||||||
target_set_examined(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds methods for NDS32 V3m targets. */
|
|
||||||
struct target_type nds32_v3m_target = {
|
|
||||||
.name = "nds32_v3m",
|
|
||||||
|
|
||||||
.poll = nds32_poll,
|
|
||||||
.arch_state = nds32_arch_state,
|
|
||||||
|
|
||||||
.target_request_data = nds32_v3_target_request_data,
|
|
||||||
|
|
||||||
.halt = nds32_halt,
|
|
||||||
.resume = nds32_resume,
|
|
||||||
.step = nds32_step,
|
|
||||||
|
|
||||||
.assert_reset = nds32_assert_reset,
|
|
||||||
.deassert_reset = nds32_v3m_deassert_reset,
|
|
||||||
|
|
||||||
/* register access */
|
|
||||||
.get_gdb_reg_list = nds32_get_gdb_reg_list,
|
|
||||||
|
|
||||||
/* memory access */
|
|
||||||
.read_buffer = nds32_v3_read_buffer,
|
|
||||||
.write_buffer = nds32_v3_write_buffer,
|
|
||||||
.read_memory = nds32_v3_read_memory,
|
|
||||||
.write_memory = nds32_v3_write_memory,
|
|
||||||
|
|
||||||
.checksum_memory = nds32_v3_checksum_memory,
|
|
||||||
|
|
||||||
/* breakpoint/watchpoint */
|
|
||||||
.add_breakpoint = nds32_v3m_add_breakpoint,
|
|
||||||
.remove_breakpoint = nds32_v3m_remove_breakpoint,
|
|
||||||
.add_watchpoint = nds32_v3m_add_watchpoint,
|
|
||||||
.remove_watchpoint = nds32_v3m_remove_watchpoint,
|
|
||||||
.hit_watchpoint = nds32_v3_hit_watchpoint,
|
|
||||||
|
|
||||||
/* MMU */
|
|
||||||
.mmu = nds32_mmu,
|
|
||||||
.virt2phys = nds32_virtual_to_physical,
|
|
||||||
.read_phys_memory = nds32_read_phys_memory,
|
|
||||||
.write_phys_memory = nds32_write_phys_memory,
|
|
||||||
|
|
||||||
.run_algorithm = nds32_v3_run_algorithm,
|
|
||||||
|
|
||||||
.commands = nds32_command_handlers,
|
|
||||||
.target_create = nds32_v3m_target_create,
|
|
||||||
.init_target = nds32_v3_init_target,
|
|
||||||
.examine = nds32_v3m_examine,
|
|
||||||
|
|
||||||
.get_gdb_fileio_info = nds32_get_gdb_fileio_info,
|
|
||||||
.gdb_fileio_end = nds32_gdb_fileio_end,
|
|
||||||
};
|
|
|
@ -1,40 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2013 Andes Technology *
|
|
||||||
* Hsiangkai Wang <hkwang@andestech.com> *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef OPENOCD_TARGET_NDS32_V3M_H
|
|
||||||
#define OPENOCD_TARGET_NDS32_V3M_H
|
|
||||||
|
|
||||||
#include "nds32.h"
|
|
||||||
|
|
||||||
struct nds32_v3m_common {
|
|
||||||
struct nds32 nds32;
|
|
||||||
|
|
||||||
/** number of hardware breakpoints */
|
|
||||||
int32_t n_hbr;
|
|
||||||
|
|
||||||
/** number of hardware watchpoints */
|
|
||||||
int32_t n_hwp;
|
|
||||||
|
|
||||||
/** number of used hardware watchpoints */
|
|
||||||
int32_t used_n_wp;
|
|
||||||
|
|
||||||
/** next hardware breakpoint index */
|
|
||||||
/** for simple breakpoints, hardware breakpoints are inserted
|
|
||||||
* from high index to low index */
|
|
||||||
int32_t next_hbr_index;
|
|
||||||
|
|
||||||
/** next hardware watchpoint index */
|
|
||||||
/** increase from low index to high index */
|
|
||||||
int32_t next_hwp_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct nds32_v3m_common *target_to_nds32_v3m(struct target *target)
|
|
||||||
{
|
|
||||||
return container_of(target->arch_info, struct nds32_v3m_common, nds32);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_NDS32_V3M_H */
|
|
|
@ -934,7 +934,7 @@ static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info,
|
||||||
void *t = NULL;
|
void *t = NULL;
|
||||||
struct target *target = jtag_info->target;
|
struct target *target = jtag_info->target;
|
||||||
if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) {
|
if ((target->endianness == TARGET_BIG_ENDIAN) && (size != 1)) {
|
||||||
t = malloc(count * size * sizeof(uint8_t));
|
t = calloc(count * size, sizeof(uint8_t));
|
||||||
if (!t) {
|
if (!t) {
|
||||||
LOG_ERROR("Out of memory");
|
LOG_ERROR("Out of memory");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -947,6 +947,9 @@ static int or1k_adv_jtag_write_memory(struct or1k_jtag *jtag_info,
|
||||||
case 2:
|
case 2:
|
||||||
buf_bswap16(t, buffer, size * count);
|
buf_bswap16(t, buffer, size * count);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
free(t);
|
||||||
|
return ERROR_TARGET_FAILURE;
|
||||||
}
|
}
|
||||||
buffer = t;
|
buffer = t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,43 +241,37 @@ int target_rtt_find_control_block(struct target *target,
|
||||||
target_addr_t *address, size_t size, const char *id, bool *found,
|
target_addr_t *address, size_t size, const char *id, bool *found,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
|
target_addr_t address_end = *address + size;
|
||||||
uint8_t buf[1024];
|
uint8_t buf[1024];
|
||||||
|
|
||||||
*found = false;
|
*found = false;
|
||||||
|
|
||||||
size_t j = 0;
|
size_t id_matched_length = 0;
|
||||||
size_t cb_offset = 0;
|
|
||||||
const size_t id_length = strlen(id);
|
const size_t id_length = strlen(id);
|
||||||
|
|
||||||
LOG_INFO("rtt: Searching for control block '%s'", id);
|
LOG_INFO("rtt: Searching for control block '%s'", id);
|
||||||
|
|
||||||
for (target_addr_t addr = 0; addr < size; addr = addr + sizeof(buf)) {
|
for (target_addr_t addr = *address; addr < address_end; addr += sizeof(buf)) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
const size_t buf_size = MIN(sizeof(buf), size - addr);
|
const size_t buf_size = MIN(sizeof(buf), address_end - addr);
|
||||||
ret = target_read_buffer(target, *address + addr, buf_size, buf);
|
ret = target_read_buffer(target, addr, buf_size, buf);
|
||||||
|
|
||||||
if (ret != ERROR_OK)
|
if (ret != ERROR_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
size_t start = 0;
|
for (size_t buf_off = 0; buf_off < buf_size; buf_off++) {
|
||||||
size_t i = 0;
|
if (id_matched_length > 0 &&
|
||||||
|
buf[buf_off] != id[id_matched_length]) {
|
||||||
while (i < buf_size) {
|
/* Start from beginning */
|
||||||
if (buf[i] != id[j]) {
|
id_matched_length = 0;
|
||||||
start++;
|
|
||||||
cb_offset++;
|
|
||||||
i = start;
|
|
||||||
j = 0;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
if (buf[buf_off] == id[id_matched_length])
|
||||||
j++;
|
id_matched_length++;
|
||||||
|
|
||||||
if (j == id_length) {
|
if (id_matched_length == id_length) {
|
||||||
*address = *address + cb_offset;
|
*address = addr + buf_off + 1 - id_length;
|
||||||
*found = true;
|
*found = true;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,11 +114,22 @@ proc ocd_process_reset_inner { MODE } {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if { ![$t was_examined] } {
|
||||||
# don't wait for targets where examination is deferred
|
# don't wait for targets where examination is deferred
|
||||||
# they can not be halted anyway at this point
|
# they can not be halted anyway at this point
|
||||||
if { ![$t was_examined] && [$t examine_deferred] } {
|
if { [$t examine_deferred] } {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
# try to re-examine or target state will be unknown
|
||||||
|
$t invoke-event examine-start
|
||||||
|
set err [catch "$t arp_examine allow-defer"]
|
||||||
|
if { $err } {
|
||||||
|
$t invoke-event examine-fail
|
||||||
|
return -code error [format "TARGET: %s - Not examined" $t]
|
||||||
|
} else {
|
||||||
|
$t invoke-event examine-end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Wait up to 1 second for target to halt. Why 1sec? Cause
|
# Wait up to 1 second for target to halt. Why 1sec? Cause
|
||||||
# the JTAG tap reset signal might be hooked to a slow
|
# the JTAG tap reset signal might be hooked to a slow
|
||||||
|
|
|
@ -92,9 +92,6 @@ extern struct target_type dsp5680xx_target;
|
||||||
extern struct target_type testee_target;
|
extern struct target_type testee_target;
|
||||||
extern struct target_type avr32_ap7k_target;
|
extern struct target_type avr32_ap7k_target;
|
||||||
extern struct target_type hla_target;
|
extern struct target_type hla_target;
|
||||||
extern struct target_type nds32_v2_target;
|
|
||||||
extern struct target_type nds32_v3_target;
|
|
||||||
extern struct target_type nds32_v3m_target;
|
|
||||||
extern struct target_type esp32_target;
|
extern struct target_type esp32_target;
|
||||||
extern struct target_type esp32s2_target;
|
extern struct target_type esp32s2_target;
|
||||||
extern struct target_type esp32s3_target;
|
extern struct target_type esp32s3_target;
|
||||||
|
@ -132,9 +129,6 @@ static struct target_type *target_types[] = {
|
||||||
&testee_target,
|
&testee_target,
|
||||||
&avr32_ap7k_target,
|
&avr32_ap7k_target,
|
||||||
&hla_target,
|
&hla_target,
|
||||||
&nds32_v2_target,
|
|
||||||
&nds32_v3_target,
|
|
||||||
&nds32_v3m_target,
|
|
||||||
&esp32_target,
|
&esp32_target,
|
||||||
&esp32s2_target,
|
&esp32s2_target,
|
||||||
&esp32s3_target,
|
&esp32s3_target,
|
||||||
|
@ -4253,11 +4247,19 @@ static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filen
|
||||||
|
|
||||||
/* max should be (largest sample + 1)
|
/* max should be (largest sample + 1)
|
||||||
* Refer to binutils/gprof/hist.c (find_histogram_for_pc) */
|
* Refer to binutils/gprof/hist.c (find_histogram_for_pc) */
|
||||||
|
if (max < UINT32_MAX)
|
||||||
max++;
|
max++;
|
||||||
|
|
||||||
|
/* gprof requires (max - min) >= 2 */
|
||||||
|
while ((max - min) < 2) {
|
||||||
|
if (max < UINT32_MAX)
|
||||||
|
max++;
|
||||||
|
else
|
||||||
|
min--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int address_space = max - min;
|
uint32_t address_space = max - min;
|
||||||
assert(address_space >= 2);
|
|
||||||
|
|
||||||
/* FIXME: What is the reasonable number of buckets?
|
/* FIXME: What is the reasonable number of buckets?
|
||||||
* The profiling result will be more accurate if there are enough buckets. */
|
* The profiling result will be more accurate if there are enough buckets. */
|
||||||
|
@ -4333,6 +4335,19 @@ COMMAND_HANDLER(handle_profile_command)
|
||||||
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset);
|
||||||
|
|
||||||
|
uint32_t start_address = 0;
|
||||||
|
uint32_t end_address = 0;
|
||||||
|
bool with_range = false;
|
||||||
|
if (CMD_ARGC == 4) {
|
||||||
|
with_range = true;
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address);
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address);
|
||||||
|
if (start_address > end_address || (end_address - start_address) < 2) {
|
||||||
|
command_print(CMD, "Error: end - start < 2");
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM);
|
uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM);
|
||||||
if (!samples) {
|
if (!samples) {
|
||||||
LOG_ERROR("No memory to store samples.");
|
LOG_ERROR("No memory to store samples.");
|
||||||
|
@ -4385,15 +4400,6 @@ COMMAND_HANDLER(handle_profile_command)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t start_address = 0;
|
|
||||||
uint32_t end_address = 0;
|
|
||||||
bool with_range = false;
|
|
||||||
if (CMD_ARGC == 4) {
|
|
||||||
with_range = true;
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address);
|
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
write_gmon(samples, num_of_samples, CMD_ARGV[1],
|
write_gmon(samples, num_of_samples, CMD_ARGV[1],
|
||||||
with_range, start_address, end_address, target, duration_ms);
|
with_range, start_address, end_address, target, duration_ms);
|
||||||
command_print(CMD, "Wrote %s", CMD_ARGV[1]);
|
command_print(CMD, "Wrote %s", CMD_ARGV[1]);
|
||||||
|
@ -6435,16 +6441,52 @@ static int jim_target_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct target_list *
|
||||||
|
__attribute__((warn_unused_result))
|
||||||
|
create_target_list_node(Jim_Obj *const name) {
|
||||||
|
int len;
|
||||||
|
const char *targetname = Jim_GetString(name, &len);
|
||||||
|
struct target *target = get_target(targetname);
|
||||||
|
LOG_DEBUG("%s ", targetname);
|
||||||
|
if (!target)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct target_list *new = malloc(sizeof(struct target_list));
|
||||||
|
if (!new) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
new->target = target;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_target_with_common_rtos_type(struct list_head *lh, struct target **result)
|
||||||
|
{
|
||||||
|
struct target *target = NULL;
|
||||||
|
struct target_list *curr;
|
||||||
|
foreach_smp_target(curr, lh) {
|
||||||
|
struct rtos *curr_rtos = curr->target->rtos;
|
||||||
|
if (curr_rtos) {
|
||||||
|
if (target && target->rtos && target->rtos->type != curr_rtos->type) {
|
||||||
|
LOG_ERROR("Different rtos types in members of one smp target!");
|
||||||
|
return JIM_ERR;
|
||||||
|
}
|
||||||
|
target = curr->target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*result = target;
|
||||||
|
return JIM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
const char *targetname;
|
|
||||||
int retval, len;
|
|
||||||
static int smp_group = 1;
|
static int smp_group = 1;
|
||||||
struct target *target = NULL;
|
|
||||||
struct target_list *head, *new;
|
|
||||||
|
|
||||||
retval = 0;
|
if (argc == 1) {
|
||||||
|
LOG_DEBUG("Empty SMP target");
|
||||||
|
return JIM_OK;
|
||||||
|
}
|
||||||
LOG_DEBUG("%d", argc);
|
LOG_DEBUG("%d", argc);
|
||||||
/* argv[1] = target to associate in smp
|
/* argv[1] = target to associate in smp
|
||||||
* argv[2] = target to associate in smp
|
* argv[2] = target to associate in smp
|
||||||
|
@ -6458,27 +6500,24 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
}
|
}
|
||||||
INIT_LIST_HEAD(lh);
|
INIT_LIST_HEAD(lh);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
|
struct target_list *new = create_target_list_node(argv[i]);
|
||||||
targetname = Jim_GetString(argv[i], &len);
|
if (new)
|
||||||
target = get_target(targetname);
|
|
||||||
LOG_DEBUG("%s ", targetname);
|
|
||||||
if (target) {
|
|
||||||
new = malloc(sizeof(struct target_list));
|
|
||||||
new->target = target;
|
|
||||||
list_add_tail(&new->lh, lh);
|
list_add_tail(&new->lh, lh);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* now parse the list of cpu and put the target in smp mode*/
|
/* now parse the list of cpu and put the target in smp mode*/
|
||||||
foreach_smp_target(head, lh) {
|
struct target_list *curr;
|
||||||
target = head->target;
|
foreach_smp_target(curr, lh) {
|
||||||
|
struct target *target = curr->target;
|
||||||
target->smp = smp_group;
|
target->smp = smp_group;
|
||||||
target->smp_targets = lh;
|
target->smp_targets = lh;
|
||||||
}
|
}
|
||||||
smp_group++;
|
smp_group++;
|
||||||
|
|
||||||
if (target && target->rtos)
|
struct target *rtos_target;
|
||||||
retval = rtos_smp_init(target);
|
int retval = get_target_with_common_rtos_type(lh, &rtos_target);
|
||||||
|
if (retval == JIM_OK && rtos_target)
|
||||||
|
retval = rtos_smp_init(rtos_target);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,10 @@ struct target {
|
||||||
struct list_head *smp_targets; /* list all targets in this smp group/cluster
|
struct list_head *smp_targets; /* list all targets in this smp group/cluster
|
||||||
* The head of the list is shared between the
|
* The head of the list is shared between the
|
||||||
* cluster, thus here there is a pointer */
|
* cluster, thus here there is a pointer */
|
||||||
|
bool smp_halt_event_postponed; /* Some SMP implementations (currently Cortex-M) stores
|
||||||
|
* 'halted' events and emits them after all targets of
|
||||||
|
* the SMP group has been polled */
|
||||||
|
|
||||||
/* the gdb service is there in case of smp, we have only one gdb server
|
/* the gdb service is there in case of smp, we have only one gdb server
|
||||||
* for all smp target
|
* for all smp target
|
||||||
* the target attached to the gdb is changing dynamically by changing
|
* the target attached to the gdb is changing dynamically by changing
|
||||||
|
|
|
@ -168,8 +168,9 @@
|
||||||
#define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num)
|
#define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num)
|
||||||
#define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num)
|
#define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num)
|
||||||
|
|
||||||
#define XT_PS_REG_NUM_BASE (0xc0U) /* (EPS2 - 2), for adding DBGLEVEL */
|
#define XT_PS_REG_NUM (0xe6U)
|
||||||
#define XT_PC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */
|
#define XT_EPS_REG_NUM_BASE (0xc0U) /* (EPS2 - 2), for adding DBGLEVEL */
|
||||||
|
#define XT_EPC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */
|
||||||
#define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */
|
#define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */
|
||||||
#define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */
|
#define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */
|
||||||
|
|
||||||
|
@ -245,7 +246,7 @@ struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS] = {
|
||||||
XT_MK_REG_DESC("ar63", 0x3F, XT_REG_GENERAL, 0),
|
XT_MK_REG_DESC("ar63", 0x3F, XT_REG_GENERAL, 0),
|
||||||
XT_MK_REG_DESC("windowbase", 0x48, XT_REG_SPECIAL, 0),
|
XT_MK_REG_DESC("windowbase", 0x48, XT_REG_SPECIAL, 0),
|
||||||
XT_MK_REG_DESC("windowstart", 0x49, XT_REG_SPECIAL, 0),
|
XT_MK_REG_DESC("windowstart", 0x49, XT_REG_SPECIAL, 0),
|
||||||
XT_MK_REG_DESC("ps", 0xE6, XT_REG_SPECIAL, 0), /* PS (not mapped through EPS[]) */
|
XT_MK_REG_DESC("ps", XT_PS_REG_NUM, XT_REG_SPECIAL, 0), /* PS (not mapped through EPS[]) */
|
||||||
XT_MK_REG_DESC("ibreakenable", 0x60, XT_REG_SPECIAL, 0),
|
XT_MK_REG_DESC("ibreakenable", 0x60, XT_REG_SPECIAL, 0),
|
||||||
XT_MK_REG_DESC("ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD),
|
XT_MK_REG_DESC("ddr", 0x68, XT_REG_DEBUG, XT_REGF_NOREAD),
|
||||||
XT_MK_REG_DESC("ibreaka0", 0x80, XT_REG_SPECIAL, 0),
|
XT_MK_REG_DESC("ibreaka0", 0x80, XT_REG_SPECIAL, 0),
|
||||||
|
@ -630,7 +631,7 @@ static int xtensa_write_dirty_registers(struct target *target)
|
||||||
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL
|
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL
|
||||||
**/
|
**/
|
||||||
reg_num =
|
reg_num =
|
||||||
(XT_PC_REG_NUM_BASE +
|
(XT_EPC_REG_NUM_BASE +
|
||||||
xtensa->core_config->debug.irq_level);
|
xtensa->core_config->debug.irq_level);
|
||||||
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
|
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
|
||||||
}
|
}
|
||||||
|
@ -800,7 +801,6 @@ int xtensa_examine(struct target *target)
|
||||||
return ERROR_TARGET_FAILURE;
|
return ERROR_TARGET_FAILURE;
|
||||||
}
|
}
|
||||||
LOG_DEBUG("OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id);
|
LOG_DEBUG("OCD_ID = %08" PRIx32, xtensa->dbg_mod.device_id);
|
||||||
if (!target_was_examined(target))
|
|
||||||
target_set_examined(target);
|
target_set_examined(target);
|
||||||
xtensa_smpbreak_write(xtensa, xtensa->smp_break);
|
xtensa_smpbreak_write(xtensa, xtensa->smp_break);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1105,10 +1105,10 @@ int xtensa_fetch_all_regs(struct target *target)
|
||||||
case XT_REG_SPECIAL:
|
case XT_REG_SPECIAL:
|
||||||
if (reg_num == XT_PC_REG_NUM_VIRTUAL) {
|
if (reg_num == XT_PC_REG_NUM_VIRTUAL) {
|
||||||
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
|
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
|
||||||
reg_num = (XT_PC_REG_NUM_BASE + xtensa->core_config->debug.irq_level);
|
reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level;
|
||||||
} else if (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num) {
|
} else if (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num) {
|
||||||
/* reg number of PS for debug interrupt depends on NDEBUGLEVEL */
|
/* reg number of PS for debug interrupt depends on NDEBUGLEVEL */
|
||||||
reg_num = (XT_PS_REG_NUM_BASE + xtensa->core_config->debug.irq_level);
|
reg_num = XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level;
|
||||||
} else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) {
|
} else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) {
|
||||||
/* CPENABLE already read/updated; don't re-read */
|
/* CPENABLE already read/updated; don't re-read */
|
||||||
reg_fetched = false;
|
reg_fetched = false;
|
||||||
|
@ -1629,7 +1629,6 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
|
||||||
|
|
||||||
target->debug_reason = DBG_REASON_SINGLESTEP;
|
target->debug_reason = DBG_REASON_SINGLESTEP;
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
|
||||||
LOG_DEBUG("Done stepping, PC=%" PRIX32, cur_pc);
|
LOG_DEBUG("Done stepping, PC=%" PRIX32, cur_pc);
|
||||||
|
|
||||||
if (cause & DEBUGCAUSE_DB) {
|
if (cause & DEBUGCAUSE_DB) {
|
||||||
|
@ -1657,7 +1656,12 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
|
||||||
|
|
||||||
int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
|
int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
|
||||||
{
|
{
|
||||||
return xtensa_do_step(target, current, address, handle_breakpoints);
|
int retval = xtensa_do_step(target, current, address, handle_breakpoints);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1780,9 +1784,9 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si
|
||||||
if (res != ERROR_OK) {
|
if (res != ERROR_OK) {
|
||||||
if (xtensa->probe_lsddr32p != 0) {
|
if (xtensa->probe_lsddr32p != 0) {
|
||||||
/* Disable fast memory access instructions and retry before reporting an error */
|
/* Disable fast memory access instructions and retry before reporting an error */
|
||||||
LOG_TARGET_INFO(target, "Disabling LDDR32.P/SDDR32.P");
|
LOG_TARGET_DEBUG(target, "Disabling LDDR32.P/SDDR32.P");
|
||||||
xtensa->probe_lsddr32p = 0;
|
xtensa->probe_lsddr32p = 0;
|
||||||
res = xtensa_read_memory(target, address, size, count, buffer);
|
res = xtensa_read_memory(target, address, size, count, albuff);
|
||||||
bswap = false;
|
bswap = false;
|
||||||
} else {
|
} else {
|
||||||
LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT,
|
LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT,
|
||||||
|
@ -2502,6 +2506,12 @@ static int xtensa_build_reg_cache(struct target *target)
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
for (j = 0; j < reg_cache->num_regs; j++) {
|
for (j = 0; j < reg_cache->num_regs; j++) {
|
||||||
if (!strcmp(reg_cache->reg_list[j].name, xtensa->contiguous_regs_desc[i]->name)) {
|
if (!strcmp(reg_cache->reg_list[j].name, xtensa->contiguous_regs_desc[i]->name)) {
|
||||||
|
/* Register number field is not filled above.
|
||||||
|
Here we are assigning the corresponding index from the contiguous reg list.
|
||||||
|
These indexes are in the same order with gdb g-packet request/response.
|
||||||
|
Some more changes may be required for sparse reg lists.
|
||||||
|
*/
|
||||||
|
reg_cache->reg_list[j].number = i;
|
||||||
xtensa->contiguous_regs_list[i] = &(reg_cache->reg_list[j]);
|
xtensa->contiguous_regs_list[i] = &(reg_cache->reg_list[j]);
|
||||||
LOG_TARGET_DEBUG(target,
|
LOG_TARGET_DEBUG(target,
|
||||||
"POPULATE contiguous regs list: %-16s, dbreg_num 0x%04x",
|
"POPULATE contiguous regs list: %-16s, dbreg_num 0x%04x",
|
||||||
|
@ -3441,8 +3451,8 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa)
|
||||||
else
|
else
|
||||||
rptr->flags = 0;
|
rptr->flags = 0;
|
||||||
|
|
||||||
if ((rptr->reg_num == (XT_PS_REG_NUM_BASE + xtensa->core_config->debug.irq_level)) &&
|
if (rptr->reg_num == (XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level) &&
|
||||||
(xtensa->core_config->core_type == XT_LX) && (rptr->type == XT_REG_SPECIAL)) {
|
xtensa->core_config->core_type == XT_LX && rptr->type == XT_REG_SPECIAL) {
|
||||||
xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1;
|
xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1;
|
||||||
LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx);
|
LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
set _CPUTAPID 0x1000063d
|
|
||||||
set _CHIPNAME nds32
|
|
||||||
source [find target/nds32v3.cfg]
|
|
||||||
|
|
||||||
jtag init
|
|
|
@ -9,7 +9,7 @@ if { [info exists CHIPNAME] } {
|
||||||
set _CHIPNAME xcu
|
set _CHIPNAME xcu
|
||||||
}
|
}
|
||||||
|
|
||||||
# The cvarious chips in the Ultrascale family have different IR length.
|
# The various chips in the Ultrascale family have different IR length.
|
||||||
# Set $CHIP before including this file to determine the device.
|
# Set $CHIP before including this file to determine the device.
|
||||||
array set _XCU_DATA {
|
array set _XCU_DATA {
|
||||||
XCKU025 {0x03824093 6}
|
XCKU025 {0x03824093 6}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#
|
|
||||||
# Andes AICE
|
|
||||||
#
|
|
||||||
# http://www.andestech.com
|
|
||||||
#
|
|
||||||
|
|
||||||
adapter driver aice
|
|
||||||
aice desc "Andes AICE adapter"
|
|
||||||
# adapter serial "C001-42163"
|
|
||||||
aice vid_pid 0x1CFC 0x0000
|
|
||||||
aice port aice_usb
|
|
||||||
reset_config trst_and_srst
|
|
||||||
adapter speed 24000
|
|
||||||
aice retry_times 50
|
|
||||||
aice count_to_check_dbger 30
|
|
|
@ -15,9 +15,9 @@ adapter driver bcm2835gpio
|
||||||
bcm2835gpio peripheral_base 0x3F000000
|
bcm2835gpio peripheral_base 0x3F000000
|
||||||
|
|
||||||
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
|
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
|
||||||
# These depend on system clock, calibrated for stock 700MHz
|
# These depend on system clock, calibrated for scaling_max_freq 900MHz
|
||||||
# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET
|
# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET
|
||||||
bcm2835gpio speed_coeffs 146203 36
|
bcm2835gpio speed_coeffs 225000 36
|
||||||
|
|
||||||
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
|
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
|
||||||
# Header pin numbers: 23 22 19 21
|
# Header pin numbers: 23 22 19 21
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# ATmega32U4
|
||||||
|
|
||||||
|
if { [info exists CHIPNAME] } {
|
||||||
|
set _CHIPNAME $CHIPNAME
|
||||||
|
} else {
|
||||||
|
set _CHIPNAME avr
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists ENDIAN] } {
|
||||||
|
set _ENDIAN $ENDIAN
|
||||||
|
} else {
|
||||||
|
set _ENDIAN little
|
||||||
|
}
|
||||||
|
|
||||||
|
if { [info exists CPUTAPID] } {
|
||||||
|
set _CPUTAPID $CPUTAPID
|
||||||
|
} else {
|
||||||
|
set _CPUTAPID 0x4958703f
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter speed 4500
|
||||||
|
|
||||||
|
jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
|
||||||
|
|
||||||
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
|
target create $_TARGETNAME avr -endian $_ENDIAN -chain-position $_TARGETNAME
|
||||||
|
|
||||||
|
set _FLASHNAME $_CHIPNAME.flash
|
||||||
|
flash bank $_FLASHNAME avr 0 0 0 0 $_TARGETNAME
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue