Merge commit 'd1b882f2c014258be5397067e45848fa5465b78b' into from_upstream

Conflicts:
	doc/openocd.texi
	src/target/riscv/riscv-013.c
	src/target/riscv/riscv.c

Change-Id: I8cd557a10c3d5beeaed05ecc05d4c325a9ee7e70
This commit is contained in:
Tim Newsome 2023-02-28 10:53:40 -08:00
commit 4f97898889
62 changed files with 7143 additions and 445 deletions

View File

@ -22,7 +22,7 @@ jobs:
- run: ./bootstrap
- name: Prepare libusb1
env:
LIBUSB1_VER: 1.0.24
LIBUSB1_VER: 1.0.26
run: |
mkdir -p $DL_DIR && cd $DL_DIR
wget "https://github.com/libusb/libusb/releases/download/v${LIBUSB1_VER}/libusb-${LIBUSB1_VER}.tar.bz2"
@ -30,7 +30,7 @@ jobs:
echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV
- name: Prepare hidapi
env:
HIDAPI_VER: 0.10.1
HIDAPI_VER: 0.11.2
run: |
mkdir -p $DL_DIR && cd $DL_DIR
wget "https://github.com/libusb/hidapi/archive/hidapi-${HIDAPI_VER}.tar.gz"

1
.gitignore vendored
View File

@ -68,6 +68,7 @@ doxygen
doxygen.log
Doxyfile
libtool
*-libtool
Makefile
!contrib/loaders/**/Makefile
stamp-h1

36
HACKING
View File

@ -197,11 +197,11 @@ while(!done) {
@endcode
\note use "git add ." before commit to add new files.
Comment template, notice the short first line w/topic. The topic field
should identify the main part or subsystem the patch touches. Check
git log for examples.
@code
topic: Short comment
Commit message template, notice the short first line.
The field '<c>specify touched area</c>'
should identify the main part or subsystem the patch touches.
@code{.unparsed}
specify touched area: short comment
<blank line>
Longer comments over several lines, explaining (where applicable) the
reason for the patch and the general idea the solution is based on,
@ -209,6 +209,32 @@ any major design decisions, etc...
<blank line>
Signed-off-by: ...
@endcode
Examples:
@code{.unparsed}
flash/nor/atsame5: add SAME59 support
Add new device ID
@endcode
@code{.unparsed}
flash/nor: flash driver for XYZ123
Add new flash driver for internal flash of ...
@endcode
@code{.unparsed}
target/cortex_m: fix segmentation fault in cmd 'soft_reset_halt'
soft_reset_halt command failed reproducibly under following conditions: ...
Test for NULL pointer and return error ...
Reported-by: John Reporter <rep9876@gmail.com>
Fixes: 123456789abc ("target: the commit where the problem started")
BugLink: https://sourceforge.net/p/openocd/tickets/999/
@endcode
@code{.unparsed}
doc: fix typos
@endcode
See "git log" for more examples.
-# Next you need to make sure that your patches
are on top of the latest stuff on the server and
that there are no conflicts:

View File

@ -299,10 +299,14 @@ AS_CASE(["${host_cpu}"],
AC_ARG_ENABLE([imx_gpio],
AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]),
[build_imx_gpio=$enableval], [build_imx_gpio=no])
AC_ARG_ENABLE([am335xgpio],
AS_HELP_STRING([--enable-am335xgpio], [Enable building support for bitbanging on AM335x (as found in Beaglebones)]),
[build_am335xgpio=$enableval], [build_am335xgpio=no])
],
[
build_bcm2835gpio=no
build_imx_gpio=no
build_am335xgpio=no
])
AS_CASE(["${host_cpu}"],
@ -508,6 +512,13 @@ AS_IF([test "x$build_imx_gpio" = "xyes"], [
AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.])
])
AS_IF([test "x$build_am335xgpio" = "xyes"], [
build_bitbang=yes
AC_DEFINE([BUILD_AM335XGPIO], [1], [1 if you want am335xgpio.])
], [
AC_DEFINE([BUILD_AM335XGPIO], [0], [0 if you don't want am335xgpio.])
])
AS_IF([test "x$parport_use_ppdev" = "xyes"], [
AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.])
], [
@ -560,9 +571,9 @@ AS_IF([test "x$enable_buspirate" != "xno"], [
AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [
AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [
jimtcl_config_options="--disable-install-jim --maintainer"
jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer"
], [
jimtcl_config_options="--disable-install-jim"
jimtcl_config_options="--disable-install-jim --with-ext=json"
])
AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options])
], [
@ -712,6 +723,7 @@ AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"])
AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"])
AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"])
AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"])
AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"])
AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"])
AM_CONDITIONAL([JTAG_VPI], [test "x$build_jtag_vpi" = "xyes"])
AM_CONDITIONAL([VDEBUG], [test "x$build_vdebug" = "xyes"])

View File

@ -154,7 +154,7 @@ if [ -d $CAPSTONE_SRC ] ; then
sed -i '1s;^;prefix=/usr \
exec_prefix=${prefix} \
libdir=${exec_prefix}/lib \
includedir=${prefix}/include\n\n;' $CAPSTONE_PC_FILE
includedir=${prefix}/include/capstone\n\n;' $CAPSTONE_PC_FILE
fi

View File

@ -584,6 +584,9 @@ produced, PDF schematics are easily found and it is easy to make.
@item @b{imx_gpio}
@* A NXP i.MX-based board (e.g. Wandboard) using the GPIO pins (should work on any i.MX processor).
@item @b{am335xgpio}
@* A Texas Instruments AM335x-based board (e.g. BeagleBone Black) using the GPIO pins of the expansion headers.
@item @b{jtag_vpi}
@* A JTAG driver acting as a client for the JTAG VPI server interface.
@* Link: @url{http://github.com/fjullien/jtag_vpi}
@ -2120,6 +2123,15 @@ corresponding subsystems:
@deffnx {Config Command} {pld init}
@deffnx {Command} {tpiu init}
@end deffn
At last, @command{init} executes all the commands that are specified in
the TCL list @var{post_init_commands}. The commands are executed in the
same order they occupy in the list. If one of the commands fails, then
the error is propagated and OpenOCD fails too.
@example
lappend post_init_commands @{echo "OpenOCD successfully initialized."@}
lappend post_init_commands @{echo "Have fun with OpenOCD !"@}
@end example
@end deffn
@deffn {Config Command} {noinit}
@ -3342,11 +3354,180 @@ pinout.
@end deffn
@deffn {Interface Driver} {am335xgpio} The AM335x SoC is present in BeagleBone
Black and BeagleBone Green single-board computers which expose some of the GPIOs
on the two expansion headers.
For maximum performance the driver accesses memory-mapped GPIO peripheral
registers directly. The memory mapping requires read and write permission to
kernel memory; if /dev/gpiomem exists it will be used, otherwise /dev/mem will
be used. The driver restores the GPIO state on exit.
All four GPIO ports are available. GPIOs numbered 0 to 31 are mapped to GPIO port
0, GPIO numbers 32 to 63 are mapped to GPIO port 1 and so on.
See @file{interface/beaglebone-swd-native.cfg} for a sample configuration file.
@deffn {Config Command} {am335xgpio jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo}
Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order).
Must be specified to enable JTAG transport. These pins can also be specified
individually.
@end deffn
@deffn {Config Command} {am335xgpio tck_num} @var{tck}
Set TCK GPIO number. Must be specified to enable JTAG transport. Can also be
specified using the configuration command @command{am335xgpio jtag_nums}.
@end deffn
@deffn {Config Command} {am335xgpio tms_num} @var{tms}
Set TMS GPIO number. Must be specified to enable JTAG transport. Can also be
specified using the configuration command @command{am335xgpio jtag_nums}.
@end deffn
@deffn {Config Command} {am335xgpio tdo_num} @var{tdo}
Set TDO GPIO number. Must be specified to enable JTAG transport. Can also be
specified using the configuration command @command{am335xgpio jtag_nums}.
@end deffn
@deffn {Config Command} {am335xgpio tdi_num} @var{tdi}
Set TDI GPIO number. Must be specified to enable JTAG transport. Can also be
specified using the configuration command @command{am335xgpio jtag_nums}.
@end deffn
@deffn {Config Command} {am335xgpio swd_nums} @var{swclk} @var{swdio}
Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be
specified to enable SWD transport. These pins can also be specified individually.
@end deffn
@deffn {Config Command} {am335xgpio swclk_num} @var{swclk}
Set SWCLK GPIO number. Must be specified to enable SWD transport. Can also be
specified using the configuration command @command{am335xgpio swd_nums}.
@end deffn
@deffn {Config Command} {am335xgpio swdio_num} @var{swdio}
Set SWDIO GPIO number. Must be specified to enable SWD transport. Can also be
specified using the configuration command @command{am335xgpio swd_nums}.
@end deffn
@deffn {Config Command} {am335xgpio swdio_dir_num} @var{swdio_dir}
Set SWDIO direction control pin GPIO number. If specified, this pin can be used
to control the direction of an external buffer on the SWDIO pin. The direction
control state can be set with the command @command{am335xgpio
swdio_dir_output_state}. If not specified this feature is disabled.
@end deffn
@deffn {Config Command} {am335xgpio swdio_dir_output_state} @var{output_state}
Set the state required for an external SWDIO buffer to be an output. Valid
values are @option{on} (default) and @option{off}.
@end deffn
@deffn {Config Command} {am335xgpio srst_num} @var{srst}
Set SRST GPIO number. Must be specified to enable SRST.
@end deffn
@deffn {Config Command} {am335xgpio trst_num} @var{trst}
Set TRST GPIO number. Must be specified to enable TRST.
@end deffn
@deffn {Config Command} {am335xgpio led_num} @var{led}
Set activity LED GPIO number. If not specified an activity LED is not enabled.
@end deffn
@deffn {Config Command} {am335xgpio led_on_state} @var{on_state}
Set required logic level for the LED to be on. Valid values are @option{on}
(default) and @option{off}.
@end deffn
@deffn {Config Command} {am335xgpio speed_coeffs} @var{speed_coeff} @var{speed_offset}
Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified
speed_coeff defaults to 600000 and speed_offset defaults to 575.
@end deffn
@end deffn
@deffn {Interface Driver} {linuxgpiod}
Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6.
The driver emulates either JTAG and SWD transport through bitbanging.
The driver emulates either JTAG or SWD transport through bitbanging.
See @file{interface/dln-2-gpiod.cfg} for a sample config.
@deffn {Config Command} {linuxgpiod gpiochip} @var{chip}
Set the GPIO chip number for all GPIOs used by linuxgpiod. If GPIOs use
different GPIO chips then the individual GPIO configuration commands (i.e., not
@command{linuxgpiod jtag_nums} or @command{linuxgpiod swd_nums}) can be used to
set chip numbers independently for each GPIO.
@end deffn
@deffn {Config Command} {linuxgpiod jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo}
Set JTAG transport GPIO numbers for TCK, TMS, TDI, and TDO (in that order). Must
be specified to enable JTAG transport. These pins can also be specified
individually.
@end deffn
@deffn {Config Command} {linuxgpiod tck_num} [@var{chip}] @var{tck}
Set TCK GPIO number, and optionally TCK chip number. Must be specified to enable
JTAG transport. Can also be specified using the configuration command
@command{linuxgpiod jtag_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod tms_num} [@var{chip}] @var{tms}
Set TMS GPIO number, and optionally TMS chip number. Must be specified to enable
JTAG transport. Can also be specified using the configuration command
@command{linuxgpiod jtag_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod tdo_num} [@var{chip}] @var{tdo}
Set TDO GPIO number, and optionally TDO chip number. Must be specified to enable
JTAG transport. Can also be specified using the configuration command
@command{linuxgpiod jtag_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod tdi_num} [@var{chip}] @var{tdi}
Set TDI GPIO number, and optionally TDI chip number. Must be specified to enable
JTAG transport. Can also be specified using the configuration command
@command{linuxgpiod jtag_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod trst_num} [@var{chip}] @var{trst}
Set TRST GPIO number, and optionally TRST chip number. Must be specified to
enable TRST.
@end deffn
@deffn {Config Command} {linuxgpiod swd_nums} @var{swclk} @var{swdio}
Set SWD transport GPIO numbers for SWCLK and SWDIO (in that order). Must be
specified to enable SWD transport. These pins can also be specified
individually.
@end deffn
@deffn {Config Command} {linuxgpiod swclk_num} [@var{chip}] @var{swclk}
Set SWCLK GPIO number, and optionally SWCLK chip number. Must be specified to
enable SWD transport. Can also be specified using the configuration command
@command{linuxgpiod swd_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod swdio_num} [@var{chip}] @var{swdio}
Set SWDIO GPIO number, and optionally SWDIO chip number. Must be specified to
enable SWD transport. Can also be specified using the configuration command
@command{linuxgpiod swd_nums}.
@end deffn
@deffn {Config Command} {linuxgpiod swdio_dir_num} [@var{chip}] @var{swdio_dir}
Set SWDIO direction control GPIO number, and optionally SWDIO direction control
chip number. If specified, this GPIO can be used to control the direction of an
external buffer connected to the SWDIO GPIO (set=output mode, clear=input mode).
@end deffn
@deffn {Config Command} {linuxgpiod srst_num} [@var{chip}] @var{srst}
Set SRST GPIO number, and optionally SRST chip number. Must be specified to
enable SRST.
@end deffn
@deffn {Config Command} {linuxgpiod led_num} [@var{chip}] @var{led}
Set activity LED GPIO number, and optionally activity LED chip number. If not
specified an activity LED is not enabled.
@end deffn
@end deffn
@ -4745,6 +4926,7 @@ compact Thumb2 instruction set. Supports also ARMv6-M and ARMv8-M cores
The current implementation supports eSi-32xx cores.
@item @code{esp32c2} -- this is an Espressif SoC with single RISC-V core.
@item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core.
@item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core.
@item @code{fa526} -- resembles arm920 (w/o Thumb).
@item @code{feroceon} -- resembles arm926.
@item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link.
@ -6449,7 +6631,7 @@ The AVR 8-bit microcontrollers from Atmel integrate flash memory.
@end deffn
@deffn {Flash Driver} {bluenrg-x}
STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory.
STMicroelectronics BlueNRG-1, BlueNRG-2 and BlueNRG-LP/LPS Bluetooth low energy wireless system-on-chip. They include ARM Cortex-M0/M0+ core and internal flash memory.
The driver automatically recognizes these chips using
the chip identification registers, and autoconfigures itself.
@ -8464,18 +8646,19 @@ Close the OpenOCD server, disconnecting all clients (GDB, telnet,
other). If option @option{error} is used, OpenOCD will return a
non-zero exit code to the parent process.
Like any TCL commands, also @command{shutdown} can be redefined, e.g.:
If user types CTRL-C or kills OpenOCD, the command @command{shutdown}
will be automatically executed to cause OpenOCD to exit.
It is possible to specify, in the TCL list @var{pre_shutdown_commands} , a
set of commands to be automatically executed before @command{shutdown} , e.g.:
@example
# redefine shutdown
rename shutdown original_shutdown
proc shutdown @{@} @{
puts "This is my implementation of shutdown"
# my own stuff before exit OpenOCD
original_shutdown
@}
lappend pre_shutdown_commands @{echo "Goodbye, my friend ..."@}
lappend pre_shutdown_commands @{echo "see you soon !"@}
@end example
If user types CTRL-C or kills OpenOCD, either the command @command{shutdown}
or its replacement will be automatically executed before OpenOCD exits.
The commands in the list will be executed (in the same order they occupy
in the list) before OpenOCD exits. If one of the commands in the list
fails, then the remaining commands are not executed anymore while OpenOCD
will proceed to quit.
@end deffn
@anchor{debuglevel}
@ -9473,6 +9656,12 @@ is valid during the run of the event handlers and is accessible with this
command.
@end deffn
@deffn {Command} {arm semihosting_basedir} [dir]
@cindex ARM semihosting
Set the base directory for semihosting I/O, either an absolute path or a path relative to OpenOCD working directory.
Use "." for the current directory.
@end deffn
@section ARMv4 and ARMv5 Architecture
@cindex ARMv4
@cindex ARMv5
@ -10956,6 +11145,94 @@ STMicroelectronics, based on a proprietary 8-bit core architecture.
OpenOCD supports debugging STM8 through the STMicroelectronics debug
protocol SWIM, @pxref{swimtransport,,SWIM}.
@section Xtensa Architecture
Xtensa processors are based on a modular, highly flexible 32-bit RISC architecture
that can easily scale from a tiny, cache-less controller or task engine to a high-performance
SIMD/VLIW DSP provided by Cadence.
@url{https://www.cadence.com/en_US/home/tools/ip/tensilica-ip/tensilica-xtensa-controllers-and-extensible-processors.html}.
OpenOCD supports generic Xtensa processors implementation which can be customized by
simply providing vendor-specific core configuration which controls every configurable
Xtensa architecture option, e.g. number of address registers, exceptions, reduced
size instructions support, memory banks configuration etc. Also OpenOCD supports SMP
configurations for Xtensa processors with any number of cores and allows to configure
their debug signals interconnection (so-called "break/stall networks") which control how
debug signals are distributed among cores. Xtensa "break networks" are compatible with
ARM's Cross Trigger Interface (CTI). For debugging code on Xtensa chips OpenOCD
uses JTAG protocol. Currently OpenOCD implements several Epsressif Xtensa-based chips of
@uref{https://www.espressif.com/en/products/socs, ESP32 family}.
@subsection General Xtensa Commands
@deffn {Command} {xtensa set_permissive} (0|1)
By default accessing memory beyond defined regions is forbidden. This commnd controls memory access address check.
When set to (1), skips access controls and address range check before read/write memory.
@end deffn
@deffn {Command} {xtensa maskisr} (on|off)
Selects whether interrupts will be disabled during stepping over single instruction. The default configuration is (off).
@end deffn
@deffn {Command} {xtensa smpbreak} [none|breakinout|runstall] | [BreakIn] [BreakOut] [RunStallIn] [DebugModeOut]
Configures debug signals connection ("break network") for currently selected core.
@itemize @bullet
@item @code{none} - Core's "break/stall network" is disconnected. Core is not affected by any debug
signal from other cores.
@item @code{breakinout} - Core's "break network" is fully connected (break inputs and outputs are enabled).
Core will receive debug break signals from other cores and send such signals to them. For example when another core
is stopped due to breakpoint hit this core will be stopped too and vice versa.
@item @code{runstall} - Core's "stall network" is fully connected (stall inputs and outputs are enabled).
This feature is not well implemented and tested yet.
@item @code{BreakIn} - Core's "break-in" signal is enabled.
Core will receive debug break signals from other cores. For example when another core is
stopped due to breakpoint hit this core will be stopped too.
@item @code{BreakOut} - Core's "break-out" signal is enabled.
Core will send debug break signal to other cores. For example when this core is
stopped due to breakpoint hit other cores with enabled break-in signals will be stopped too.
@item @code{RunStallIn} - Core's "runstall-in" signal is enabled.
This feature is not well implemented and tested yet.
@item @code{DebugModeOut} - Core's "debugmode-out" signal is enabled.
This feature is not well implemented and tested yet.
@end itemize
@end deffn
@deffn {Command} {xtensa perfmon_enable} <counter_id> <select> [mask] [kernelcnt] [tracelevel]
Enable and start performance counter.
@itemize @bullet
@item @code{counter_id} - Counter ID (0-1).
@item @code{select} - Selects performance metric to be counted by the counter,
e.g. 0 - CPU cycles, 2 - retired instructions.
@item @code{mask} - Selects input subsets to be counted (counter will
increment only once even if more than one condition corresponding to a mask bit occurs).
@item @code{kernelcnt} - 0 - count events with "CINTLEVEL <= tracelevel",
1 - count events with "CINTLEVEL > tracelevel".
@item @code{tracelevel} - Compares this value to "CINTLEVEL" when deciding
whether to count.
@end itemize
@end deffn
@deffn {Command} {xtensa perfmon_dump} (counter_id)
Dump performance counter value. If no argument specified, dumps all counters.
@end deffn
@deffn {Command} {xtensa tracestart} [pc <pcval>/[<maskbitcount>]] [after <n> [ins|words]]
Set up and start a HW trace. Optionally set PC address range to trigger tracing stop when reached during program execution.
This command also allows to specify the amount of data to capture after stop trigger activation.
@itemize @bullet
@item @code{pcval} - PC value which will trigger trace data collection stop.
@item @code{maskbitcount} - PC value mask.
@item @code{n} - Maximum number of instructions/words to capture after trace stop trigger.
@end itemize
@end deffn
@deffn {Command} {xtensa tracestop}
Stop current trace as started by the tracestart command.
@end deffn
@deffn {Command} {xtensa tracedump} <outfile>
Dump trace memory to a file.
@end deffn
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support
@ -11756,57 +12033,6 @@ The @command{step} and @command{stepi} commands can be used to step a specific c
while other cores are free-running or remain halted, depending on the
scheduler-locking mode configured in GDB.
@section Legacy SMP core switching support
@quotation Note
This method is deprecated in favor of the @emph{hwthread} pseudo RTOS.
@end quotation
For SMP support following GDB serial protocol packet have been defined :
@itemize @bullet
@item j - smp status request
@item J - smp set request
@end itemize
OpenOCD implements :
@itemize @bullet
@item @option{jc} packet for reading core id displayed by
GDB connection. Reply is @option{XXXXXXXX} (8 hex digits giving core id) or
@option{E01} for target not smp.
@item @option{JcXXXXXXXX} (8 hex digits) packet for setting core id displayed at next GDB continue
(core id -1 is reserved for returning to normal resume mode). Reply @option{E01}
for target not smp or @option{OK} on success.
@end itemize
Handling of this packet within GDB can be done :
@itemize @bullet
@item by the creation of an internal variable (i.e @option{_core}) by mean
of function allocate_computed_value allowing following GDB command.
@example
set $_core 1
#Jc01 packet is sent
print $_core
#jc packet is sent and result is affected in $
@end example
@item by the usage of GDB maintenance command as described in following example (2 cpus in SMP with
core id 0 and 1 @pxref{definecputargetsworkinginsmp,,Define CPU targets working in SMP}).
@example
# toggle0 : force display of coreid 0
define toggle0
maint packet Jc0
continue
main packet Jc-1
end
# toggle1 : force display of coreid 1
define toggle1
maint packet Jc1
continue
main packet Jc-1
end
@end example
@end itemize
@node Tcl Scripting API
@chapter Tcl Scripting API
@cindex Tcl Scripting API
@ -12374,7 +12600,7 @@ It sort of works like this:
When the command ``proc'' is parsed (which creates a procedure
function) it gets 3 parameters on the command line. @b{1} the name of
the proc (function), @b{2} the list of parameters, and @b{3} the body
of the function. Not the choice of words: LIST and BODY. The PROC
of the function. Note the choice of words: LIST and BODY. The PROC
command stores these items in a table somewhere so it can be found by
``LookupCommand()''

View File

@ -35,6 +35,8 @@
#define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg)
#define FLASH_PAGE_SIZE(bluenrgx_info) (bluenrgx_info->flash_ptr->flash_page_size)
#define FLASH_SIZE_REG_MASK (0xFFFF)
struct flash_ctrl_priv_data {
uint32_t die_id_reg;
uint32_t jtag_idcode_reg;
@ -75,6 +77,16 @@ static const struct flash_ctrl_priv_data flash_priv_data_lp = {
.part_name = "BLUENRG-LP",
};
static const struct flash_ctrl_priv_data flash_priv_data_lps = {
.die_id_reg = 0x40000000,
.jtag_idcode_reg = 0x40000004,
.flash_base = 0x10040000,
.flash_regs_base = 0x40001000,
.flash_page_size = 2048,
.jtag_idcode = 0x02028041,
.part_name = "BLUENRG-LPS",
};
struct bluenrgx_flash_bank {
bool probed;
uint32_t die_id;
@ -84,8 +96,8 @@ struct bluenrgx_flash_bank {
static const struct flash_ctrl_priv_data *flash_ctrl[] = {
&flash_priv_data_1,
&flash_priv_data_2,
&flash_priv_data_lp
};
&flash_priv_data_lp,
&flash_priv_data_lps};
/* flash_bank bluenrg-x 0 0 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
@ -377,7 +389,7 @@ static int bluenrgx_probe(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
if (idcode != flash_priv_data_lp.jtag_idcode) {
if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) {
retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
if (retval != ERROR_OK)
return retval;
@ -395,6 +407,7 @@ static int bluenrgx_probe(struct flash_bank *bank)
}
}
retval = bluenrgx_read_flash_reg(bank, FLASH_SIZE_REG, &size_info);
size_info = size_info & FLASH_SIZE_REG_MASK;
if (retval != ERROR_OK)
return retval;

View File

@ -429,7 +429,11 @@ int default_flash_blank_check(struct flash_bank *bank)
bank->sectors[i].is_erased = block_array[i].result;
retval = ERROR_OK;
} else {
LOG_USER("Running slow fallback erase check - add working memory");
if (retval == ERROR_NOT_IMPLEMENTED)
LOG_USER("Running slow fallback erase check");
else
LOG_USER("Running slow fallback erase check - add working memory");
retval = default_flash_mem_blank_check(bank);
}
free(block_array);

View File

@ -1385,13 +1385,6 @@ static int numicro_writeblock(struct flash_bank *bank, const uint8_t *buffer,
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* faddr */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* number of words to program */
struct armv7m_common *armv7m = target_to_armv7m(target);
if (!armv7m) {
/* something is very wrong if armv7m is NULL */
LOG_ERROR("unable to get armv7m target");
return retval;
}
/* write code buffer and use Flash programming code within NuMicro */
/* Set breakpoint to 0 with time-out of 1000 ms */
while (count > 0) {

View File

@ -1078,7 +1078,7 @@ static int stm32l4_get_all_wrpxy(struct flash_bank *bank, enum stm32_bank_id dev
if (dev_bank_id != STM32_BANK1 && stm32l4_info->dual_bank_mode)
wrp2y_sectors_offset = stm32l4_info->bank1_sectors;
if (wrp2y_sectors_offset > -1) {
if (wrp2y_sectors_offset >= 0) {
/* get WRP2AR */
ret = stm32l4_get_one_wrpxy(bank, &wrpxy[(*n_wrp)++], STM32_FLASH_WRP2AR_INDEX, wrp2y_sectors_offset);
if (ret != ERROR_OK)
@ -1220,49 +1220,11 @@ err_lock:
return retval2;
}
static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set,
unsigned int first, unsigned int last)
{
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
int ret = ERROR_OK;
unsigned int i;
if (stm32l4_is_otp(bank)) {
LOG_ERROR("cannot protect/unprotect OTP memory");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* the requested sectors could be located into bank1 and/or bank2 */
bool use_bank2 = false;
if (last >= stm32l4_info->bank1_sectors) {
if (first < stm32l4_info->bank1_sectors) {
/* the requested sectors for (un)protection are shared between
* bank 1 and 2, then split the operation */
/* 1- deal with bank 1 sectors */
LOG_DEBUG("The requested sectors for %s are shared between bank 1 and 2",
set ? "protection" : "unprotection");
ret = stm32l4_protect(bank, set, first, stm32l4_info->bank1_sectors - 1);
if (ret != ERROR_OK)
return ret;
/* 2- then continue with bank 2 sectors */
first = stm32l4_info->bank1_sectors;
}
use_bank2 = true;
}
/* refresh the sectors' protection */
ret = stm32l4_protect_check(bank);
if (ret != ERROR_OK)
return ret;
/* check if the desired protection is already configured */
for (i = first; i <= last; i++) {
if (bank->sectors[i].is_protected != set)
@ -1278,7 +1240,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int n_wrp;
struct stm32l4_wrp wrpxy[4];
ret = stm32l4_get_all_wrpxy(bank, use_bank2 ? STM32_BANK2 : STM32_BANK1, wrpxy, &n_wrp);
int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp);
if (ret != ERROR_OK)
return ret;
@ -1349,6 +1311,40 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first,
return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
}
static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last)
{
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
if (stm32l4_is_otp(bank)) {
LOG_ERROR("cannot protect/unprotect OTP memory");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* refresh the sectors' protection */
int ret = stm32l4_protect_check(bank);
if (ret != ERROR_OK)
return ret;
/* the requested sectors could be located into bank1 and/or bank2 */
if (last < stm32l4_info->bank1_sectors) {
return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last);
} else if (first >= stm32l4_info->bank1_sectors) {
return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last);
} else {
ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1);
if (ret != ERROR_OK)
return ret;
return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last);
}
}
/* count is the size divided by stm32l4_info->data_width */
static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
@ -1987,6 +1983,15 @@ static int stm32l4_probe(struct flash_bank *bank)
return ERROR_FAIL;
}
/* ensure that at least there is 1 flash sector / page */
if (num_pages == 0) {
if (stm32l4_info->user_bank_size)
LOG_ERROR("The specified flash size is less than page size");
LOG_ERROR("Flash pages count cannot be zero");
return ERROR_FAIL;
}
LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;

View File

@ -28,4 +28,26 @@ proc script {filename} {
add_help_text script "filename of OpenOCD script (tcl) to run"
add_usage_text script "<file>"
# Run a list of post-init commands
# Each command should be added with 'lappend post_init_commands command'
lappend _telnet_autocomplete_skip _run_post_init_commands
proc _run_post_init_commands {} {
if {[info exists ::post_init_commands]} {
foreach cmd $::post_init_commands {
eval $cmd
}
}
}
# Run a list of pre-shutdown commands
# Each command should be added with 'lappend pre_shutdown_commands command'
lappend _telnet_autocomplete_skip _run_pre_shutdown_commands
proc _run_pre_shutdown_commands {} {
if {[info exists ::pre_shutdown_commands]} {
foreach cmd $::pre_shutdown_commands {
eval $cmd
}
}
}
#########

View File

@ -185,6 +185,9 @@ endif
if XDS110
DRIVERFILES += %D%/xds110.c
endif
if AM335XGPIO
DRIVERFILES += %D%/am335xgpio.c
endif
DRIVERHEADERS = \
%D%/bitbang.h \

View File

@ -0,0 +1,733 @@
/***************************************************************************
* Copyright (C) 2022 by Steve Marple, stevemarple@googlemail.com *
* *
* Based on bcm2835gpio.c and linuxgpiod.c *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <jtag/interface.h>
#include <transport/transport.h>
#include "bitbang.h"
#include <sys/mman.h>
/*
* GPIO register base addresses. Values taken from "AM335x and AMIC110 Sitara
* Processors Technical Reference Manual", Chapter 2 Memory Map.
*/
#define AM335XGPIO_NUM_GPIO_PORTS 4
#define AM335XGPIO_GPIO0_HW_ADDR 0x44E07000
#define AM335XGPIO_GPIO1_HW_ADDR 0x4804C000
#define AM335XGPIO_GPIO2_HW_ADDR 0x481AC000
#define AM335XGPIO_GPIO3_HW_ADDR 0x481AE000
/* 32-bit offsets from GPIO port base address. Values taken from "AM335x and
* AMIC110 Sitara Processors Technical Reference Manual", Chapter 25
* General-Purpose Input/Output.
*/
#define AM335XGPIO_GPIO_OE_OFFSET (0x134 / 4)
#define AM335XGPIO_GPIO_DATAIN_OFFSET (0x138 / 4)
#define AM335XGPIO_GPIO_DATAOUT_OFFSET (0x13C / 4) /* DATAOUT register uses 0 for output, 1 for input */
#define AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET (0x190 / 4)
#define AM335XGPIO_GPIO_SETDATAOUT_OFFSET (0x194 / 4)
/* GPIOs are integer values; need to map to a port module, and the pin within
* that module. GPIOs 0 to 31 map to GPIO0, 32 to 63 to GPIO1 etc. This scheme
* matches that used by Linux on the BeagleBone.
*/
#define AM335XGPIO_PORT_NUM(gpio_num) ((gpio_num) / 32)
#define AM335XGPIO_BIT_NUM(gpio_num) ((gpio_num) % 32)
#define AM335XGPIO_BIT_MASK(gpio_num) BIT(AM335XGPIO_BIT_NUM(gpio_num))
#define AM335XGPIO_READ_REG(gpio_num, offset) \
(*(am335xgpio_gpio_port_mmap_addr[AM335XGPIO_PORT_NUM(gpio_num)] + (offset)))
#define AM335XGPIO_WRITE_REG(gpio_num, offset, value) \
(*(am335xgpio_gpio_port_mmap_addr[AM335XGPIO_PORT_NUM(gpio_num)] + (offset)) = (value))
#define AM335XGPIO_SET_REG_BITS(gpio_num, offset, bit_mask) \
(*(am335xgpio_gpio_port_mmap_addr[AM335XGPIO_PORT_NUM(gpio_num)] + (offset)) |= (bit_mask))
#define AM335XGPIO_CLEAR_REG_BITS(gpio_num, offset, bit_mask) \
(*(am335xgpio_gpio_port_mmap_addr[AM335XGPIO_PORT_NUM(gpio_num)] + (offset)) &= ~(bit_mask))
enum amx335gpio_gpio_mode {
AM335XGPIO_GPIO_MODE_INPUT,
AM335XGPIO_GPIO_MODE_OUTPUT, /* To set output mode but not state */
AM335XGPIO_GPIO_MODE_OUTPUT_LOW,
AM335XGPIO_GPIO_MODE_OUTPUT_HIGH,
};
static const uint32_t am335xgpio_gpio_port_hw_addr[AM335XGPIO_NUM_GPIO_PORTS] = {
AM335XGPIO_GPIO0_HW_ADDR,
AM335XGPIO_GPIO1_HW_ADDR,
AM335XGPIO_GPIO2_HW_ADDR,
AM335XGPIO_GPIO3_HW_ADDR,
};
/* Memory-mapped address pointers */
static volatile uint32_t *am335xgpio_gpio_port_mmap_addr[AM335XGPIO_NUM_GPIO_PORTS];
static int dev_mem_fd;
/* GPIO numbers for each signal. Negative values are invalid */
static int tck_gpio = -1;
static enum amx335gpio_gpio_mode tck_gpio_mode;
static int tms_gpio = -1;
static enum amx335gpio_gpio_mode tms_gpio_mode;
static int tdi_gpio = -1;
static enum amx335gpio_gpio_mode tdi_gpio_mode;
static int tdo_gpio = -1;
static enum amx335gpio_gpio_mode tdo_gpio_mode;
static int trst_gpio = -1;
static enum amx335gpio_gpio_mode trst_gpio_mode;
static int srst_gpio = -1;
static enum amx335gpio_gpio_mode srst_gpio_mode;
static int swclk_gpio = -1;
static enum amx335gpio_gpio_mode swclk_gpio_mode;
static int swdio_gpio = -1;
static enum amx335gpio_gpio_mode swdio_gpio_mode;
static int swdio_dir_gpio = -1;
static enum amx335gpio_gpio_mode swdio_dir_gpio_mode;
static int led_gpio = -1;
static enum amx335gpio_gpio_mode led_gpio_mode = -1;
static bool swdio_dir_is_active_high = true; /* Active state means output */
static bool led_is_active_high = true;
/* Transition delay coefficients */
static int speed_coeff = 600000;
static int speed_offset = 575;
static unsigned int jtag_delay;
static int is_gpio_valid(int gpio_num)
{
return gpio_num >= 0 && gpio_num < (32 * AM335XGPIO_NUM_GPIO_PORTS);
}
static int get_gpio_value(int gpio_num)
{
unsigned int shift = AM335XGPIO_BIT_NUM(gpio_num);
return (AM335XGPIO_READ_REG(gpio_num, AM335XGPIO_GPIO_DATAIN_OFFSET) >> shift) & 1;
}
static void set_gpio_value(int gpio_num, int value)
{
if (value)
AM335XGPIO_WRITE_REG(gpio_num, AM335XGPIO_GPIO_SETDATAOUT_OFFSET, AM335XGPIO_BIT_MASK(gpio_num));
else
AM335XGPIO_WRITE_REG(gpio_num, AM335XGPIO_GPIO_CLEARDATAOUT_OFFSET, AM335XGPIO_BIT_MASK(gpio_num));
}
static enum amx335gpio_gpio_mode get_gpio_mode(int gpio_num)
{
if (AM335XGPIO_READ_REG(gpio_num, AM335XGPIO_GPIO_OE_OFFSET) & AM335XGPIO_BIT_MASK(gpio_num)) {
return AM335XGPIO_GPIO_MODE_INPUT;
} else {
/* Return output level too so that pin mode can be fully restored */
if (AM335XGPIO_READ_REG(gpio_num, AM335XGPIO_GPIO_DATAOUT_OFFSET) & AM335XGPIO_BIT_MASK(gpio_num))
return AM335XGPIO_GPIO_MODE_OUTPUT_HIGH;
else
return AM335XGPIO_GPIO_MODE_OUTPUT_LOW;
}
}
static void set_gpio_mode(int gpio_num, enum amx335gpio_gpio_mode gpio_mode)
{
if (gpio_mode == AM335XGPIO_GPIO_MODE_INPUT) {
AM335XGPIO_SET_REG_BITS(gpio_num, AM335XGPIO_GPIO_OE_OFFSET, AM335XGPIO_BIT_MASK(gpio_num));
return;
}
if (gpio_mode == AM335XGPIO_GPIO_MODE_OUTPUT_LOW)
set_gpio_value(gpio_num, 0);
if (gpio_mode == AM335XGPIO_GPIO_MODE_OUTPUT_HIGH)
set_gpio_value(gpio_num, 1);
if (gpio_mode == AM335XGPIO_GPIO_MODE_OUTPUT ||
gpio_mode == AM335XGPIO_GPIO_MODE_OUTPUT_LOW ||
gpio_mode == AM335XGPIO_GPIO_MODE_OUTPUT_HIGH) {
AM335XGPIO_CLEAR_REG_BITS(gpio_num, AM335XGPIO_GPIO_OE_OFFSET, AM335XGPIO_BIT_MASK(gpio_num));
}
}
static const char *get_gpio_mode_name(enum amx335gpio_gpio_mode gpio_mode)
{
switch (gpio_mode) {
case AM335XGPIO_GPIO_MODE_INPUT:
return "input";
case AM335XGPIO_GPIO_MODE_OUTPUT:
return "output";
case AM335XGPIO_GPIO_MODE_OUTPUT_LOW:
return "output (low)";
case AM335XGPIO_GPIO_MODE_OUTPUT_HIGH:
return "output (high)";
default:
return "unknown";
}
}
static bb_value_t am335xgpio_read(void)
{
return get_gpio_value(tdo_gpio) ? BB_HIGH : BB_LOW;
}
static int am335xgpio_write(int tck, int tms, int tdi)
{
set_gpio_value(tdi_gpio, tdi);
set_gpio_value(tms_gpio, tms);
set_gpio_value(tck_gpio, tck); /* Write clock last */
for (unsigned int i = 0; i < jtag_delay; ++i)
asm volatile ("");
return ERROR_OK;
}
static int am335xgpio_swd_write(int swclk, int swdio)
{
set_gpio_value(swdio_gpio, swdio);
set_gpio_value(swclk_gpio, swclk); /* Write clock last */
for (unsigned int i = 0; i < jtag_delay; ++i)
asm volatile ("");
return ERROR_OK;
}
/* (1) assert or (0) deassert reset lines */
static int am335xgpio_reset(int trst, int srst)
{
/* assume active low */
if (is_gpio_valid(srst_gpio)) {
if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
set_gpio_mode(srst_gpio, srst ? AM335XGPIO_GPIO_MODE_OUTPUT_LOW : AM335XGPIO_GPIO_MODE_OUTPUT_HIGH);
else
set_gpio_mode(srst_gpio, srst ? AM335XGPIO_GPIO_MODE_OUTPUT_LOW : AM335XGPIO_GPIO_MODE_INPUT);
}
/* assume active low */
if (is_gpio_valid(trst_gpio)) {
if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
set_gpio_mode(trst_gpio, trst ? AM335XGPIO_GPIO_MODE_OUTPUT_LOW : AM335XGPIO_GPIO_MODE_INPUT);
else
set_gpio_mode(trst_gpio, trst ? AM335XGPIO_GPIO_MODE_OUTPUT_LOW : AM335XGPIO_GPIO_MODE_OUTPUT_HIGH);
}
LOG_DEBUG("am335xgpio_reset(%d, %d), trst_gpio: %d (%s), srst_gpio: %d (%s)",
trst, srst,
trst_gpio, get_gpio_mode_name(get_gpio_mode(trst_gpio)),
srst_gpio, get_gpio_mode_name(get_gpio_mode(srst_gpio)));
return ERROR_OK;
}
static void am335xgpio_swdio_drive(bool is_output)
{
if (is_output) {
set_gpio_value(swdio_dir_gpio, swdio_dir_is_active_high ? 1 : 0);
set_gpio_mode(swdio_gpio, AM335XGPIO_GPIO_MODE_OUTPUT);
} else {
set_gpio_mode(swdio_gpio, AM335XGPIO_GPIO_MODE_INPUT);
set_gpio_value(swdio_dir_gpio, swdio_dir_is_active_high ? 0 : 1);
}
}
static int am335xgpio_swdio_read(void)
{
return get_gpio_value(swdio_gpio);
}
static int am335xgpio_blink(int on)
{
if (is_gpio_valid(led_gpio))
set_gpio_value(led_gpio, (!on ^ led_is_active_high) ? 1 : 0);
return ERROR_OK;
}
static struct bitbang_interface am335xgpio_bitbang = {
.read = am335xgpio_read,
.write = am335xgpio_write,
.swdio_read = am335xgpio_swdio_read,
.swdio_drive = am335xgpio_swdio_drive,
.swd_write = am335xgpio_swd_write,
.blink = am335xgpio_blink
};
static int am335xgpio_khz(int khz, int *jtag_speed)
{
if (!khz) {
LOG_DEBUG("RCLK not supported");
return ERROR_FAIL;
}
*jtag_speed = speed_coeff / khz - speed_offset;
if (*jtag_speed < 0)
*jtag_speed = 0;
return ERROR_OK;
}
static int am335xgpio_speed_div(int speed, int *khz)
{
*khz = speed_coeff / (speed + speed_offset);
return ERROR_OK;
}
static int am335xgpio_speed(int speed)
{
jtag_delay = speed;
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionums)
{
if (CMD_ARGC == 4) {
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio);
} else if (CMD_ARGC != 0) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
command_print(CMD, "AM335x GPIO config: tck = %d, tms = %d, tdi = %d, tdo = %d",
tck_gpio, tms_gpio, tdi_gpio, tdo_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_tck)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio);
command_print(CMD, "AM335x GPIO config: tck = %d", tck_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_tms)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio);
command_print(CMD, "AM335x GPIO config: tms = %d", tms_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_tdo)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio);
command_print(CMD, "AM335x GPIO config: tdo = %d", tdo_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_tdi)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio);
command_print(CMD, "AM335x GPIO config: tdi = %d", tdi_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_srst)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio);
command_print(CMD, "AM335x GPIO config: srst = %d", srst_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_jtag_gpionum_trst)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio);
command_print(CMD, "AM335x GPIO config: trst = %d", trst_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_swd_gpionums)
{
if (CMD_ARGC == 2) {
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
} else if (CMD_ARGC != 0) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
command_print(CMD, "AM335x GPIO config: swclk = %d, swdio = %d", swclk_gpio, swdio_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_swd_gpionum_swclk)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
command_print(CMD, "AM335x GPIO config: swclk = %d", swclk_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_swd_gpionum_swdio)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
command_print(CMD, "AM335x GPIO config: swdio = %d", swdio_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_swd_gpionum_swdio_dir)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_dir_gpio);
command_print(CMD, "AM335x GPIO config: swdio_dir = %d", swdio_dir_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_swd_dir_output_state)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_BOOL(CMD_ARGV[0], swdio_dir_is_active_high, "high", "low");
command_print(CMD, "AM335x GPIO config: swdio_dir_output_state = %s", swdio_dir_is_active_high ? "high" : "low");
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_gpionum_led)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], led_gpio);
command_print(CMD, "AM335x GPIO config: led = %d", led_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_led_on_state)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_BOOL(CMD_ARGV[0], led_is_active_high, "high", "low");
command_print(CMD, "AM335x GPIO config: led_on_state = %s", led_is_active_high ? "high" : "low");
return ERROR_OK;
}
COMMAND_HANDLER(am335xgpio_handle_speed_coeffs)
{
if (CMD_ARGC == 2) {
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], speed_coeff);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], speed_offset);
}
command_print(CMD, "AM335x GPIO config: speed_coeffs = %d, speed_offset = %d",
speed_coeff, speed_offset);
return ERROR_OK;
}
static const struct command_registration am335xgpio_subcommand_handlers[] = {
{
.name = "jtag_nums",
.handler = am335xgpio_handle_jtag_gpionums,
.mode = COMMAND_CONFIG,
.help = "gpio numbers for tck, tms, tdi, tdo (in that order).",
.usage = "[tck tms tdi tdo]",
},
{
.name = "tck_num",
.handler = am335xgpio_handle_jtag_gpionum_tck,
.mode = COMMAND_CONFIG,
.help = "gpio number for tck.",
.usage = "[tck]",
},
{
.name = "tms_num",
.handler = am335xgpio_handle_jtag_gpionum_tms,
.mode = COMMAND_CONFIG,
.help = "gpio number for tms.",
.usage = "[tms]",
},
{
.name = "tdo_num",
.handler = am335xgpio_handle_jtag_gpionum_tdo,
.mode = COMMAND_CONFIG,
.help = "gpio number for tdo.",
.usage = "[tdo]",
},
{
.name = "tdi_num",
.handler = am335xgpio_handle_jtag_gpionum_tdi,
.mode = COMMAND_CONFIG,
.help = "gpio number for tdi.",
.usage = "[tdi]",
},
{
.name = "swd_nums",
.handler = am335xgpio_handle_swd_gpionums,
.mode = COMMAND_CONFIG,
.help = "gpio numbers for swclk, swdio (in that order).",
.usage = "[swclk swdio]",
},
{
.name = "swclk_num",
.handler = am335xgpio_handle_swd_gpionum_swclk,
.mode = COMMAND_CONFIG,
.help = "gpio number for swclk.",
.usage = "[swclk]",
},
{
.name = "swdio_num",
.handler = am335xgpio_handle_swd_gpionum_swdio,
.mode = COMMAND_CONFIG,
.help = "gpio number for swdio.",
.usage = "[swdio]",
},
{
.name = "swdio_dir_num",
.handler = am335xgpio_handle_swd_gpionum_swdio_dir,
.mode = COMMAND_CONFIG,
.help = "gpio number for swdio direction control pin.",
.usage = "[swdio_dir]",
},
{
.name = "swdio_dir_output_state",
.handler = am335xgpio_handle_swd_dir_output_state,
.mode = COMMAND_CONFIG,
.help = "required state for swdio_dir pin to select SWDIO buffer to be output.",
.usage = "['off'|'on']",
},
{
.name = "srst_num",
.handler = am335xgpio_handle_jtag_gpionum_srst,
.mode = COMMAND_CONFIG,
.help = "gpio number for srst.",
.usage = "[srst]",
},
{
.name = "trst_num",
.handler = am335xgpio_handle_jtag_gpionum_trst,
.mode = COMMAND_CONFIG,
.help = "gpio number for trst.",
.usage = "[trst]",
},
{
.name = "led_num",
.handler = am335xgpio_handle_gpionum_led,
.mode = COMMAND_CONFIG,
.help = "gpio number for led.",
.usage = "[led]",
},
{
.name = "led_on_state",
.handler = am335xgpio_handle_led_on_state,
.mode = COMMAND_CONFIG,
.help = "required state for led pin to turn on LED.",
.usage = "['off'|'on']",
},
{
.name = "speed_coeffs",
.handler = am335xgpio_handle_speed_coeffs,
.mode = COMMAND_CONFIG,
.help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
.usage = "[SPEED_COEFF SPEED_OFFSET]",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration am335xgpio_command_handlers[] = {
{
.name = "am335xgpio",
.mode = COMMAND_ANY,
.help = "perform am335xgpio management",
.chain = am335xgpio_subcommand_handlers,
.usage = "",
},
COMMAND_REGISTRATION_DONE
};
static const char * const am335xgpio_transports[] = { "jtag", "swd", NULL };
static struct jtag_interface am335xgpio_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
};
static bool am335xgpio_jtag_mode_possible(void)
{
if (!is_gpio_valid(tck_gpio))
return false;
if (!is_gpio_valid(tms_gpio))
return false;
if (!is_gpio_valid(tdi_gpio))
return false;
if (!is_gpio_valid(tdo_gpio))
return false;
return true;
}
static bool am335xgpio_swd_mode_possible(void)
{
if (!is_gpio_valid(swclk_gpio))
return false;
if (!is_gpio_valid(swdio_gpio))
return false;
return true;
}
static int am335xgpio_init(void)
{
bitbang_interface = &am335xgpio_bitbang;
LOG_INFO("AM335x GPIO JTAG/SWD bitbang driver");
if (transport_is_jtag() && !am335xgpio_jtag_mode_possible()) {
LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode");
return ERROR_JTAG_INIT_FAILED;
}
if (transport_is_swd() && !am335xgpio_swd_mode_possible()) {
LOG_ERROR("Require swclk and swdio gpio for SWD mode");
return ERROR_JTAG_INIT_FAILED;
}
dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
if (dev_mem_fd < 0) {
LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
}
if (dev_mem_fd < 0) {
LOG_ERROR("open: %s", strerror(errno));
return ERROR_JTAG_INIT_FAILED;
}
for (unsigned int i = 0; i < AM335XGPIO_NUM_GPIO_PORTS; ++i) {
am335xgpio_gpio_port_mmap_addr[i] = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
MAP_SHARED, dev_mem_fd, am335xgpio_gpio_port_hw_addr[i]);
if (am335xgpio_gpio_port_mmap_addr[i] == MAP_FAILED) {
LOG_ERROR("mmap: %s", strerror(errno));
close(dev_mem_fd);
return ERROR_JTAG_INIT_FAILED;
}
}
/*
* Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST as outputs.
* Drive TDI and TCK low, and TMS high.
*/
if (transport_is_jtag()) {
tdo_gpio_mode = get_gpio_mode(tdo_gpio);
tdi_gpio_mode = get_gpio_mode(tdi_gpio);
tck_gpio_mode = get_gpio_mode(tck_gpio);
tms_gpio_mode = get_gpio_mode(tms_gpio);
LOG_DEBUG("saved GPIO mode for tdo (GPIO #%d): %s", tdo_gpio, get_gpio_mode_name(tdo_gpio_mode));
LOG_DEBUG("saved GPIO mode for tdi (GPIO #%d): %s", tdi_gpio, get_gpio_mode_name(tdi_gpio_mode));
LOG_DEBUG("saved GPIO mode for tck (GPIO #%d): %s", tck_gpio, get_gpio_mode_name(tck_gpio_mode));
LOG_DEBUG("saved GPIO mode for tms (GPIO #%d): %s", tms_gpio, get_gpio_mode_name(tms_gpio_mode));
set_gpio_mode(tdo_gpio, AM335XGPIO_GPIO_MODE_INPUT);
set_gpio_mode(tdi_gpio, AM335XGPIO_GPIO_MODE_OUTPUT_LOW);
set_gpio_mode(tms_gpio, AM335XGPIO_GPIO_MODE_OUTPUT_HIGH);
set_gpio_mode(tck_gpio, AM335XGPIO_GPIO_MODE_OUTPUT_LOW);
if (is_gpio_valid(trst_gpio)) {
trst_gpio_mode = get_gpio_mode(trst_gpio);
LOG_DEBUG("saved GPIO mode for trst (GPIO #%d): %s", trst_gpio, get_gpio_mode_name(trst_gpio_mode));
}
}
if (transport_is_swd()) {
swclk_gpio_mode = get_gpio_mode(swclk_gpio);
swdio_gpio_mode = get_gpio_mode(swdio_gpio);
LOG_DEBUG("saved GPIO mode for swclk (GPIO #%d): %s", swclk_gpio, get_gpio_mode_name(swclk_gpio_mode));
LOG_DEBUG("saved GPIO mode for swdio (GPIO #%d): %s", swdio_gpio, get_gpio_mode_name(swdio_gpio_mode));
if (is_gpio_valid(swdio_dir_gpio)) {
swdio_dir_gpio_mode = get_gpio_mode(swdio_dir_gpio);
LOG_DEBUG("saved GPIO mode for swdio_dir (GPIO #%d): %s",
swdio_dir_gpio, get_gpio_mode_name(swdio_dir_gpio_mode));
set_gpio_mode(swdio_dir_gpio,
swdio_dir_is_active_high ? AM335XGPIO_GPIO_MODE_OUTPUT_HIGH : AM335XGPIO_GPIO_MODE_OUTPUT_LOW);
}
set_gpio_mode(swdio_gpio, AM335XGPIO_GPIO_MODE_OUTPUT_LOW);
set_gpio_mode(swclk_gpio, AM335XGPIO_GPIO_MODE_OUTPUT_LOW);
}
if (is_gpio_valid(srst_gpio)) {
srst_gpio_mode = get_gpio_mode(srst_gpio);
LOG_DEBUG("saved GPIO mode for srst (GPIO #%d): %s", srst_gpio, get_gpio_mode_name(srst_gpio_mode));
}
if (is_gpio_valid(led_gpio)) {
led_gpio_mode = get_gpio_mode(led_gpio);
LOG_DEBUG("saved GPIO mode for led (GPIO #%d): %s", led_gpio, get_gpio_mode_name(led_gpio_mode));
set_gpio_mode(led_gpio,
led_is_active_high ? AM335XGPIO_GPIO_MODE_OUTPUT_LOW : AM335XGPIO_GPIO_MODE_OUTPUT_HIGH);
}
/* Set GPIO modes for TRST and SRST and make both inactive */
am335xgpio_reset(0, 0);
return ERROR_OK;
}
static int am335xgpio_quit(void)
{
if (transport_is_jtag()) {
set_gpio_mode(tdo_gpio, tdo_gpio_mode);
set_gpio_mode(tdi_gpio, tdi_gpio_mode);
set_gpio_mode(tck_gpio, tck_gpio_mode);
set_gpio_mode(tms_gpio, tms_gpio_mode);
if (is_gpio_valid(trst_gpio))
set_gpio_mode(trst_gpio, trst_gpio_mode);
}
if (transport_is_swd()) {
set_gpio_mode(swclk_gpio, swclk_gpio_mode);
set_gpio_mode(swdio_gpio, swdio_gpio_mode);
if (is_gpio_valid(swdio_dir_gpio))
set_gpio_mode(swdio_dir_gpio, swdio_dir_gpio_mode);
}
if (is_gpio_valid(srst_gpio))
set_gpio_mode(srst_gpio, srst_gpio_mode);
if (is_gpio_valid(led_gpio))
set_gpio_mode(led_gpio, led_gpio_mode);
return ERROR_OK;
}
struct adapter_driver am335xgpio_adapter_driver = {
.name = "am335xgpio",
.transports = am335xgpio_transports,
.commands = am335xgpio_command_handlers,
.init = am335xgpio_init,
.quit = am335xgpio_quit,
.reset = am335xgpio_reset,
.speed = am335xgpio_speed,
.khz = am335xgpio_khz,
.speed_div = am335xgpio_speed_div,
.jtag_ops = &am335xgpio_interface,
.swd_ops = &bitbang_swd,
};

View File

@ -94,6 +94,11 @@ static int speed_coeff = 113714;
static int speed_offset = 28;
static unsigned int jtag_delay;
static int is_gpio_valid(int gpio)
{
return gpio >= 0 && gpio <= 31;
}
static bb_value_t bcm2835gpio_read(void)
{
return (GPIO_LEV & 1<<tdo_gpio) ? BB_HIGH : BB_LOW;
@ -133,12 +138,12 @@ static int bcm2835gpio_reset(int trst, int srst)
uint32_t set = 0;
uint32_t clear = 0;
if (trst_gpio > 0) {
if (is_gpio_valid(trst_gpio)) {
set |= !trst<<trst_gpio;
clear |= trst<<trst_gpio;
}
if (srst_gpio > 0) {
if (is_gpio_valid(srst_gpio)) {
set |= !srst<<srst_gpio;
clear |= srst<<srst_gpio;
}
@ -151,7 +156,7 @@ static int bcm2835gpio_reset(int trst, int srst)
static void bcm2835_swdio_drive(bool is_output)
{
if (swdio_dir_gpio > 0) {
if (is_gpio_valid(swdio_dir_gpio)) {
if (is_output) {
GPIO_SET = 1 << swdio_dir_gpio;
OUT_GPIO(swdio_gpio);
@ -196,11 +201,6 @@ static int bcm2835gpio_speed(int speed)
return ERROR_OK;
}
static int is_gpio_valid(int gpio)
{
return gpio >= 0 && gpio <= 31;
}
COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
{
if (CMD_ARGC == 4) {
@ -557,7 +557,7 @@ static int bcm2835gpio_init(void)
OUT_GPIO(tck_gpio);
OUT_GPIO(tms_gpio);
if (trst_gpio != -1) {
if (is_gpio_valid(trst_gpio)) {
trst_gpio_mode = MODE_GPIO(trst_gpio);
GPIO_SET = 1 << trst_gpio;
OUT_GPIO(trst_gpio);
@ -566,7 +566,7 @@ static int bcm2835gpio_init(void)
if (transport_is_swd()) {
/* Make buffer an output before the GPIO connected to it */
if (swdio_dir_gpio != -1) {
if (is_gpio_valid(swdio_dir_gpio)) {
swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio);
GPIO_SET = 1 << swdio_dir_gpio;
OUT_GPIO(swdio_dir_gpio);
@ -581,7 +581,7 @@ static int bcm2835gpio_init(void)
OUT_GPIO(swdio_gpio);
}
if (srst_gpio != -1) {
if (is_gpio_valid(srst_gpio)) {
srst_gpio_mode = MODE_GPIO(srst_gpio);
GPIO_SET = 1 << srst_gpio;
OUT_GPIO(srst_gpio);
@ -601,7 +601,7 @@ static int bcm2835gpio_quit(void)
SET_MODE_GPIO(tdi_gpio, tdi_gpio_mode);
SET_MODE_GPIO(tck_gpio, tck_gpio_mode);
SET_MODE_GPIO(tms_gpio, tms_gpio_mode);
if (trst_gpio != -1)
if (is_gpio_valid(trst_gpio))
SET_MODE_GPIO(trst_gpio, trst_gpio_mode);
}
@ -610,10 +610,10 @@ static int bcm2835gpio_quit(void)
SET_MODE_GPIO(swdio_gpio, swdio_gpio_mode);
}
if (srst_gpio != -1)
if (is_gpio_valid(srst_gpio))
SET_MODE_GPIO(srst_gpio, srst_gpio_mode);
if (swdio_dir_gpio != -1)
if (is_gpio_valid(swdio_dir_gpio))
SET_MODE_GPIO(swdio_dir_gpio, swdio_dir_gpio_mode);
return ERROR_OK;

View File

@ -532,8 +532,9 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
bool check_ack = swd_cmd_returns_ack(cmd);
/* init the array to silence scan-build */
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)] = {0};
for (;;) {
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value);
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value));

View File

@ -504,6 +504,8 @@ static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, i
#define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053
#define STLINK_TCP_SS_TCP_ERROR 0x00002001
#define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002
#define STLINK_TCP_SS_TCP_CLOSE_ERROR 0x00002003
#define STLINK_TCP_SS_TCP_BUSY 0x00002004
#define STLINK_TCP_SS_WIN32_ERROR 0x00010000
/*
@ -971,6 +973,11 @@ static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool
if (check_tcp_status) {
uint32_t tcp_ss = le_to_h_u32(h->tcp_backend_priv.recv_buf);
if (tcp_ss != STLINK_TCP_SS_OK) {
if (tcp_ss == STLINK_TCP_SS_TCP_BUSY) {
LOG_DEBUG("TCP busy");
return ERROR_WAIT;
}
LOG_ERROR("TCP error status 0x%X", tcp_ss);
return ERROR_FAIL;
}

View File

@ -150,6 +150,9 @@ extern struct adapter_driver stlink_dap_adapter_driver;
#if BUILD_RSHIM == 1
extern struct adapter_driver rshim_dap_adapter_driver;
#endif
#if BUILD_AM335XGPIO == 1
extern struct adapter_driver am335xgpio_adapter_driver;
#endif
/**
* The list of built-in JTAG interfaces, containing entries for those
@ -263,6 +266,9 @@ struct adapter_driver *adapter_drivers[] = {
#endif
#if BUILD_RSHIM == 1
&rshim_dap_adapter_driver,
#endif
#if BUILD_AM335XGPIO == 1
&am335xgpio_adapter_driver,
#endif
NULL,
};

View File

@ -182,6 +182,9 @@ COMMAND_HANDLER(handle_init_command)
target_register_event_callback(log_target_callback_event_handler, CMD_CTX);
if (command_run_line(CMD_CTX, "_run_post_init_commands") != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}

View File

@ -3716,12 +3716,14 @@ static int gdb_input_inner(struct connection *connection)
break;
case 'j':
/* DEPRECATED */
/* packet supported only by smp target i.e cortex_a.c*/
/* handle smp packet replying coreid played to gbd */
gdb_read_smp_packet(connection, packet, packet_size);
break;
case 'J':
/* DEPRECATED */
/* packet supported only by smp target i.e cortex_a.c */
/* handle smp packet setting coreid to be played at next
* resume to gdb */

View File

@ -763,6 +763,8 @@ COMMAND_HANDLER(handle_shutdown_command)
shutdown_openocd = SHUTDOWN_REQUESTED;
command_run_line(CMD_CTX, "_run_pre_shutdown_commands");
if (CMD_ARGC == 1) {
if (!strcmp(CMD_ARGV[0], "error")) {
shutdown_openocd = SHUTDOWN_WITH_ERROR_CODE;

View File

@ -222,9 +222,8 @@ static int telnet_new_connection(struct connection *connection)
{
struct telnet_connection *telnet_connection;
struct telnet_service *telnet_service = connection->service->priv;
int i;
telnet_connection = malloc(sizeof(struct telnet_connection));
telnet_connection = calloc(1, sizeof(struct telnet_connection));
if (!telnet_connection) {
LOG_ERROR("Failed to allocate telnet connection.");
@ -234,9 +233,6 @@ static int telnet_new_connection(struct connection *connection)
connection->priv = telnet_connection;
/* initialize telnet connection information */
telnet_connection->closed = false;
telnet_connection->line_size = 0;
telnet_connection->line_cursor = 0;
telnet_connection->prompt = strdup("> ");
telnet_connection->prompt_visible = true;
telnet_connection->state = TELNET_STATE_DATA;
@ -257,11 +253,6 @@ static int telnet_new_connection(struct connection *connection)
telnet_write(connection, "\r", 1);
telnet_prompt(connection);
/* initialize history */
for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++)
telnet_connection->history[i] = NULL;
telnet_connection->next_history = 0;
telnet_connection->current_history = 0;
telnet_load_history(telnet_connection);
log_add_callback(telnet_log_callback, connection);
@ -624,7 +615,11 @@ static void telnet_auto_complete(struct connection *connection)
while ((usr_cmd_pos < t_con->line_cursor) && isspace(t_con->line[usr_cmd_pos]))
usr_cmd_pos++;
/* user command length */
/* check user command length */
if (t_con->line_cursor < usr_cmd_pos) {
telnet_bell(connection);
return;
}
size_t usr_cmd_len = t_con->line_cursor - usr_cmd_pos;
/* optimize multiple spaces in the user command,

View File

@ -1,5 +1,7 @@
%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
%D%/riscv/libriscv.la
%D%/riscv/libriscv.la \
%D%/xtensa/libxtensa.la \
%D%/espressif/libespressif.la
%C%_libtarget_la_CPPFLAGS = $(AM_CPPFLAGS)
@ -260,3 +262,5 @@ ARC_SRC = \
include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am
include %D%/xtensa/Makefile.am
include %D%/espressif/Makefile.am

View File

@ -2026,9 +2026,13 @@ static int aarch64_deassert_reset(struct target *target)
if (target->state != TARGET_HALTED) {
LOG_WARNING("%s: ran after reset and before halt ...",
target_name(target));
retval = target_halt(target);
if (retval != ERROR_OK)
return retval;
if (target_was_examined(target)) {
retval = aarch64_halt_one(target, HALT_LAZY);
if (retval != ERROR_OK)
return retval;
} else {
target->state = TARGET_UNKNOWN;
}
}
}
@ -2574,20 +2578,13 @@ static int aarch64_examine_first(struct target *target)
armv8->debug_ap->memaccess_tck = 10;
if (!target->dbgbase_set) {
target_addr_t dbgbase;
/* Get ROM Table base */
uint32_t apid;
int32_t coreidx = target->coreid;
retval = dap_get_debugbase(armv8->debug_ap, &dbgbase, &apid);
if (retval != ERROR_OK)
return retval;
/* Lookup Processor DAP */
retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&armv8->debug_base, &coreidx);
retval = dap_lookup_cs_component(armv8->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&armv8->debug_base, target->coreid);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT
" apid: %08" PRIx32, coreidx, armv8->debug_base, apid);
LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT,
target->coreid, armv8->debug_base);
} else
armv8->debug_base = target->dbgbase;

View File

@ -532,7 +532,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
/* check for overrun condition in the last batch of transactions */
if (found_wait) {
LOG_INFO("DAP transaction stalled (WAIT) - slowing down");
LOG_INFO("DAP transaction stalled (WAIT) - slowing down and resending");
/* clear the sticky overrun condition */
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_WRITE,
@ -574,7 +574,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap)
retval = ERROR_JTAG_DEVICE_ERROR;
break;
}
LOG_INFO("DAP transaction stalled during replay (WAIT) - resending");
LOG_DEBUG("DAP transaction stalled during replay (WAIT) - resending");
/* clear the sticky overrun condition */
retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC,
DP_CTRL_STAT, DPAP_WRITE,

View File

@ -893,6 +893,55 @@ static const char *class_description[16] = {
[0xF] = "CoreLink, PrimeCell or System component",
};
#define ARCH_ID(architect, archid) ( \
(((architect) << ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) | \
(((archid) << ARM_CS_C9_DEVARCH_ARCHID_SHIFT) & ARM_CS_C9_DEVARCH_ARCHID_MASK) \
)
static const struct {
uint32_t arch_id;
const char *description;
} class0x9_devarch[] = {
/* keep same unsorted order as in ARM IHI0029E */
{ ARCH_ID(ARM_ID, 0x0A00), "RAS architecture" },
{ ARCH_ID(ARM_ID, 0x1A01), "Instrumentation Trace Macrocell (ITM) architecture" },
{ ARCH_ID(ARM_ID, 0x1A02), "DWT architecture" },
{ ARCH_ID(ARM_ID, 0x1A03), "Flash Patch and Breakpoint unit (FPB) architecture" },
{ ARCH_ID(ARM_ID, 0x2A04), "Processor debug architecture (ARMv8-M)" },
{ ARCH_ID(ARM_ID, 0x6A05), "Processor debug architecture (ARMv8-R)" },
{ ARCH_ID(ARM_ID, 0x0A10), "PC sample-based profiling" },
{ ARCH_ID(ARM_ID, 0x4A13), "Embedded Trace Macrocell (ETM) architecture" },
{ ARCH_ID(ARM_ID, 0x1A14), "Cross Trigger Interface (CTI) architecture" },
{ ARCH_ID(ARM_ID, 0x6A15), "Processor debug architecture (v8.0-A)" },
{ ARCH_ID(ARM_ID, 0x7A15), "Processor debug architecture (v8.1-A)" },
{ ARCH_ID(ARM_ID, 0x8A15), "Processor debug architecture (v8.2-A)" },
{ ARCH_ID(ARM_ID, 0x2A16), "Processor Performance Monitor (PMU) architecture" },
{ ARCH_ID(ARM_ID, 0x0A17), "Memory Access Port v2 architecture" },
{ ARCH_ID(ARM_ID, 0x0A27), "JTAG Access Port v2 architecture" },
{ ARCH_ID(ARM_ID, 0x0A31), "Basic trace router" },
{ ARCH_ID(ARM_ID, 0x0A37), "Power requestor" },
{ ARCH_ID(ARM_ID, 0x0A47), "Unknown Access Port v2 architecture" },
{ ARCH_ID(ARM_ID, 0x0A50), "HSSTP architecture" },
{ ARCH_ID(ARM_ID, 0x0A63), "System Trace Macrocell (STM) architecture" },
{ ARCH_ID(ARM_ID, 0x0A75), "CoreSight ELA architecture" },
{ ARCH_ID(ARM_ID, 0x0AF7), "CoreSight ROM architecture" },
};
#define DEVARCH_ID_MASK (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK)
#define DEVARCH_ROM_C_0X9 ARCH_ID(ARM_ID, 0x0AF7)
static const char *class0x9_devarch_description(uint32_t devarch)
{
if (!(devarch & ARM_CS_C9_DEVARCH_PRESENT))
return "not present";
for (unsigned int i = 0; i < ARRAY_SIZE(class0x9_devarch); i++)
if ((devarch & DEVARCH_ID_MASK) == class0x9_devarch[i].arch_id)
return class0x9_devarch[i].description;
return "unknown";
}
static const struct {
enum ap_type type;
const char *description;
@ -953,7 +1002,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
return ERROR_FAIL;
}
int dap_get_debugbase(struct adiv5_ap *ap,
static int dap_get_debugbase(struct adiv5_ap *ap,
target_addr_t *dbgbase, uint32_t *apid)
{
struct adiv5_dap *dap = ap->dap;
@ -989,109 +1038,89 @@ int dap_get_debugbase(struct adiv5_ap *ap,
return ERROR_OK;
}
int dap_lookup_cs_component(struct adiv5_ap *ap,
target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx)
{
uint32_t romentry, entry_offset = 0, devtype;
/** Holds registers and coordinates of a CoreSight component */
struct cs_component_vals {
struct adiv5_ap *ap;
target_addr_t component_base;
int retval;
uint64_t pid;
uint32_t cid;
uint32_t devarch;
uint32_t devid;
uint32_t devtype_memtype;
};
dbgbase &= 0xFFFFFFFFFFFFF000ull;
*addr = 0;
do {
retval = mem_ap_read_atomic_u32(ap, dbgbase |
entry_offset, &romentry);
if (retval != ERROR_OK)
return retval;
component_base = dbgbase + (target_addr_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK);
if (romentry & ARM_CS_ROMENTRY_PRESENT) {
uint32_t c_cid1;
retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_CIDR1, &c_cid1);
if (retval != ERROR_OK) {
LOG_ERROR("Can't read component with base address " TARGET_ADDR_FMT
", the corresponding core might be turned off", component_base);
return retval;
}
unsigned int class = (c_cid1 & ARM_CS_CIDR1_CLASS_MASK) >> ARM_CS_CIDR1_CLASS_SHIFT;
if (class == ARM_CS_CLASS_0X1_ROM_TABLE) {
retval = dap_lookup_cs_component(ap, component_base,
type, addr, idx);
if (retval == ERROR_OK)
break;
if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return retval;
}
retval = mem_ap_read_atomic_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &devtype);
if (retval != ERROR_OK)
return retval;
if ((devtype & ARM_CS_C9_DEVTYPE_MASK) == type) {
if (!*idx) {
*addr = component_base;
break;
} else
(*idx)--;
}
}
entry_offset += 4;
} while ((romentry > 0) && (entry_offset < 0xf00));
if (!*addr)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
return ERROR_OK;
}
static int dap_read_part_id(struct adiv5_ap *ap, target_addr_t component_base, uint32_t *cid, uint64_t *pid)
/**
* Read the CoreSight registers needed during ROM Table Parsing (RTP).
*
* @param ap Pointer to AP containing the component.
* @param component_base On MEM-AP access method, base address of the component.
* @param v Pointer to the struct holding the value of registers.
*
* @return ERROR_OK on success, else a fault code.
*/
static int rtp_read_cs_regs(struct adiv5_ap *ap, target_addr_t component_base,
struct cs_component_vals *v)
{
assert(IS_ALIGNED(component_base, ARM_CS_ALIGN));
assert(ap && cid && pid);
assert(ap && v);
uint32_t cid0, cid1, cid2, cid3;
uint32_t pid0, pid1, pid2, pid3, pid4;
int retval;
int retval = ERROR_OK;
/* IDs are in last 4K section */
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR0, &pid0);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR1, &pid1);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR2, &pid2);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR3, &pid3);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR4, &pid4);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR0, &cid0);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR1, &cid1);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR2, &cid2);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR3, &cid3);
if (retval != ERROR_OK)
return retval;
v->ap = ap;
v->component_base = component_base;
retval = dap_run(ap->dap);
if (retval != ERROR_OK)
return retval;
/* sort by offset to gain speed */
*cid = (cid3 & 0xff) << 24
/*
* Registers DEVARCH, DEVID and DEVTYPE are valid on Class 0x9 devices
* only, but are at offset above 0xf00, so can be read on any device
* without triggering error. Read them for eventual use on Class 0x9.
*/
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVARCH, &v->devarch);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVID, &v->devid);
/* Same address as ARM_CS_C1_MEMTYPE */
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_C9_DEVTYPE, &v->devtype_memtype);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR4, &pid4);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR0, &pid0);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR1, &pid1);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR2, &pid2);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_PIDR3, &pid3);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR0, &cid0);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR1, &cid1);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR2, &cid2);
if (retval == ERROR_OK)
retval = mem_ap_read_u32(ap, component_base + ARM_CS_CIDR3, &cid3);
if (retval == ERROR_OK)
retval = dap_run(ap->dap);
if (retval != ERROR_OK) {
LOG_DEBUG("Failed read CoreSight registers");
return retval;
}
v->cid = (cid3 & 0xff) << 24
| (cid2 & 0xff) << 16
| (cid1 & 0xff) << 8
| (cid0 & 0xff);
*pid = (uint64_t)(pid4 & 0xff) << 32
v->pid = (uint64_t)(pid4 & 0xff) << 32
| (pid3 & 0xff) << 24
| (pid2 & 0xff) << 16
| (pid1 & 0xff) << 8
@ -1397,122 +1426,269 @@ static int dap_devtype_display(struct command_invocation *cmd, uint32_t devtype)
return ERROR_OK;
}
static int dap_rom_display(struct command_invocation *cmd,
struct adiv5_ap *ap, target_addr_t dbgbase, int depth)
/**
* Actions/operations to be executed while parsing ROM tables.
*/
struct rtp_ops {
/**
* Executed at the start of a new MEM-AP, typically to print the MEM-AP header.
* @param retval Error encountered while reading AP.
* @param ap Pointer to AP.
* @param dbgbase Value of MEM-AP Debug Base Address register.
* @param apid Value of MEM-AP IDR Identification Register.
* @param priv Pointer to private data.
* @return ERROR_OK on success, else a fault code.
*/
int (*mem_ap_header)(int retval, struct adiv5_ap *ap, uint64_t dbgbase,
uint32_t apid, void *priv);
/**
* Executed when a CoreSight component is parsed, typically to print
* information on the component.
* @param retval Error encountered while reading component's registers.
* @param v Pointer to a container of the component's registers.
* @param depth The current depth level of ROM table.
* @param priv Pointer to private data.
* @return ERROR_OK on success, else a fault code.
*/
int (*cs_component)(int retval, struct cs_component_vals *v, int depth, void *priv);
/**
* Executed for each entry of a ROM table, typically to print the entry
* and information about validity or end-of-table mark.
* @param retval Error encountered while reading the ROM table entry.
* @param depth The current depth level of ROM table.
* @param offset The offset of the entry in the ROM table.
* @param romentry The value of the ROM table entry.
* @param priv Pointer to private data.
* @return ERROR_OK on success, else a fault code.
*/
int (*rom_table_entry)(int retval, int depth, unsigned int offset, uint64_t romentry,
void *priv);
/**
* Private data
*/
void *priv;
};
/**
* Wrapper around struct rtp_ops::mem_ap_header.
* Input parameter @a retval is propagated.
*/
static int rtp_ops_mem_ap_header(const struct rtp_ops *ops,
int retval, struct adiv5_ap *ap, uint64_t dbgbase, uint32_t apid)
{
int retval;
uint64_t pid;
uint32_t cid;
char tabs[16] = "";
if (!ops->mem_ap_header)
return retval;
if (depth > 16) {
command_print(cmd, "\tTables too deep");
return ERROR_FAIL;
}
int retval1 = ops->mem_ap_header(retval, ap, dbgbase, apid, ops->priv);
if (retval != ERROR_OK)
return retval;
return retval1;
}
if (depth)
snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
/**
* Wrapper around struct rtp_ops::cs_component.
* Input parameter @a retval is propagated.
*/
static int rtp_ops_cs_component(const struct rtp_ops *ops,
int retval, struct cs_component_vals *v, int depth)
{
if (!ops->cs_component)
return retval;
target_addr_t base_addr = dbgbase & 0xFFFFFFFFFFFFF000ull;
command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, base_addr);
int retval1 = ops->cs_component(retval, v, depth, ops->priv);
if (retval != ERROR_OK)
return retval;
return retval1;
}
retval = dap_read_part_id(ap, base_addr, &cid, &pid);
if (retval != ERROR_OK) {
command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
return ERROR_OK; /* Don't abort recursion */
}
/**
* Wrapper around struct rtp_ops::rom_table_entry.
* Input parameter @a retval is propagated.
*/
static int rtp_ops_rom_table_entry(const struct rtp_ops *ops,
int retval, int depth, unsigned int offset, uint64_t romentry)
{
if (!ops->rom_table_entry)
return retval;
if (!is_valid_arm_cs_cidr(cid)) {
command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, cid);
return ERROR_OK; /* Don't abort recursion */
}
int retval1 = ops->rom_table_entry(retval, depth, offset, romentry, ops->priv);
if (retval != ERROR_OK)
return retval;
return retval1;
}
/* component may take multiple 4K pages */
uint32_t size = ARM_CS_PIDR_SIZE(pid);
if (size > 0)
command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, base_addr - 0x1000 * size);
/* Broken ROM tables can have circular references. Stop after a while */
#define ROM_TABLE_MAX_DEPTH (16)
command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, pid);
/**
* Value used only during lookup of a CoreSight component in ROM table.
* Return CORESIGHT_COMPONENT_FOUND when component is found.
* Return ERROR_OK when component is not found yet.
* Return any other ERROR_* in case of error.
*/
#define CORESIGHT_COMPONENT_FOUND (1)
const unsigned int class = (cid & ARM_CS_CIDR_CLASS_MASK) >> ARM_CS_CIDR_CLASS_SHIFT;
const unsigned int part_num = ARM_CS_PIDR_PART(pid);
unsigned int designer_id = ARM_CS_PIDR_DESIGNER(pid);
static int rtp_cs_component(const struct rtp_ops *ops,
struct adiv5_ap *ap, target_addr_t dbgbase, int depth);
if (pid & ARM_CS_PIDR_JEDEC) {
/* JEP106 code */
command_print(cmd, "\t\tDesigner is 0x%03x, %s",
designer_id, jep106_manufacturer(designer_id));
} else {
/* Legacy ASCII ID, clear invalid bits */
designer_id &= 0x7f;
command_print(cmd, "\t\tDesigner ASCII code 0x%02x, %s",
designer_id, designer_id == 0x41 ? "ARM" : "<unknown>");
}
static int rtp_rom_loop(const struct rtp_ops *ops,
struct adiv5_ap *ap, target_addr_t base_address, int depth,
unsigned int width, unsigned int max_entries)
{
assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
const struct dap_part_nums *partnum = pidr_to_part_num(designer_id, part_num);
command_print(cmd, "\t\tPart is 0x%03x, %s %s", part_num, partnum->type, partnum->full);
command_print(cmd, "\t\tComponent class is 0x%x, %s", class, class_description[class]);
unsigned int offset = 0;
while (max_entries--) {
uint64_t romentry;
uint32_t romentry_low, romentry_high;
target_addr_t component_base;
unsigned int saved_offset = offset;
if (class == ARM_CS_CLASS_0X1_ROM_TABLE) {
uint32_t memtype;
retval = mem_ap_read_atomic_u32(ap, base_addr + ARM_CS_C1_MEMTYPE, &memtype);
if (retval != ERROR_OK)
return retval;
if (memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK)
command_print(cmd, "\t\tMEMTYPE system memory present on bus");
else
command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
/* Read ROM table entries from base address until we get 0x00000000 or reach the reserved area */
for (uint16_t entry_offset = 0; entry_offset < 0xF00; entry_offset += 4) {
uint32_t romentry;
retval = mem_ap_read_atomic_u32(ap, base_addr | entry_offset, &romentry);
if (retval != ERROR_OK)
return retval;
command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%" PRIx32 "",
tabs, entry_offset, romentry);
if (romentry & ARM_CS_ROMENTRY_PRESENT) {
/* Recurse. "romentry" is signed */
retval = dap_rom_display(cmd, ap, base_addr + (int32_t)(romentry & ARM_CS_ROMENTRY_OFFSET_MASK),
depth + 1);
if (retval != ERROR_OK)
return retval;
} else if (romentry != 0) {
command_print(cmd, "\t\tComponent not present");
} else {
command_print(cmd, "\t%s\tEnd of ROM table", tabs);
break;
}
int retval = mem_ap_read_u32(ap, base_address + offset, &romentry_low);
offset += 4;
if (retval == ERROR_OK && width == 64) {
retval = mem_ap_read_u32(ap, base_address + offset, &romentry_high);
offset += 4;
}
} else if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
uint32_t devtype;
retval = mem_ap_read_atomic_u32(ap, base_addr + ARM_CS_C9_DEVTYPE, &devtype);
if (retval == ERROR_OK)
retval = dap_run(ap->dap);
if (retval != ERROR_OK) {
LOG_DEBUG("Failed read ROM table entry");
return retval;
}
if (width == 64) {
romentry = (((uint64_t)romentry_high) << 32) | romentry_low;
component_base = base_address +
((((uint64_t)romentry_high) << 32) | (romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK));
} else {
romentry = romentry_low;
/* "romentry" is signed */
component_base = base_address + (int32_t)(romentry_low & ARM_CS_ROMENTRY_OFFSET_MASK);
if (!is_64bit_ap(ap))
component_base = (uint32_t)component_base;
}
retval = rtp_ops_rom_table_entry(ops, retval, depth, saved_offset, romentry);
if (retval != ERROR_OK)
return retval;
retval = dap_devtype_display(cmd, devtype);
if (retval != ERROR_OK)
return retval;
if (romentry == 0) {
/* End of ROM table */
break;
}
/* REVISIT also show ARM_CS_C9_DEVID */
if (!(romentry & ARM_CS_ROMENTRY_PRESENT))
continue;
/* Recurse */
retval = rtp_cs_component(ops, ap, component_base, depth + 1);
if (retval == CORESIGHT_COMPONENT_FOUND)
return CORESIGHT_COMPONENT_FOUND;
if (retval != ERROR_OK) {
/* TODO: do we need to send an ABORT before continuing? */
LOG_DEBUG("Ignore error parsing CoreSight component");
continue;
}
}
return ERROR_OK;
}
int dap_info_command(struct command_invocation *cmd,
struct adiv5_ap *ap)
static int rtp_cs_component(const struct rtp_ops *ops,
struct adiv5_ap *ap, target_addr_t base_address, int depth)
{
struct cs_component_vals v;
int retval;
assert(IS_ALIGNED(base_address, ARM_CS_ALIGN));
if (depth > ROM_TABLE_MAX_DEPTH)
retval = ERROR_FAIL;
else
retval = rtp_read_cs_regs(ap, base_address, &v);
retval = rtp_ops_cs_component(ops, retval, &v, depth);
if (retval == CORESIGHT_COMPONENT_FOUND)
return CORESIGHT_COMPONENT_FOUND;
if (retval != ERROR_OK)
return ERROR_OK; /* Don't abort recursion */
if (!is_valid_arm_cs_cidr(v.cid))
return ERROR_OK; /* Don't abort recursion */
const unsigned int class = ARM_CS_CIDR_CLASS(v.cid);
if (class == ARM_CS_CLASS_0X1_ROM_TABLE)
return rtp_rom_loop(ops, ap, base_address, depth, 32, 960);
if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
if ((v.devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
return ERROR_OK;
/* quit if not ROM table */
if ((v.devarch & DEVARCH_ID_MASK) != DEVARCH_ROM_C_0X9)
return ERROR_OK;
if ((v.devid & ARM_CS_C9_DEVID_FORMAT_MASK) == ARM_CS_C9_DEVID_FORMAT_64BIT)
return rtp_rom_loop(ops, ap, base_address, depth, 64, 256);
else
return rtp_rom_loop(ops, ap, base_address, depth, 32, 512);
}
/* Class other than 0x1 and 0x9 */
return ERROR_OK;
}
static int rtp_ap(const struct rtp_ops *ops, struct adiv5_ap *ap)
{
int retval;
uint32_t apid;
target_addr_t dbgbase;
target_addr_t dbgaddr;
target_addr_t dbgbase, invalid_entry;
/* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */
retval = dap_get_debugbase(ap, &dbgbase, &apid);
if (retval != ERROR_OK)
return retval;
retval = rtp_ops_mem_ap_header(ops, retval, ap, dbgbase, apid);
if (retval != ERROR_OK)
return retval;
if (apid == 0)
return ERROR_FAIL;
/* NOTE: a MEM-AP may have a single CoreSight component that's
* not a ROM table ... or have no such components at all.
*/
const unsigned int class = (apid & AP_REG_IDR_CLASS_MASK) >> AP_REG_IDR_CLASS_SHIFT;
if (class == AP_REG_IDR_CLASS_MEM_AP) {
if (is_64bit_ap(ap))
invalid_entry = 0xFFFFFFFFFFFFFFFFull;
else
invalid_entry = 0xFFFFFFFFul;
if (dbgbase != invalid_entry && (dbgbase & 0x3) != 0x2) {
retval = rtp_cs_component(ops, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, 0);
if (retval == CORESIGHT_COMPONENT_FOUND)
return CORESIGHT_COMPONENT_FOUND;
}
}
return ERROR_OK;
}
/* Actions for command "dap info" */
static int dap_info_mem_ap_header(int retval, struct adiv5_ap *ap,
target_addr_t dbgbase, uint32_t apid, void *priv)
{
struct command_invocation *cmd = priv;
target_addr_t invalid_entry;
if (retval != ERROR_OK) {
command_print(cmd, "\t\tCan't read MEM-AP, the corresponding core might be turned off");
return retval;
}
command_print(cmd, "AP ID register 0x%8.8" PRIx32, apid);
if (apid == 0) {
@ -1529,27 +1705,221 @@ int dap_info_command(struct command_invocation *cmd,
if (class == AP_REG_IDR_CLASS_MEM_AP) {
if (is_64bit_ap(ap))
dbgaddr = 0xFFFFFFFFFFFFFFFFull;
invalid_entry = 0xFFFFFFFFFFFFFFFFull;
else
dbgaddr = 0xFFFFFFFFul;
invalid_entry = 0xFFFFFFFFul;
command_print(cmd, "MEM-AP BASE " TARGET_ADDR_FMT, dbgbase);
if (dbgbase == dbgaddr || (dbgbase & 0x3) == 0x2) {
if (dbgbase == invalid_entry || (dbgbase & 0x3) == 0x2) {
command_print(cmd, "\tNo ROM table present");
} else {
if (dbgbase & 0x01)
command_print(cmd, "\tValid ROM table present");
else
command_print(cmd, "\tROM table in legacy format");
dap_rom_display(cmd, ap, dbgbase & 0xFFFFFFFFFFFFF000ull, 0);
}
}
return ERROR_OK;
}
static int dap_info_cs_component(int retval, struct cs_component_vals *v, int depth, void *priv)
{
struct command_invocation *cmd = priv;
if (depth > ROM_TABLE_MAX_DEPTH) {
command_print(cmd, "\tTables too deep");
return ERROR_FAIL;
}
command_print(cmd, "\t\tComponent base address " TARGET_ADDR_FMT, v->component_base);
if (retval != ERROR_OK) {
command_print(cmd, "\t\tCan't read component, the corresponding core might be turned off");
return retval;
}
if (!is_valid_arm_cs_cidr(v->cid)) {
command_print(cmd, "\t\tInvalid CID 0x%08" PRIx32, v->cid);
return ERROR_OK; /* Don't abort recursion */
}
/* component may take multiple 4K pages */
uint32_t size = ARM_CS_PIDR_SIZE(v->pid);
if (size > 0)
command_print(cmd, "\t\tStart address " TARGET_ADDR_FMT, v->component_base - 0x1000 * size);
command_print(cmd, "\t\tPeripheral ID 0x%010" PRIx64, v->pid);
const unsigned int part_num = ARM_CS_PIDR_PART(v->pid);
unsigned int designer_id = ARM_CS_PIDR_DESIGNER(v->pid);
if (v->pid & ARM_CS_PIDR_JEDEC) {
/* JEP106 code */
command_print(cmd, "\t\tDesigner is 0x%03x, %s",
designer_id, jep106_manufacturer(designer_id));
} else {
/* Legacy ASCII ID, clear invalid bits */
designer_id &= 0x7f;
command_print(cmd, "\t\tDesigner ASCII code 0x%02x, %s",
designer_id, designer_id == 0x41 ? "ARM" : "<unknown>");
}
const struct dap_part_nums *partnum = pidr_to_part_num(designer_id, part_num);
command_print(cmd, "\t\tPart is 0x%03x, %s %s", part_num, partnum->type, partnum->full);
const unsigned int class = ARM_CS_CIDR_CLASS(v->cid);
command_print(cmd, "\t\tComponent class is 0x%x, %s", class, class_description[class]);
if (class == ARM_CS_CLASS_0X1_ROM_TABLE) {
if (v->devtype_memtype & ARM_CS_C1_MEMTYPE_SYSMEM_MASK)
command_print(cmd, "\t\tMEMTYPE system memory present on bus");
else
command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
return ERROR_OK;
}
if (class == ARM_CS_CLASS_0X9_CS_COMPONENT) {
dap_devtype_display(cmd, v->devtype_memtype);
/* REVISIT also show ARM_CS_C9_DEVID */
if ((v->devarch & ARM_CS_C9_DEVARCH_PRESENT) == 0)
return ERROR_OK;
unsigned int architect_id = ARM_CS_C9_DEVARCH_ARCHITECT(v->devarch);
unsigned int revision = ARM_CS_C9_DEVARCH_REVISION(v->devarch);
command_print(cmd, "\t\tDev Arch is 0x%08" PRIx32 ", %s \"%s\" rev.%u", v->devarch,
jep106_manufacturer(architect_id), class0x9_devarch_description(v->devarch),
revision);
if ((v->devarch & DEVARCH_ID_MASK) == DEVARCH_ROM_C_0X9) {
command_print(cmd, "\t\tType is ROM table");
if (v->devid & ARM_CS_C9_DEVID_SYSMEM_MASK)
command_print(cmd, "\t\tMEMTYPE system memory present on bus");
else
command_print(cmd, "\t\tMEMTYPE system memory not present: dedicated debug bus");
}
return ERROR_OK;
}
/* Class other than 0x1 and 0x9 */
return ERROR_OK;
}
static int dap_info_rom_table_entry(int retval, int depth,
unsigned int offset, uint64_t romentry, void *priv)
{
struct command_invocation *cmd = priv;
char tabs[16] = "";
if (depth)
snprintf(tabs, sizeof(tabs), "[L%02d] ", depth);
if (retval != ERROR_OK) {
command_print(cmd, "\t%sROMTABLE[0x%x] Read error", tabs, offset);
command_print(cmd, "\t\tUnable to continue");
command_print(cmd, "\t%s\tStop parsing of ROM table", tabs);
return retval;
}
command_print(cmd, "\t%sROMTABLE[0x%x] = 0x%08" PRIx64,
tabs, offset, romentry);
if (romentry == 0) {
command_print(cmd, "\t%s\tEnd of ROM table", tabs);
return ERROR_OK;
}
if (!(romentry & ARM_CS_ROMENTRY_PRESENT)) {
command_print(cmd, "\t\tComponent not present");
return ERROR_OK;
}
return ERROR_OK;
}
int dap_info_command(struct command_invocation *cmd, struct adiv5_ap *ap)
{
struct rtp_ops dap_info_ops = {
.mem_ap_header = dap_info_mem_ap_header,
.cs_component = dap_info_cs_component,
.rom_table_entry = dap_info_rom_table_entry,
.priv = cmd,
};
return rtp_ap(&dap_info_ops, ap);
}
/* Actions for dap_lookup_cs_component() */
struct dap_lookup_data {
/* input */
unsigned int idx;
unsigned int type;
/* output */
uint64_t component_base;
};
static int dap_lookup_cs_component_cs_component(int retval,
struct cs_component_vals *v, int depth, void *priv)
{
struct dap_lookup_data *lookup = priv;
if (retval != ERROR_OK)
return retval;
if (!is_valid_arm_cs_cidr(v->cid))
return ERROR_OK;
const unsigned int class = ARM_CS_CIDR_CLASS(v->cid);
if (class != ARM_CS_CLASS_0X9_CS_COMPONENT)
return ERROR_OK;
if ((v->devtype_memtype & ARM_CS_C9_DEVTYPE_MASK) != lookup->type)
return ERROR_OK;
if (lookup->idx) {
/* search for next one */
--lookup->idx;
return ERROR_OK;
}
/* Found! */
lookup->component_base = v->component_base;
return CORESIGHT_COMPONENT_FOUND;
}
int dap_lookup_cs_component(struct adiv5_ap *ap, uint8_t type,
target_addr_t *addr, int32_t core_id)
{
struct dap_lookup_data lookup = {
.type = type,
.idx = core_id,
};
struct rtp_ops dap_lookup_cs_component_ops = {
.mem_ap_header = NULL,
.cs_component = dap_lookup_cs_component_cs_component,
.rom_table_entry = NULL,
.priv = &lookup,
};
int retval = rtp_ap(&dap_lookup_cs_component_ops, ap);
if (retval == CORESIGHT_COMPONENT_FOUND) {
LOG_DEBUG("CS lookup found at 0x%" PRIx64, lookup.component_base);
*addr = lookup.component_base;
return ERROR_OK;
}
if (retval != ERROR_OK) {
LOG_DEBUG("CS lookup error %d", retval);
return retval;
}
LOG_DEBUG("CS lookup not found");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
enum adiv5_cfg_param {
CFG_DAP,
CFG_AP_NUM,
@ -1568,6 +1938,8 @@ static const struct jim_nvp nvp_config_opts[] = {
static int adiv5_jim_spot_configure(struct jim_getopt_info *goi,
struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p)
{
assert(dap_p && ap_num_p);
if (!goi->argc)
return JIM_OK;
@ -1672,6 +2044,10 @@ int adiv5_jim_configure(struct target *target, struct jim_getopt_info *goi)
pc = (struct adiv5_private_config *)target->private_config;
if (!pc) {
pc = calloc(1, sizeof(struct adiv5_private_config));
if (!pc) {
LOG_ERROR("Out of memory");
return JIM_ERR;
}
pc->ap_num = DP_APSEL_INVALID;
target->private_config = pc;
}

View File

@ -619,10 +619,6 @@ int mem_ap_init(struct adiv5_ap *ap);
/* Invalidate cached DP select and cached TAR and CSW of all APs */
void dap_invalidate_cache(struct adiv5_dap *dap);
/* Probe the AP for ROM Table location */
int dap_get_debugbase(struct adiv5_ap *ap,
target_addr_t *dbgbase, uint32_t *apid);
/* Probe Access Ports to find a particular type */
int dap_find_ap(struct adiv5_dap *dap,
enum ap_type type_to_find,
@ -641,7 +637,7 @@ static inline bool dap_is_multidrop(struct adiv5_dap *dap)
/* Lookup CoreSight component */
int dap_lookup_cs_component(struct adiv5_ap *ap,
target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx);
uint8_t type, target_addr_t *addr, int32_t idx);
struct target;

View File

@ -44,13 +44,10 @@
#define ARM_CS_CIDR3 (0xFFC)
#define ARM_CS_CIDR_CLASS_MASK (0x0000F000)
#define ARM_CS_CIDR_CLASS_SHIFT (12)
#define ARM_CS_CIDR_CLASS(cidr) (((cidr) >> 12) & 0x000F)
#define ARM_CS_CLASS_0X1_ROM_TABLE (0x1)
#define ARM_CS_CLASS_0X9_CS_COMPONENT (0x9)
#define ARM_CS_CIDR1_CLASS_MASK (0x000000F0)
#define ARM_CS_CIDR1_CLASS_SHIFT (4)
static inline bool is_valid_arm_cs_cidr(uint32_t cidr)
{
return (cidr & ~ARM_CS_CIDR_CLASS_MASK) == 0xB105000D;
@ -66,6 +63,10 @@ static inline bool is_valid_arm_cs_cidr(uint32_t cidr)
#define ARM_CS_C9_DEVARCH_PRESENT BIT(20)
#define ARM_CS_C9_DEVARCH_ARCHITECT_MASK (0xFFE00000)
#define ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT (21)
#define ARM_CS_C9_DEVARCH_REVISION(devarch) \
(((devarch) & ARM_CS_C9_DEVARCH_REVISION_MASK) >> ARM_CS_C9_DEVARCH_REVISION_SHIFT)
#define ARM_CS_C9_DEVARCH_ARCHITECT(devarch) \
(((devarch) & ARM_CS_C9_DEVARCH_ARCHITECT_MASK) >> ARM_CS_C9_DEVARCH_ARCHITECT_SHIFT)
#define ARM_CS_C9_DEVID (0xFC8)

View File

@ -112,7 +112,7 @@ static int armv7a_read_midr(struct target *target)
armv7a->arch = (midr >> 16) & 0xf;
armv7a->variant = (midr >> 20) & 0xf;
armv7a->implementor = (midr >> 24) & 0xff;
LOG_INFO("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
LOG_DEBUG("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32
", variant %" PRIx32 ", implementor %" PRIx32,
target->cmd_name,
armv7a->rev,

View File

@ -2905,18 +2905,11 @@ static int cortex_a_examine_first(struct target *target)
armv7a->debug_ap->memaccess_tck = 80;
if (!target->dbgbase_set) {
target_addr_t dbgbase;
/* Get ROM Table base */
uint32_t apid;
int32_t coreidx = target->coreid;
LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table",
target->cmd_name);
retval = dap_get_debugbase(armv7a->debug_ap, &dbgbase, &apid);
if (retval != ERROR_OK)
return retval;
/* Lookup Processor DAP */
retval = dap_lookup_cs_component(armv7a->debug_ap, dbgbase, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&armv7a->debug_base, &coreidx);
retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&armv7a->debug_base, target->coreid);
if (retval != ERROR_OK) {
LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.",
target->cmd_name);

View File

@ -0,0 +1,6 @@
noinst_LTLIBRARIES += %D%/libespressif.la
%C%_libespressif_la_SOURCES = \
%D%/esp_xtensa.c \
%D%/esp_xtensa.h \
%D%/esp32s2.c \
%D%/esp32s2.h

View File

@ -0,0 +1,715 @@
/***************************************************************************
* ESP32-S2 target for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "assert.h"
#include <target/target.h>
#include <target/target_type.h>
#include "esp_xtensa.h"
#include "esp32s2.h"
/* Overall memory map
* TODO: read memory configuration from target registers */
#define ESP32_S2_IROM_MASK_LOW 0x40000000
#define ESP32_S2_IROM_MASK_HIGH 0x40020000
#define ESP32_S2_IRAM_LOW 0x40020000
#define ESP32_S2_IRAM_HIGH 0x40070000
#define ESP32_S2_DRAM_LOW 0x3ffb0000
#define ESP32_S2_DRAM_HIGH 0x40000000
#define ESP32_S2_RTC_IRAM_LOW 0x40070000
#define ESP32_S2_RTC_IRAM_HIGH 0x40072000
#define ESP32_S2_RTC_DRAM_LOW 0x3ff9e000
#define ESP32_S2_RTC_DRAM_HIGH 0x3ffa0000
#define ESP32_S2_RTC_DATA_LOW 0x50000000
#define ESP32_S2_RTC_DATA_HIGH 0x50002000
#define ESP32_S2_EXTRAM_DATA_LOW 0x3f500000
#define ESP32_S2_EXTRAM_DATA_HIGH 0x3ff80000
#define ESP32_S2_DR_REG_LOW 0x3f400000
#define ESP32_S2_DR_REG_HIGH 0x3f4d3FFC
#define ESP32_S2_SYS_RAM_LOW 0x60000000UL
#define ESP32_S2_SYS_RAM_HIGH (ESP32_S2_SYS_RAM_LOW + 0x20000000UL)
/* ESP32-S2 DROM mapping is not contiguous. */
/* IDF declares this as 0x3F000000..0x3FF80000, but there are peripheral registers mapped to
* 0x3f400000..0x3f4d3FFC. */
#define ESP32_S2_DROM0_LOW ESP32_S2_DROM_LOW
#define ESP32_S2_DROM0_HIGH ESP32_S2_DR_REG_LOW
#define ESP32_S2_DROM1_LOW ESP32_S2_DR_REG_HIGH
#define ESP32_S2_DROM1_HIGH ESP32_S2_DROM_HIGH
/* ESP32 WDT */
#define ESP32_S2_WDT_WKEY_VALUE 0x50d83aa1
#define ESP32_S2_TIMG0_BASE 0x3f41F000
#define ESP32_S2_TIMG1_BASE 0x3f420000
#define ESP32_S2_TIMGWDT_CFG0_OFF 0x48
#define ESP32_S2_TIMGWDT_PROTECT_OFF 0x64
#define ESP32_S2_TIMG0WDT_CFG0 (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
#define ESP32_S2_TIMG1WDT_CFG0 (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_CFG0_OFF)
#define ESP32_S2_TIMG0WDT_PROTECT (ESP32_S2_TIMG0_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
#define ESP32_S2_TIMG1WDT_PROTECT (ESP32_S2_TIMG1_BASE + ESP32_S2_TIMGWDT_PROTECT_OFF)
#define ESP32_S2_RTCCNTL_BASE 0x3f408000
#define ESP32_S2_RTCWDT_CFG_OFF 0x94
#define ESP32_S2_RTCWDT_PROTECT_OFF 0xAC
#define ESP32_S2_SWD_CONF_OFF 0xB0
#define ESP32_S2_SWD_WPROTECT_OFF 0xB4
#define ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF 0x8C
#define ESP32_S2_RTC_CNTL_DIG_PWC_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTC_CNTL_DIG_PWC_REG_OFF)
#define ESP32_S2_RTCWDT_CFG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_CFG_OFF)
#define ESP32_S2_RTCWDT_PROTECT (ESP32_S2_RTCCNTL_BASE + ESP32_S2_RTCWDT_PROTECT_OFF)
#define ESP32_S2_SWD_CONF_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_CONF_OFF)
#define ESP32_S2_SWD_WPROTECT_REG (ESP32_S2_RTCCNTL_BASE + ESP32_S2_SWD_WPROTECT_OFF)
#define ESP32_S2_SWD_AUTO_FEED_EN_M BIT(31)
#define ESP32_S2_SWD_WKEY_VALUE 0x8F1D312AU
#define ESP32_S2_OPTIONS0 (ESP32_S2_RTCCNTL_BASE + 0x0000)
#define ESP32_S2_SW_SYS_RST_M 0x80000000
#define ESP32_S2_SW_SYS_RST_V 0x1
#define ESP32_S2_SW_SYS_RST_S 31
#define ESP32_S2_SW_STALL_PROCPU_C0_M ((ESP32_S2_SW_STALL_PROCPU_C0_V) << (ESP32_S2_SW_STALL_PROCPU_C0_S))
#define ESP32_S2_SW_STALL_PROCPU_C0_V 0x3
#define ESP32_S2_SW_STALL_PROCPU_C0_S 2
#define ESP32_S2_SW_CPU_STALL (ESP32_S2_RTCCNTL_BASE + 0x00B8)
#define ESP32_S2_SW_STALL_PROCPU_C1_M ((ESP32_S2_SW_STALL_PROCPU_C1_V) << (ESP32_S2_SW_STALL_PROCPU_C1_S))
#define ESP32_S2_SW_STALL_PROCPU_C1_V 0x3FU
#define ESP32_S2_SW_STALL_PROCPU_C1_S 26
#define ESP32_S2_CLK_CONF (ESP32_S2_RTCCNTL_BASE + 0x0074)
#define ESP32_S2_CLK_CONF_DEF 0x1583218
#define ESP32_S2_STORE4 (ESP32_S2_RTCCNTL_BASE + 0x00BC)
#define ESP32_S2_STORE5 (ESP32_S2_RTCCNTL_BASE + 0x00C0)
#define ESP32_S2_DPORT_PMS_OCCUPY_3 0x3F4C10E0
#define ESP32_S2_TRACEMEM_BLOCK_SZ 0x4000
#define ESP32_S2_DR_REG_UART_BASE 0x3f400000
#define ESP32_S2_REG_UART_BASE(i) (ESP32_S2_DR_REG_UART_BASE + (i) * 0x10000)
#define ESP32_S2_UART_DATE_REG(i) (ESP32_S2_REG_UART_BASE(i) + 0x74)
/* this should map local reg IDs to GDB reg mapping as defined in xtensa-config.c 'rmap' in
* xtensa-overlay */
static const unsigned int esp32s2_gdb_regs_mapping[ESP32_S2_NUM_REGS] = {
XT_REG_IDX_PC,
XT_REG_IDX_AR0, XT_REG_IDX_AR1, XT_REG_IDX_AR2, XT_REG_IDX_AR3,
XT_REG_IDX_AR4, XT_REG_IDX_AR5, XT_REG_IDX_AR6, XT_REG_IDX_AR7,
XT_REG_IDX_AR8, XT_REG_IDX_AR9, XT_REG_IDX_AR10, XT_REG_IDX_AR11,
XT_REG_IDX_AR12, XT_REG_IDX_AR13, XT_REG_IDX_AR14, XT_REG_IDX_AR15,
XT_REG_IDX_AR16, XT_REG_IDX_AR17, XT_REG_IDX_AR18, XT_REG_IDX_AR19,
XT_REG_IDX_AR20, XT_REG_IDX_AR21, XT_REG_IDX_AR22, XT_REG_IDX_AR23,
XT_REG_IDX_AR24, XT_REG_IDX_AR25, XT_REG_IDX_AR26, XT_REG_IDX_AR27,
XT_REG_IDX_AR28, XT_REG_IDX_AR29, XT_REG_IDX_AR30, XT_REG_IDX_AR31,
XT_REG_IDX_AR32, XT_REG_IDX_AR33, XT_REG_IDX_AR34, XT_REG_IDX_AR35,
XT_REG_IDX_AR36, XT_REG_IDX_AR37, XT_REG_IDX_AR38, XT_REG_IDX_AR39,
XT_REG_IDX_AR40, XT_REG_IDX_AR41, XT_REG_IDX_AR42, XT_REG_IDX_AR43,
XT_REG_IDX_AR44, XT_REG_IDX_AR45, XT_REG_IDX_AR46, XT_REG_IDX_AR47,
XT_REG_IDX_AR48, XT_REG_IDX_AR49, XT_REG_IDX_AR50, XT_REG_IDX_AR51,
XT_REG_IDX_AR52, XT_REG_IDX_AR53, XT_REG_IDX_AR54, XT_REG_IDX_AR55,
XT_REG_IDX_AR56, XT_REG_IDX_AR57, XT_REG_IDX_AR58, XT_REG_IDX_AR59,
XT_REG_IDX_AR60, XT_REG_IDX_AR61, XT_REG_IDX_AR62, XT_REG_IDX_AR63,
XT_REG_IDX_SAR,
XT_REG_IDX_WINDOWBASE, XT_REG_IDX_WINDOWSTART, XT_REG_IDX_CONFIGID0, XT_REG_IDX_CONFIGID1,
XT_REG_IDX_PS, XT_REG_IDX_THREADPTR,
ESP32_S2_REG_IDX_GPIOOUT,
XT_REG_IDX_MMID, XT_REG_IDX_IBREAKENABLE, XT_REG_IDX_OCD_DDR,
XT_REG_IDX_IBREAKA0, XT_REG_IDX_IBREAKA1, XT_REG_IDX_DBREAKA0, XT_REG_IDX_DBREAKA1,
XT_REG_IDX_DBREAKC0, XT_REG_IDX_DBREAKC1,
XT_REG_IDX_EPC1, XT_REG_IDX_EPC2, XT_REG_IDX_EPC3, XT_REG_IDX_EPC4,
XT_REG_IDX_EPC5, XT_REG_IDX_EPC6, XT_REG_IDX_EPC7, XT_REG_IDX_DEPC,
XT_REG_IDX_EPS2, XT_REG_IDX_EPS3, XT_REG_IDX_EPS4, XT_REG_IDX_EPS5,
XT_REG_IDX_EPS6, XT_REG_IDX_EPS7,
XT_REG_IDX_EXCSAVE1, XT_REG_IDX_EXCSAVE2, XT_REG_IDX_EXCSAVE3, XT_REG_IDX_EXCSAVE4,
XT_REG_IDX_EXCSAVE5, XT_REG_IDX_EXCSAVE6, XT_REG_IDX_EXCSAVE7, XT_REG_IDX_CPENABLE,
XT_REG_IDX_INTERRUPT, XT_REG_IDX_INTSET, XT_REG_IDX_INTCLEAR, XT_REG_IDX_INTENABLE,
XT_REG_IDX_VECBASE, XT_REG_IDX_EXCCAUSE, XT_REG_IDX_DEBUGCAUSE, XT_REG_IDX_CCOUNT,
XT_REG_IDX_PRID, XT_REG_IDX_ICOUNT, XT_REG_IDX_ICOUNTLEVEL, XT_REG_IDX_EXCVADDR,
XT_REG_IDX_CCOMPARE0, XT_REG_IDX_CCOMPARE1, XT_REG_IDX_CCOMPARE2,
XT_REG_IDX_MISC0, XT_REG_IDX_MISC1, XT_REG_IDX_MISC2, XT_REG_IDX_MISC3,
XT_REG_IDX_A0, XT_REG_IDX_A1, XT_REG_IDX_A2, XT_REG_IDX_A3,
XT_REG_IDX_A4, XT_REG_IDX_A5, XT_REG_IDX_A6, XT_REG_IDX_A7,
XT_REG_IDX_A8, XT_REG_IDX_A9, XT_REG_IDX_A10, XT_REG_IDX_A11,
XT_REG_IDX_A12, XT_REG_IDX_A13, XT_REG_IDX_A14, XT_REG_IDX_A15,
XT_REG_IDX_PWRCTL, XT_REG_IDX_PWRSTAT, XT_REG_IDX_ERISTAT,
XT_REG_IDX_CS_ITCTRL, XT_REG_IDX_CS_CLAIMSET, XT_REG_IDX_CS_CLAIMCLR,
XT_REG_IDX_CS_LOCKACCESS, XT_REG_IDX_CS_LOCKSTATUS, XT_REG_IDX_CS_AUTHSTATUS,
XT_REG_IDX_FAULT_INFO,
XT_REG_IDX_TRAX_ID, XT_REG_IDX_TRAX_CTRL, XT_REG_IDX_TRAX_STAT,
XT_REG_IDX_TRAX_DATA, XT_REG_IDX_TRAX_ADDR, XT_REG_IDX_TRAX_PCTRIGGER,
XT_REG_IDX_TRAX_PCMATCH, XT_REG_IDX_TRAX_DELAY, XT_REG_IDX_TRAX_MEMSTART,
XT_REG_IDX_TRAX_MEMEND,
XT_REG_IDX_PMG, XT_REG_IDX_PMPC, XT_REG_IDX_PM0, XT_REG_IDX_PM1,
XT_REG_IDX_PMCTRL0, XT_REG_IDX_PMCTRL1, XT_REG_IDX_PMSTAT0, XT_REG_IDX_PMSTAT1,
XT_REG_IDX_OCD_ID, XT_REG_IDX_OCD_DCRCLR, XT_REG_IDX_OCD_DCRSET, XT_REG_IDX_OCD_DSR,
};
static const struct xtensa_user_reg_desc esp32s2_user_regs[ESP32_S2_NUM_REGS - XT_NUM_REGS] = {
{ "gpio_out", 0x00, 0, 32, &xtensa_user_reg_u32_type },
};
static const struct xtensa_config esp32s2_xtensa_cfg = {
.density = true,
.aregs_num = XT_AREGS_NUM_MAX,
.windowed = true,
.coproc = true,
.miscregs_num = 4,
.reloc_vec = true,
.proc_id = true,
.threadptr = true,
.user_regs_num = ARRAY_SIZE(esp32s2_user_regs),
.user_regs = esp32s2_user_regs,
.fetch_user_regs = xtensa_fetch_user_regs_u32,
.queue_write_dirty_user_regs = xtensa_queue_write_dirty_user_regs_u32,
.gdb_general_regs_num = ESP32_S2_NUM_REGS_G_COMMAND,
.gdb_regs_mapping = esp32s2_gdb_regs_mapping,
.irom = {
.count = 2,
.regions = {
{
.base = ESP32_S2_IROM_LOW,
.size = ESP32_S2_IROM_HIGH - ESP32_S2_IROM_LOW,
.access = XT_MEM_ACCESS_READ,
},
{
.base = ESP32_S2_IROM_MASK_LOW,
.size = ESP32_S2_IROM_MASK_HIGH - ESP32_S2_IROM_MASK_LOW,
.access = XT_MEM_ACCESS_READ,
},
}
},
.iram = {
.count = 2,
.regions = {
{
.base = ESP32_S2_IRAM_LOW,
.size = ESP32_S2_IRAM_HIGH - ESP32_S2_IRAM_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_RTC_IRAM_LOW,
.size = ESP32_S2_RTC_IRAM_HIGH - ESP32_S2_RTC_IRAM_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
}
},
.drom = {
.count = 2,
.regions = {
{
.base = ESP32_S2_DROM0_LOW,
.size = ESP32_S2_DROM0_HIGH - ESP32_S2_DROM0_LOW,
.access = XT_MEM_ACCESS_READ,
},
{
.base = ESP32_S2_DROM1_LOW,
.size = ESP32_S2_DROM1_HIGH - ESP32_S2_DROM1_LOW,
.access = XT_MEM_ACCESS_READ,
},
}
},
.dram = {
.count = 6,
.regions = {
{
.base = ESP32_S2_DRAM_LOW,
.size = ESP32_S2_DRAM_HIGH - ESP32_S2_DRAM_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_RTC_DRAM_LOW,
.size = ESP32_S2_RTC_DRAM_HIGH - ESP32_S2_RTC_DRAM_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_RTC_DATA_LOW,
.size = ESP32_S2_RTC_DATA_HIGH - ESP32_S2_RTC_DATA_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_EXTRAM_DATA_LOW,
.size = ESP32_S2_EXTRAM_DATA_HIGH - ESP32_S2_EXTRAM_DATA_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_DR_REG_LOW,
.size = ESP32_S2_DR_REG_HIGH - ESP32_S2_DR_REG_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
{
.base = ESP32_S2_SYS_RAM_LOW,
.size = ESP32_S2_SYS_RAM_HIGH - ESP32_S2_SYS_RAM_LOW,
.access = XT_MEM_ACCESS_READ | XT_MEM_ACCESS_WRITE,
},
}
},
.exc = {
.enabled = true,
},
.irq = {
.enabled = true,
.irq_num = 32,
},
.high_irq = {
.enabled = true,
.excm_level = 3,
.nmi_num = 1,
},
.tim_irq = {
.enabled = true,
.comp_num = 3,
},
.debug = {
.enabled = true,
.irq_level = 6,
.ibreaks_num = 2,
.dbreaks_num = 2,
.icount_sz = 32,
},
.trace = {
.enabled = true,
.mem_sz = ESP32_S2_TRACEMEM_BLOCK_SZ,
},
};
struct esp32s2_common {
struct esp_xtensa_common esp_xtensa;
};
static int esp32s2_soc_reset(struct target *target);
static int esp32s2_disable_wdts(struct target *target);
static int esp32s2_assert_reset(struct target *target)
{
return ERROR_OK;
}
static int esp32s2_deassert_reset(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
LOG_TARGET_DEBUG(target, "begin");
int res = xtensa_deassert_reset(target);
if (res != ERROR_OK)
return res;
/* restore configured value
esp32s2_soc_reset() modified it, but can not restore just after SW reset for some reason (???) */
res = xtensa_smpbreak_write(xtensa, xtensa->smp_break);
if (res != ERROR_OK) {
LOG_ERROR("Failed to restore smpbreak (%d)!", res);
return res;
}
return ERROR_OK;
}
int esp32s2_soft_reset_halt(struct target *target)
{
LOG_TARGET_DEBUG(target, "begin");
/* Reset the SoC first */
int res = esp32s2_soc_reset(target);
if (res != ERROR_OK)
return res;
return xtensa_assert_reset(target);
}
static int esp32s2_set_peri_reg_mask(struct target *target,
target_addr_t addr,
uint32_t mask,
uint32_t val)
{
uint32_t reg_val;
int res = target_read_u32(target, addr, &reg_val);
if (res != ERROR_OK)
return res;
reg_val = (reg_val & (~mask)) | val;
res = target_write_u32(target, addr, reg_val);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
static int esp32s2_stall_set(struct target *target, bool stall)
{
LOG_TARGET_DEBUG(target, "begin");
int res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_SW_CPU_STALL,
ESP32_S2_SW_STALL_PROCPU_C1_M,
stall ? 0x21U << ESP32_S2_SW_STALL_PROCPU_C1_S : 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SW_CPU_STALL (%d)!", res);
return res;
}
res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_OPTIONS0,
ESP32_S2_SW_STALL_PROCPU_C0_M,
stall ? 0x2 << ESP32_S2_SW_STALL_PROCPU_C0_S : 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
return res;
}
return ERROR_OK;
}
static inline int esp32s2_stall(struct target *target)
{
return esp32s2_stall_set(target, true);
}
static inline int esp32s2_unstall(struct target *target)
{
return esp32s2_stall_set(target, false);
}
/* Reset ESP32-S2's peripherals.
Postconditions: all peripherals except RTC_CNTL are reset, CPU's PC is undefined, PRO CPU is halted, APP CPU is in reset
How this works:
0. make sure target is halted; if not, try to halt it; if that fails, try to reset it (via OCD) and then halt
1. Resets clock related registers
2. Stalls CPU
3. trigger SoC reset using RTC_CNTL_SW_SYS_RST bit
4. CPU is reset and stalled at the first reset vector instruction
5. wait for the OCD to be reset
6. halt the target
7. Unstalls CPU
8. Disables WDTs and trace memory mapping
*/
static int esp32s2_soc_reset(struct target *target)
{
int res;
struct xtensa *xtensa = target_to_xtensa(target);
LOG_DEBUG("start");
/* In order to write to peripheral registers, target must be halted first */
if (target->state != TARGET_HALTED) {
LOG_TARGET_DEBUG(target, "Target not halted before SoC reset, trying to halt it first");
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_DEBUG(target, "Couldn't halt target before SoC reset, trying to do reset-halt");
res = xtensa_assert_reset(target);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(
target,
"Couldn't halt target before SoC reset! (xtensa_assert_reset returned %d)",
res);
return res;
}
alive_sleep(10);
xtensa_poll(target);
int reset_halt_save = target->reset_halt;
target->reset_halt = 1;
res = xtensa_deassert_reset(target);
target->reset_halt = reset_halt_save;
if (res != ERROR_OK) {
LOG_TARGET_ERROR(
target,
"Couldn't halt target before SoC reset! (xtensa_deassert_reset returned %d)",
res);
return res;
}
alive_sleep(10);
xtensa_poll(target);
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
return res;
}
}
}
assert(target->state == TARGET_HALTED);
/* Set some clock-related RTC registers to the default values */
res = target_write_u32(target, ESP32_S2_STORE4, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_STORE4 (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_STORE5, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_STORE5 (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_RTC_CNTL_DIG_PWC_REG, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTC_CNTL_DIG_PWC_REG (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_CLK_CONF, ESP32_S2_CLK_CONF_DEF);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_CLK_CONF (%d)!", res);
return res;
}
/* Stall CPU */
res = esp32s2_stall(target);
if (res != ERROR_OK)
return res;
/* enable stall */
res = xtensa_smpbreak_write(xtensa, OCDDCR_RUNSTALLINEN);
if (res != ERROR_OK) {
LOG_ERROR("Failed to set smpbreak (%d)!", res);
return res;
}
/* Reset CPU */
xtensa->suppress_dsr_errors = true;
res = esp32s2_set_peri_reg_mask(target,
ESP32_S2_OPTIONS0,
ESP32_S2_SW_SYS_RST_M,
1U << ESP32_S2_SW_SYS_RST_S);
xtensa->suppress_dsr_errors = false;
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_OPTIONS0 (%d)!", res);
return res;
}
/* Wait for SoC to reset */
alive_sleep(100);
int timeout = 100;
while (target->state != TARGET_RESET && target->state != TARGET_RUNNING && --timeout > 0) {
alive_sleep(10);
xtensa_poll(target);
}
if (timeout == 0) {
LOG_ERROR("Timed out waiting for CPU to be reset, target->state=%d", target->state);
return ERROR_TARGET_TIMEOUT;
}
xtensa_halt(target);
res = target_wait_state(target, TARGET_HALTED, 1000);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Couldn't halt target before SoC reset");
return res;
}
/* Unstall CPU */
res = esp32s2_unstall(target);
if (res != ERROR_OK)
return res;
/* Disable WDTs */
res = esp32s2_disable_wdts(target);
if (res != ERROR_OK)
return res;
/* Disable trace memory mapping */
res = target_write_u32(target, ESP32_S2_DPORT_PMS_OCCUPY_3, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_DPORT_PMS_OCCUPY_3 (%d)!", res);
return res;
}
return ERROR_OK;
}
static int esp32s2_disable_wdts(struct target *target)
{
/* TIMG1 WDT */
int res = target_write_u32(target, ESP32_S2_TIMG0WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_TIMG0WDT_CFG0, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG0WDT_CFG0 (%d)!", res);
return res;
}
/* TIMG2 WDT */
res = target_write_u32(target, ESP32_S2_TIMG1WDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_TIMG1WDT_CFG0, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_TIMG1WDT_CFG0 (%d)!", res);
return res;
}
/* RTC WDT */
res = target_write_u32(target, ESP32_S2_RTCWDT_PROTECT, ESP32_S2_WDT_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTCWDT_PROTECT (%d)!", res);
return res;
}
res = target_write_u32(target, ESP32_S2_RTCWDT_CFG, 0);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_RTCWDT_CFG (%d)!", res);
return res;
}
/* Enable SWD auto-feed */
res = target_write_u32(target, ESP32_S2_SWD_WPROTECT_REG, ESP32_S2_SWD_WKEY_VALUE);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SWD_WPROTECT_REG (%d)!", res);
return res;
}
uint32_t swd_conf_reg = 0;
res = target_read_u32(target, ESP32_S2_SWD_CONF_REG, &swd_conf_reg);
if (res != ERROR_OK) {
LOG_ERROR("Failed to read ESP32_S2_SWD_CONF_REG (%d)!", res);
return res;
}
swd_conf_reg |= ESP32_S2_SWD_AUTO_FEED_EN_M;
res = target_write_u32(target, ESP32_S2_SWD_CONF_REG, swd_conf_reg);
if (res != ERROR_OK) {
LOG_ERROR("Failed to write ESP32_S2_SWD_CONF_REG (%d)!", res);
return res;
}
return ERROR_OK;
}
static int esp32s2_arch_state(struct target *target)
{
return ERROR_OK;
}
static int esp32s2_on_halt(struct target *target)
{
return esp32s2_disable_wdts(target);
}
static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints)
{
int ret = xtensa_step(target, current, address, handle_breakpoints);
if (ret == ERROR_OK) {
esp32s2_on_halt(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
return ret;
}
static int esp32s2_poll(struct target *target)
{
enum target_state old_state = target->state;
int ret = esp_xtensa_poll(target);
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
/* Call any event callbacks that are applicable */
if (old_state == TARGET_DEBUG_RUNNING) {
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
} else {
esp32s2_on_halt(target);
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
}
}
return ret;
}
static int esp32s2_virt2phys(struct target *target,
target_addr_t virtual, target_addr_t *physical)
{
*physical = virtual;
return ERROR_OK;
}
static int esp32s2_target_init(struct command_context *cmd_ctx, struct target *target)
{
return esp_xtensa_target_init(cmd_ctx, target);
}
static const struct xtensa_debug_ops esp32s2_dbg_ops = {
.queue_enable = xtensa_dm_queue_enable,
.queue_reg_read = xtensa_dm_queue_reg_read,
.queue_reg_write = xtensa_dm_queue_reg_write
};
static const struct xtensa_power_ops esp32s2_pwr_ops = {
.queue_reg_read = xtensa_dm_queue_pwr_reg_read,
.queue_reg_write = xtensa_dm_queue_pwr_reg_write
};
static int esp32s2_target_create(struct target *target, Jim_Interp *interp)
{
struct xtensa_debug_module_config esp32s2_dm_cfg = {
.dbg_ops = &esp32s2_dbg_ops,
.pwr_ops = &esp32s2_pwr_ops,
.tap = target->tap,
.queue_tdi_idle = NULL,
.queue_tdi_idle_arg = NULL
};
/* creates xtensa object */
struct esp32s2_common *esp32 = calloc(1, sizeof(*esp32));
if (!esp32) {
LOG_ERROR("Failed to alloc memory for arch info!");
return ERROR_FAIL;
}
int ret = esp_xtensa_init_arch_info(target, &esp32->esp_xtensa, &esp32s2_xtensa_cfg, &esp32s2_dm_cfg);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to init arch info!");
free(esp32);
return ret;
}
/* Assume running target. If different, the first poll will fix this */
target->state = TARGET_RUNNING;
target->debug_reason = DBG_REASON_NOTHALTED;
return ERROR_OK;
}
static const struct command_registration esp32s2_command_handlers[] = {
{
.name = "xtensa",
.mode = COMMAND_ANY,
.help = "Xtensa commands group",
.usage = "",
.chain = xtensa_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/* Holds methods for Xtensa targets. */
struct target_type esp32s2_target = {
.name = "esp32s2",
.poll = esp32s2_poll,
.arch_state = esp32s2_arch_state,
.halt = xtensa_halt,
.resume = xtensa_resume,
.step = esp32s2_step,
.assert_reset = esp32s2_assert_reset,
.deassert_reset = esp32s2_deassert_reset,
.soft_reset_halt = esp32s2_soft_reset_halt,
.virt2phys = esp32s2_virt2phys,
.mmu = xtensa_mmu_is_enabled,
.read_memory = xtensa_read_memory,
.write_memory = xtensa_write_memory,
.read_buffer = xtensa_read_buffer,
.write_buffer = xtensa_write_buffer,
.checksum_memory = xtensa_checksum_memory,
.get_gdb_arch = xtensa_get_gdb_arch,
.get_gdb_reg_list = xtensa_get_gdb_reg_list,
.add_breakpoint = esp_xtensa_breakpoint_add,
.remove_breakpoint = esp_xtensa_breakpoint_remove,
.add_watchpoint = xtensa_watchpoint_add,
.remove_watchpoint = xtensa_watchpoint_remove,
.target_create = esp32s2_target_create,
.init_target = esp32s2_target_init,
.examine = xtensa_examine,
.deinit_target = esp_xtensa_target_deinit,
.commands = esp32s2_command_handlers,
};

View File

@ -0,0 +1,40 @@
/***************************************************************************
* ESP32-S2 target for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_ESP32S2_H
#define OPENOCD_TARGET_ESP32S2_H
#include <target/xtensa/xtensa_regs.h>
#define ESP32_S2_DROM_LOW 0x3f000000
#define ESP32_S2_DROM_HIGH 0x3ff80000
#define ESP32_S2_IROM_LOW 0x40080000
#define ESP32_S2_IROM_HIGH 0x40800000
/* Number of registers returned directly by the G command
* Corresponds to the amount of regs listed in regformats/reg-xtensa.dat in the gdb source */
#define ESP32_S2_NUM_REGS_G_COMMAND 72
enum esp32s2_reg_id {
/* chip specific registers that extend ISA go after ISA-defined ones */
ESP32_S2_REG_IDX_GPIOOUT = XT_USR_REG_START,
ESP32_S2_NUM_REGS,
};
#endif /* OPENOCD_TARGET_ESP32S2_H */

View File

@ -0,0 +1,71 @@
/***************************************************************************
* Espressif Xtensa target API for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdbool.h>
#include <stdint.h>
#include <target/smp.h>
#include "esp_xtensa.h"
#include <target/register.h>
int esp_xtensa_init_arch_info(struct target *target,
struct esp_xtensa_common *esp_xtensa,
const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg)
{
return xtensa_init_arch_info(target, &esp_xtensa->xtensa, xtensa_cfg, dm_cfg);
}
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target)
{
return xtensa_target_init(cmd_ctx, target);
}
void esp_xtensa_target_deinit(struct target *target)
{
LOG_DEBUG("start");
xtensa_target_deinit(target);
free(target_to_esp_xtensa(target)); /* same as free(xtensa) */
}
int esp_xtensa_arch_state(struct target *target)
{
return ERROR_OK;
}
int esp_xtensa_poll(struct target *target)
{
return xtensa_poll(target);
}
int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint)
{
return xtensa_breakpoint_add(target, breakpoint);
/* flash breakpoints will be handled in another patch */
}
int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint)
{
return xtensa_breakpoint_remove(target, breakpoint);
/* flash breakpoints will be handled in another patch */
}

View File

@ -0,0 +1,48 @@
/***************************************************************************
* Generic ESP xtensa target implementation for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_ESP_XTENSA_H
#define OPENOCD_TARGET_ESP_XTENSA_H
#include <helper/command.h>
#include <target/target.h>
#include <target/xtensa/xtensa.h>
struct esp_xtensa_common {
struct xtensa xtensa; /* must be the first element */
};
static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target)
{
return container_of(target->arch_info, struct esp_xtensa_common, xtensa);
}
int esp_xtensa_init_arch_info(struct target *target,
struct esp_xtensa_common *esp_xtensa,
const struct xtensa_config *xtensa_cfg,
struct xtensa_debug_module_config *dm_cfg);
int esp_xtensa_target_init(struct command_context *cmd_ctx, struct target *target);
void esp_xtensa_target_deinit(struct target *target);
int esp_xtensa_arch_state(struct target *target);
void esp_xtensa_queue_tdi_idle(struct target *target);
int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint);
int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint);
int esp_xtensa_poll(struct target *target);
#endif /* OPENOCD_TARGET_ESP_XTENSA_H */

View File

@ -2468,10 +2468,11 @@ static int deassert_reset(struct target *target)
select_dmi(target);
/* Clear the reset, but make sure haltreq is still set */
uint32_t control = 0;
control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
uint32_t control = 0, control_haltreq;
control = set_field(control, DM_DMCONTROL_DMACTIVE, 1);
dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index));
control_haltreq = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
dmi_write(target, DM_DMCONTROL,
set_dmcontrol_hartsel(control_haltreq, info->index));
uint32_t dmstatus;
int dmi_busy_delay = info->dmi_busy_delay;
@ -2483,7 +2484,7 @@ static int deassert_reset(struct target *target)
if (index != info->index)
continue;
dmi_write(target, DM_DMCONTROL,
set_dmcontrol_hartsel(control, index));
set_dmcontrol_hartsel(control_haltreq, index));
} else {
index = info->index;
}
@ -2525,7 +2526,7 @@ static int deassert_reset(struct target *target)
}
if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) {
/* Ack reset. */
/* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */
dmi_write(target, DM_DMCONTROL,
set_dmcontrol_hartsel(control, index) |
DM_DMCONTROL_ACKHAVERESET);

View File

@ -159,6 +159,7 @@ int semihosting_common_init(struct target *target, void *setup,
semihosting->result = -1;
semihosting->sys_errno = -1;
semihosting->cmdline = NULL;
semihosting->basedir = NULL;
/* If possible, update it in setup(). */
semihosting->setup_time = clock();
@ -870,17 +871,21 @@ int semihosting_common(struct target *target)
semihosting->sys_errno = EINVAL;
break;
}
uint8_t *fn = malloc(len+1);
size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0;
uint8_t *fn = malloc(basedir_len + len + 2);
if (!fn) {
semihosting->result = -1;
semihosting->sys_errno = ENOMEM;
} else {
retval = target_read_memory(target, addr, 1, len, fn);
strncpy((char *)fn, semihosting->basedir, basedir_len);
if (fn[basedir_len - 1] != '/')
fn[basedir_len++] = '/';
retval = target_read_memory(target, addr, 1, len, fn + basedir_len);
if (retval != ERROR_OK) {
free(fn);
return retval;
}
fn[len] = 0;
fn[basedir_len + len] = 0;
/* TODO: implement the :semihosting-features special file.
* */
if (semihosting->is_fileio) {
@ -2025,6 +2030,44 @@ COMMAND_HANDLER(handle_common_semihosting_read_user_param_command)
return ERROR_OK;
}
COMMAND_HANDLER(handle_common_semihosting_basedir_command)
{
struct target *target = get_current_target(CMD_CTX);
if (CMD_ARGC > 1)
return ERROR_COMMAND_SYNTAX_ERROR;
if (!target) {
LOG_ERROR("No target selected");
return ERROR_FAIL;
}
struct semihosting *semihosting = target->semihosting;
if (!semihosting) {
command_print(CMD, "semihosting not supported for current target");
return ERROR_FAIL;
}
if (!semihosting->is_active) {
command_print(CMD, "semihosting not yet enabled for current target");
return ERROR_FAIL;
}
if (CMD_ARGC > 0) {
free(semihosting->basedir);
semihosting->basedir = strdup(CMD_ARGV[0]);
if (!semihosting->basedir) {
command_print(CMD, "semihosting failed to allocate memory for basedir!");
return ERROR_FAIL;
}
}
command_print(CMD, "semihosting base dir: %s",
semihosting->basedir ? semihosting->basedir : "");
return ERROR_OK;
}
const struct command_registration semihosting_common_handlers[] = {
{
.name = "semihosting",
@ -2068,5 +2111,12 @@ const struct command_registration semihosting_common_handlers[] = {
.usage = "",
.help = "read parameters in semihosting-user-cmd-0x10X callbacks",
},
{
.name = "semihosting_basedir",
.handler = handle_common_semihosting_basedir_command,
.mode = COMMAND_EXEC,
.usage = "[dir]",
.help = "set the base directory for semihosting I/O operations",
},
COMMAND_REGISTRATION_DONE
};

View File

@ -176,6 +176,9 @@ struct semihosting {
/** The current time when 'execution starts' */
clock_t setup_time;
/** Base directory for semihosting I/O operations. */
char *basedir;
int (*setup)(struct target *target, int enable);
int (*post_result)(struct target *target);
};

View File

@ -28,6 +28,7 @@
#include "smp.h"
#include "helper/binarybuffer.h"
/* DEPRECATED: gdb_read_smp_packet/gdb_write_smp_packet to be removed */
/* implementation of new packet in gdb interface for smp feature */
/* */
/* j : smp status request */
@ -53,11 +54,15 @@
/* maint packet jc */
/* packet j :smp status request */
#define DEPRECATED_MSG "DEPRECATED: This method is deprecated in favor of the hwthread pseudo RTOS"
int gdb_read_smp_packet(struct connection *connection,
char const *packet, int packet_size)
{
struct target *target = get_target_from_connection(connection);
int retval = ERROR_OK;
LOG_WARNING(DEPRECATED_MSG);
if (target->smp) {
if (strncmp(packet, "jc", 2) == 0) {
const uint32_t len = sizeof(target->gdb_service->core[0]);
@ -83,6 +88,8 @@ int gdb_write_smp_packet(struct connection *connection,
int coreid = 0;
int retval = ERROR_OK;
LOG_WARNING(DEPRECATED_MSG);
/* skip command character */
if (target->smp) {
if (strncmp(packet, "Jc", 2) == 0) {

View File

@ -30,8 +30,10 @@
extern const struct command_registration smp_command_handlers[];
/* DEPRECATED */
int gdb_read_smp_packet(struct connection *connection,
char const *packet, int packet_size);
/* DEPRECATED */
int gdb_write_smp_packet(struct connection *connection,
char const *packet, int packet_size);

View File

@ -57,6 +57,7 @@
#include "transport/transport.h"
#include "arm_cti.h"
#include "smp.h"
#include "semihosting_common.h"
/* default halt wait timeout (ms) */
#define DEFAULT_HALT_TIMEOUT 5000
@ -104,6 +105,7 @@ 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 esp32s2_target;
extern struct target_type or1k_target;
extern struct target_type quark_x10xx_target;
extern struct target_type quark_d20xx_target;
@ -140,6 +142,7 @@ static struct target_type *target_types[] = {
&nds32_v2_target,
&nds32_v3_target,
&nds32_v3m_target,
&esp32s2_target,
&or1k_target,
&quark_x10xx_target,
&quark_d20xx_target,
@ -2268,6 +2271,8 @@ static void target_destroy(struct target *target)
if (target->type->deinit_target)
target->type->deinit_target(target);
if (target->semihosting)
free(target->semihosting->basedir);
free(target->semihosting);
jtag_unregister_event_callback(jtag_enable_callback, target);
@ -2597,7 +2602,7 @@ int target_blank_check_memory(struct target *target,
}
if (!target->type->blank_check_memory)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
return ERROR_NOT_IMPLEMENTED;
return target->type->blank_check_memory(target, blocks, num_blocks, erased_value);
}
@ -5224,10 +5229,18 @@ static int target_jim_set_reg(Jim_Interp *interp, int argc,
}
int tmp;
#if JIM_VERSION >= 80
Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp);
if (!dict)
return JIM_ERR;
#else
Jim_Obj **dict;
int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp);
if (ret != JIM_OK)
return ret;
#endif
const unsigned int length = tmp;
struct command_context *cmd_ctx = current_command_context(interp);
@ -6473,7 +6486,7 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
smp_group++;
if (target && target->rtos)
retval = rtos_smp_init(head->target);
retval = rtos_smp_init(target);
return retval;
}

View File

@ -206,7 +206,7 @@ struct target {
* poll too quickly because we'll just overwhelm the user with error
* messages. */
struct backoff_timer backoff;
int smp; /* add some target attributes for smp support */
int smp; /* Unique non-zero number for each SMP group */
struct list_head *smp_targets; /* list all targets in this smp group/cluster
* The head of the list is shared between the
* cluster, thus here there is a pointer */

View File

@ -242,6 +242,17 @@ struct target_type {
/**
* Free all the resources allocated by the target.
*
* WARNING: deinit_target is called unconditionally regardless the target has
* ever been examined/initialised or not.
* If a problem has prevented establishing JTAG/SWD/... communication
* or
* if the target was created with -defer-examine flag and has never been
* examined
* then it is not possible to communicate with the target.
*
* If you need to talk to the target during deinit, first check if
* target_was_examined()!
*
* @param target The target to deinit
*/
void (*deinit_target)(struct target *target);

View File

@ -0,0 +1,7 @@
noinst_LTLIBRARIES += %D%/libxtensa.la
%C%_libxtensa_la_SOURCES = \
%D%/xtensa.c \
%D%/xtensa.h \
%D%/xtensa_debug_module.c \
%D%/xtensa_debug_module.h \
%D%/xtensa_regs.h

2731
src/target/xtensa/xtensa.c Normal file

File diff suppressed because it is too large Load Diff

309
src/target/xtensa/xtensa.h Normal file
View File

@ -0,0 +1,309 @@
/***************************************************************************
* Generic Xtensa target *
* Copyright (C) 2019 Espressif Systems Ltd. *
* Author: Alexey Gerenkov <alexey@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_H
#define OPENOCD_TARGET_XTENSA_H
#include "assert.h"
#include <target/target.h>
#include <target/breakpoints.h>
#include "xtensa_regs.h"
#include "xtensa_debug_module.h"
/**
* @file
* Holds the interface to Xtensa cores.
*/
#define XT_ISNS_SZ_MAX 3
#define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6)
#define XT_PS_RING_MSK (0x3 << 6)
#define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3)
#define XT_PS_CALLINC_MSK (0x3 << 16)
#define XT_PS_OWB_MSK (0xF << 8)
#define XT_LOCAL_MEM_REGIONS_NUM_MAX 8
#define XT_AREGS_NUM_MAX 64
#define XT_USER_REGS_NUM_MAX 256
#define XT_MEM_ACCESS_NONE 0x0
#define XT_MEM_ACCESS_READ 0x1
#define XT_MEM_ACCESS_WRITE 0x2
enum xtensa_mem_err_detect {
XT_MEM_ERR_DETECT_NONE,
XT_MEM_ERR_DETECT_PARITY,
XT_MEM_ERR_DETECT_ECC,
};
struct xtensa_cache_config {
uint8_t way_count;
uint8_t line_size;
uint16_t size;
bool writeback;
enum xtensa_mem_err_detect mem_err_check;
};
struct xtensa_local_mem_region_config {
target_addr_t base;
uint32_t size;
enum xtensa_mem_err_detect mem_err_check;
int access;
};
struct xtensa_local_mem_config {
uint16_t count;
struct xtensa_local_mem_region_config regions[XT_LOCAL_MEM_REGIONS_NUM_MAX];
};
struct xtensa_mmu_config {
bool enabled;
uint8_t itlb_entries_count;
uint8_t dtlb_entries_count;
bool ivarway56;
bool dvarway56;
};
struct xtensa_exception_config {
bool enabled;
uint8_t depc_num;
};
struct xtensa_irq_config {
bool enabled;
uint8_t irq_num;
};
struct xtensa_high_prio_irq_config {
bool enabled;
uint8_t excm_level;
uint8_t nmi_num;
};
struct xtensa_debug_config {
bool enabled;
uint8_t irq_level;
uint8_t ibreaks_num;
uint8_t dbreaks_num;
uint8_t icount_sz;
};
struct xtensa_tracing_config {
bool enabled;
uint32_t mem_sz;
bool reversed_mem_access;
};
struct xtensa_timer_irq_config {
bool enabled;
uint8_t comp_num;
};
struct xtensa_config {
bool density;
uint8_t aregs_num;
bool windowed;
bool coproc;
bool fp_coproc;
bool loop;
uint8_t miscregs_num;
bool threadptr;
bool boolean;
bool cond_store;
bool ext_l32r;
bool mac16;
bool reloc_vec;
bool proc_id;
bool mem_err_check;
uint16_t user_regs_num;
const struct xtensa_user_reg_desc *user_regs;
int (*fetch_user_regs)(struct target *target);
int (*queue_write_dirty_user_regs)(struct target *target);
struct xtensa_cache_config icache;
struct xtensa_cache_config dcache;
struct xtensa_local_mem_config irom;
struct xtensa_local_mem_config iram;
struct xtensa_local_mem_config drom;
struct xtensa_local_mem_config dram;
struct xtensa_local_mem_config uram;
struct xtensa_local_mem_config xlmi;
struct xtensa_mmu_config mmu;
struct xtensa_exception_config exc;
struct xtensa_irq_config irq;
struct xtensa_high_prio_irq_config high_irq;
struct xtensa_timer_irq_config tim_irq;
struct xtensa_debug_config debug;
struct xtensa_tracing_config trace;
unsigned int gdb_general_regs_num;
const unsigned int *gdb_regs_mapping;
};
typedef uint32_t xtensa_insn_t;
enum xtensa_stepping_isr_mode {
XT_STEPPING_ISR_OFF, /* interrupts are disabled during stepping */
XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */
};
/* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */
enum xtensa_mode {
XT_MODE_RING0,
XT_MODE_RING1,
XT_MODE_RING2,
XT_MODE_RING3,
XT_MODE_ANY /* special value to run algorithm in current core mode */
};
struct xtensa_sw_breakpoint {
struct breakpoint *oocd_bp;
/* original insn */
uint8_t insn[XT_ISNS_SZ_MAX];
/* original insn size */
uint8_t insn_sz; /* 2 or 3 bytes */
};
#define XTENSA_COMMON_MAGIC 0x54E4E555U
/**
* Represents a generic Xtensa core.
*/
struct xtensa {
unsigned int common_magic;
const struct xtensa_config *core_config;
struct xtensa_debug_module dbg_mod;
struct reg_cache *core_cache;
unsigned int regs_num;
/* An array of pointers to buffers to backup registers' values while algo is run on target.
* Size is 'regs_num'. */
void **algo_context_backup;
struct target *target;
bool reset_asserted;
enum xtensa_stepping_isr_mode stepping_isr_mode;
struct breakpoint **hw_brps;
struct watchpoint **hw_wps;
struct xtensa_sw_breakpoint *sw_brps;
bool trace_active;
bool permissive_mode; /* bypass memory checks */
bool suppress_dsr_errors;
uint32_t smp_break;
/* Sometimes debug module's 'powered' bit is cleared after reset, but get set after some
* time.This is the number of polling periods after which core is considered to be powered
* off (marked as unexamined) if the bit retains to be cleared (e.g. if core is disabled by
* SW running on target).*/
uint8_t come_online_probes_num;
bool regs_fetched; /* true after first register fetch completed successfully */
};
static inline struct xtensa *target_to_xtensa(struct target *target)
{
assert(target);
struct xtensa *xtensa = target->arch_info;
assert(xtensa->common_magic == XTENSA_COMMON_MAGIC);
return xtensa;
}
int xtensa_init_arch_info(struct target *target,
struct xtensa *xtensa,
const struct xtensa_config *cfg,
const struct xtensa_debug_module_config *dm_cfg);
int xtensa_target_init(struct command_context *cmd_ctx, struct target *target);
void xtensa_target_deinit(struct target *target);
static inline bool xtensa_addr_in_mem(const struct xtensa_local_mem_config *mem, uint32_t addr)
{
for (unsigned int i = 0; i < mem->count; i++) {
if (addr >= mem->regions[i].base &&
addr < mem->regions[i].base + mem->regions[i].size)
return true;
}
return false;
}
static inline bool xtensa_data_addr_valid(struct target *target, uint32_t addr)
{
struct xtensa *xtensa = target_to_xtensa(target);
if (xtensa_addr_in_mem(&xtensa->core_config->drom, addr))
return true;
if (xtensa_addr_in_mem(&xtensa->core_config->dram, addr))
return true;
if (xtensa_addr_in_mem(&xtensa->core_config->uram, addr))
return true;
return false;
}
int xtensa_core_status_check(struct target *target);
int xtensa_examine(struct target *target);
int xtensa_wakeup(struct target *target);
int xtensa_smpbreak_set(struct target *target, uint32_t set);
int xtensa_smpbreak_get(struct target *target, uint32_t *val);
int xtensa_smpbreak_write(struct xtensa *xtensa, uint32_t set);
int xtensa_smpbreak_read(struct xtensa *xtensa, uint32_t *val);
xtensa_reg_val_t xtensa_reg_get(struct target *target, enum xtensa_reg_id reg_id);
void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg_val_t value);
int xtensa_fetch_all_regs(struct target *target);
int xtensa_get_gdb_reg_list(struct target *target,
struct reg **reg_list[],
int *reg_list_size,
enum target_register_class reg_class);
int xtensa_poll(struct target *target);
void xtensa_on_poll(struct target *target);
int xtensa_halt(struct target *target);
int xtensa_resume(struct target *target,
int current,
target_addr_t address,
int handle_breakpoints,
int debug_execution);
int xtensa_prepare_resume(struct target *target,
int current,
target_addr_t address,
int handle_breakpoints,
int debug_execution);
int xtensa_do_resume(struct target *target);
int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints);
int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints);
int xtensa_mmu_is_enabled(struct target *target, int *enabled);
int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer);
int xtensa_write_memory(struct target *target,
target_addr_t address,
uint32_t size,
uint32_t count,
const uint8_t *buffer);
int xtensa_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer);
int xtensa_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum);
int xtensa_assert_reset(struct target *target);
int xtensa_deassert_reset(struct target *target);
int xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint);
int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint);
int xtensa_watchpoint_add(struct target *target, struct watchpoint *watchpoint);
int xtensa_watchpoint_remove(struct target *target, struct watchpoint *watchpoint);
void xtensa_set_permissive_mode(struct target *target, bool state);
int xtensa_fetch_user_regs_u32(struct target *target);
int xtensa_queue_write_dirty_user_regs_u32(struct target *target);
const char *xtensa_get_gdb_arch(struct target *target);
extern const struct reg_arch_type xtensa_user_reg_u32_type;
extern const struct reg_arch_type xtensa_user_reg_u128_type;
extern const struct command_registration xtensa_command_handlers[];
#endif /* OPENOCD_TARGET_XTENSA_H */

View File

@ -0,0 +1,359 @@
/***************************************************************************
* Generic Xtensa debug module API for OpenOCD *
* Copyright (C) 2019 Espressif Systems Ltd. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "xtensa_debug_module.h"
#define TAPINS_PWRCTL 0x08
#define TAPINS_PWRSTAT 0x09
#define TAPINS_NARSEL 0x1C
#define TAPINS_IDCODE 0x1E
#define TAPINS_BYPASS 0x1F
#define TAPINS_PWRCTL_LEN 8
#define TAPINS_PWRSTAT_LEN 8
#define TAPINS_NARSEL_ADRLEN 8
#define TAPINS_NARSEL_DATALEN 32
#define TAPINS_IDCODE_LEN 32
#define TAPINS_BYPASS_LEN 1
static void xtensa_dm_add_set_ir(struct xtensa_debug_module *dm, uint8_t value)
{
struct scan_field field;
uint8_t t[4] = { 0 };
memset(&field, 0, sizeof(field));
field.num_bits = dm->tap->ir_length;
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, value);
jtag_add_ir_scan(dm->tap, &field, TAP_IDLE);
}
static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm,
int len,
const uint8_t *src,
uint8_t *dest,
tap_state_t endstate)
{
struct scan_field field;
memset(&field, 0, sizeof(field));
field.num_bits = len;
field.out_value = src;
field.in_value = dest;
jtag_add_dr_scan(dm->tap, 1, &field, endstate);
}
int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg)
{
if (!dm || !cfg)
return ERROR_FAIL;
dm->pwr_ops = cfg->pwr_ops;
dm->dbg_ops = cfg->dbg_ops;
dm->tap = cfg->tap;
dm->queue_tdi_idle = cfg->queue_tdi_idle;
dm->queue_tdi_idle_arg = cfg->queue_tdi_idle_arg;
return ERROR_OK;
}
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm)
{
return dm->dbg_ops->queue_reg_write(dm, NARADR_DCRSET, OCDDCR_ENABLEOCD);
}
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value)
{
uint8_t regdata = (reg << 1) | 0;
uint8_t dummy[4] = { 0, 0, 0, 0 };
if (reg > NARADR_MAX) {
LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, dummy, value, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint32_t value)
{
uint8_t regdata = (reg << 1) | 1;
uint8_t valdata[] = { value, value >> 8, value >> 16, value >> 24 };
if (reg > NARADR_MAX) {
LOG_ERROR("Invalid DBG reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, TAPINS_NARSEL);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_ADRLEN, &regdata, NULL, TAP_IDLE);
xtensa_dm_add_dr_scan(dm, TAPINS_NARSEL_DATALEN, valdata, NULL, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data, uint8_t clear)
{
uint8_t value_clr = clear;
uint8_t tap_insn;
int tap_insn_sz;
if (reg == DMREG_PWRCTL) {
tap_insn = TAPINS_PWRCTL;
tap_insn_sz = TAPINS_PWRCTL_LEN;
} else if (reg == DMREG_PWRSTAT) {
tap_insn = TAPINS_PWRSTAT;
tap_insn_sz = TAPINS_PWRSTAT_LEN;
} else {
LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, tap_insn);
xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value_clr, data, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data)
{
uint8_t value = data;
uint8_t tap_insn;
int tap_insn_sz;
if (reg == DMREG_PWRCTL) {
tap_insn = TAPINS_PWRCTL;
tap_insn_sz = TAPINS_PWRCTL_LEN;
} else if (reg == DMREG_PWRSTAT) {
tap_insn = TAPINS_PWRSTAT;
tap_insn_sz = TAPINS_PWRSTAT_LEN;
} else {
LOG_ERROR("Invalid PWR reg ID %d!", reg);
return ERROR_FAIL;
}
xtensa_dm_add_set_ir(dm, tap_insn);
xtensa_dm_add_dr_scan(dm, tap_insn_sz, &value, NULL, TAP_IDLE);
return ERROR_OK;
}
int xtensa_dm_device_id_read(struct xtensa_debug_module *dm)
{
uint8_t id_buf[sizeof(uint32_t)];
dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
dm->device_id = buf_get_u32(id_buf, 0, 32);
return ERROR_OK;
}
int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear)
{
/* uint8_t id_buf[sizeof(uint32_t)]; */
/* TODO: JTAG does not work when PWRCTL_JTAGDEBUGUSE is not set.
* It is set in xtensa_examine(), need to move reading of NARADR_OCDID out of this function */
/* dm->dbg_ops->queue_reg_read(dm, NARADR_OCDID, id_buf);
*Read reset state */
dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stat, clear);
dm->pwr_ops->queue_reg_read(dm, DMREG_PWRSTAT, &dm->power_status.stath, clear);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_core_status_read(struct xtensa_debug_module *dm)
{
uint8_t dsr_buf[sizeof(uint32_t)];
xtensa_dm_queue_enable(dm);
dm->dbg_ops->queue_reg_read(dm, NARADR_DSR, dsr_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
dm->core_status.dsr = buf_get_u32(dsr_buf, 0, 32);
return res;
}
int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits)
{
dm->dbg_ops->queue_reg_write(dm, NARADR_DSR, bits);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg)
{
/*Turn off trace unit so we can start a new trace. */
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, 0);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
/*Set up parameters */
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXADDR, 0);
if (cfg->stopmask != XTENSA_STOPMASK_DISABLED) {
dm->dbg_ops->queue_reg_write(dm, NARADR_PCMATCHCTRL,
(cfg->stopmask << PCMATCHCTRL_PCML_SHIFT));
dm->dbg_ops->queue_reg_write(dm, NARADR_TRIGGERPC, cfg->stoppc);
}
dm->dbg_ops->queue_reg_write(dm, NARADR_DELAYCNT, cfg->after);
/*Options are mostly hardcoded for now. ToDo: make this more configurable. */
dm->dbg_ops->queue_reg_write(
dm,
NARADR_TRAXCTRL,
TRAXCTRL_TREN |
((cfg->stopmask != XTENSA_STOPMASK_DISABLED) ? TRAXCTRL_PCMEN : 0) | TRAXCTRL_TMEN |
(cfg->after_is_words ? 0 : TRAXCTRL_CNTU) | (0 << TRAXCTRL_SMPER_SHIFT) | TRAXCTRL_PTOWS);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable)
{
uint8_t traxctl_buf[sizeof(uint32_t)];
uint32_t traxctl;
struct xtensa_trace_status trace_status;
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
traxctl = buf_get_u32(traxctl_buf, 0, 32);
if (!pto_enable)
traxctl &= ~(TRAXCTRL_PTOWS | TRAXCTRL_PTOWT);
dm->dbg_ops->queue_reg_write(dm, NARADR_TRAXCTRL, traxctl | TRAXCTRL_TRSTP);
xtensa_dm_queue_tdi_idle(dm);
res = jtag_execute_queue();
if (res != ERROR_OK)
return res;
/*Check current status of trace hardware */
res = xtensa_dm_trace_status_read(dm, &trace_status);
if (res != ERROR_OK)
return res;
if (trace_status.stat & TRAXSTAT_TRACT) {
LOG_ERROR("Failed to stop tracing (0x%x)!", trace_status.stat);
return ERROR_FAIL;
}
return ERROR_OK;
}
int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status)
{
uint8_t traxstat_buf[sizeof(uint32_t)];
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXSTAT, traxstat_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK && status)
status->stat = buf_get_u32(traxstat_buf, 0, 32);
return res;
}
int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config)
{
uint8_t traxctl_buf[sizeof(uint32_t)];
uint8_t memadrstart_buf[sizeof(uint32_t)];
uint8_t memadrend_buf[sizeof(uint32_t)];
uint8_t adr_buf[sizeof(uint32_t)];
if (!config)
return ERROR_FAIL;
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXCTRL, traxctl_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDRSTART, memadrstart_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_MEMADDREND, memadrend_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXADDR, adr_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK) {
config->ctrl = buf_get_u32(traxctl_buf, 0, 32);
config->memaddr_start = buf_get_u32(memadrstart_buf, 0, 32);
config->memaddr_end = buf_get_u32(memadrend_buf, 0, 32);
config->addr = buf_get_u32(adr_buf, 0, 32);
}
return res;
}
int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size)
{
if (!dest)
return ERROR_FAIL;
for (unsigned int i = 0; i < size / 4; i++)
dm->dbg_ops->queue_reg_read(dm, NARADR_TRAXDATA, &dest[i * 4]);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
const struct xtensa_perfmon_config *config)
{
if (!config)
return ERROR_FAIL;
uint8_t pmstat_buf[4];
uint32_t pmctrl = ((config->tracelevel) << 4) +
(config->select << 8) +
(config->mask << 16) +
(config->kernelcnt << 3);
/* enable performance monitor */
dm->dbg_ops->queue_reg_write(dm, NARADR_PMG, 0x1);
/* reset counter */
dm->dbg_ops->queue_reg_write(dm, NARADR_PM0 + counter_id, 0);
dm->dbg_ops->queue_reg_write(dm, NARADR_PMCTRL0 + counter_id, pmctrl);
dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
xtensa_dm_queue_tdi_idle(dm);
return jtag_execute_queue();
}
int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
struct xtensa_perfmon_result *out_result)
{
uint8_t pmstat_buf[4];
uint8_t pmcount_buf[4];
dm->dbg_ops->queue_reg_read(dm, NARADR_PMSTAT0 + counter_id, pmstat_buf);
dm->dbg_ops->queue_reg_read(dm, NARADR_PM0 + counter_id, pmcount_buf);
xtensa_dm_queue_tdi_idle(dm);
int res = jtag_execute_queue();
if (res == ERROR_OK) {
uint32_t stat = buf_get_u32(pmstat_buf, 0, 32);
uint64_t result = buf_get_u32(pmcount_buf, 0, 32);
/* TODO: if counter # counter_id+1 has 'select' set to 1, use its value as the
* high 32 bits of the counter. */
if (out_result) {
out_result->overflow = ((stat & 1) != 0);
out_result->value = result;
}
}
return res;
}

View File

@ -0,0 +1,385 @@
/***************************************************************************
* Xtensa debug module API *
* Copyright (C) 2019 Espressif Systems Ltd. *
* <alexey@espressif.com> *
* *
* Derived from original ESP8266 target. *
* Copyright (C) 2015 by Angus Gratton *
* gus@projectgus.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H
#define OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H
#include <jtag/jtag.h>
#include <helper/bits.h>
#include <target/target.h>
/* Virtual IDs for using with xtensa_power_ops API */
#define DMREG_PWRCTL 0x00
#define DMREG_PWRSTAT 0x01
/*
From the manual:
To properly use Debug registers through JTAG, software must ensure that:
- Tap is out of reset
- Xtensa Debug Module is out of reset
- Other bits of PWRCTL are set to their desired values, and finally
- JtagDebugUse transitions from 0 to 1
The bit must continue to be 1 in order for JTAG accesses to the Debug
Module to happen correctly. When it is set, any write to this bit clears it.
Either don't access it, or re-write it to 1 so JTAG accesses continue.
*/
#define PWRCTL_JTAGDEBUGUSE BIT(7)
#define PWRCTL_DEBUGRESET BIT(6)
#define PWRCTL_CORERESET BIT(4)
#define PWRCTL_DEBUGWAKEUP BIT(2)
#define PWRCTL_MEMWAKEUP BIT(1)
#define PWRCTL_COREWAKEUP BIT(0)
#define PWRSTAT_DEBUGWASRESET BIT(6)
#define PWRSTAT_COREWASRESET BIT(4)
#define PWRSTAT_CORESTILLNEEDED BIT(3)
#define PWRSTAT_DEBUGDOMAINON BIT(2)
#define PWRSTAT_MEMDOMAINON BIT(1)
#define PWRSTAT_COREDOMAINON BIT(0)
/* *** NAR addresses (also used as IDs for debug registers in xtensa_debug_ops API) ***
*TRAX registers */
#define NARADR_TRAXID 0x00
#define NARADR_TRAXCTRL 0x01
#define NARADR_TRAXSTAT 0x02
#define NARADR_TRAXDATA 0x03
#define NARADR_TRAXADDR 0x04
#define NARADR_TRIGGERPC 0x05
#define NARADR_PCMATCHCTRL 0x06
#define NARADR_DELAYCNT 0x07
#define NARADR_MEMADDRSTART 0x08
#define NARADR_MEMADDREND 0x09
/*Performance monitor registers */
#define NARADR_PMG 0x20
#define NARADR_INTPC 0x24
#define NARADR_PM0 0x28
/*... */
#define NARADR_PM7 0x2F
#define NARADR_PMCTRL0 0x30
/*... */
#define NARADR_PMCTRL7 0x37
#define NARADR_PMSTAT0 0x38
/*... */
#define NARADR_PMSTAT7 0x3F
/*OCD registers */
#define NARADR_OCDID 0x40
#define NARADR_DCRCLR 0x42
#define NARADR_DCRSET 0x43
#define NARADR_DSR 0x44
#define NARADR_DDR 0x45
#define NARADR_DDREXEC 0x46
#define NARADR_DIR0EXEC 0x47
#define NARADR_DIR0 0x48
#define NARADR_DIR1 0x49
/*... */
#define NARADR_DIR7 0x4F
/*Misc registers */
#define NARADR_PWRCTL 0x58
#define NARADR_PWRSTAT 0x59
#define NARADR_ERISTAT 0x5A
/*CoreSight registers */
#define NARADR_ITCTRL 0x60
#define NARADR_CLAIMSET 0x68
#define NARADR_CLAIMCLR 0x69
#define NARADR_LOCKACCESS 0x6c
#define NARADR_LOCKSTATUS 0x6d
#define NARADR_AUTHSTATUS 0x6e
#define NARADR_DEVID 0x72
#define NARADR_DEVTYPE 0x73
#define NARADR_PERID4 0x74
/*... */
#define NARADR_PERID7 0x77
#define NARADR_PERID0 0x78
/*... */
#define NARADR_PERID3 0x7b
#define NARADR_COMPID0 0x7c
/*... */
#define NARADR_COMPID3 0x7f
#define NARADR_MAX NARADR_COMPID3
/*OCD registers, bit definitions */
#define OCDDCR_ENABLEOCD BIT(0)
#define OCDDCR_DEBUGINTERRUPT BIT(1)
#define OCDDCR_INTERRUPTALLCONDS BIT(2)
#define OCDDCR_BREAKINEN BIT(16)
#define OCDDCR_BREAKOUTEN BIT(17)
#define OCDDCR_DEBUGSWACTIVE BIT(20)
#define OCDDCR_RUNSTALLINEN BIT(21)
#define OCDDCR_DEBUGMODEOUTEN BIT(22)
#define OCDDCR_BREAKOUTITO BIT(24)
#define OCDDCR_BREAKACKITO BIT(25)
#define OCDDSR_EXECDONE BIT(0)
#define OCDDSR_EXECEXCEPTION BIT(1)
#define OCDDSR_EXECBUSY BIT(2)
#define OCDDSR_EXECOVERRUN BIT(3)
#define OCDDSR_STOPPED BIT(4)
#define OCDDSR_COREWROTEDDR BIT(10)
#define OCDDSR_COREREADDDR BIT(11)
#define OCDDSR_HOSTWROTEDDR BIT(14)
#define OCDDSR_HOSTREADDDR BIT(15)
#define OCDDSR_DEBUGPENDBREAK BIT(16)
#define OCDDSR_DEBUGPENDHOST BIT(17)
#define OCDDSR_DEBUGPENDTRAX BIT(18)
#define OCDDSR_DEBUGINTBREAK BIT(20)
#define OCDDSR_DEBUGINTHOST BIT(21)
#define OCDDSR_DEBUGINTTRAX BIT(22)
#define OCDDSR_RUNSTALLTOGGLE BIT(23)
#define OCDDSR_RUNSTALLSAMPLE BIT(24)
#define OCDDSR_BREACKOUTACKITI BIT(25)
#define OCDDSR_BREAKINITI BIT(26)
#define OCDDSR_DBGMODPOWERON BIT(31)
#define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */
#define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */
#define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */
#define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */
#define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */
#define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */
#define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */
#define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */
#define TRAXCTRL_PCMEN BIT(2) /* PC match enable */
#define TRAXCTRL_PTIEN BIT(4) /* Processor-trigger enable */
#define TRAXCTRL_CTIEN BIT(5) /* Cross-trigger enable */
#define TRAXCTRL_TMEN BIT(7) /* Tracemem Enable. Always set. */
#define TRAXCTRL_CNTU BIT(9) /* Post-stop-trigger countdown units; selects when DelayCount-- happens.
*0 - every 32-bit word written to tracemem, 1 - every cpu instruction */
#define TRAXCTRL_TSEN BIT(11) /* Undocumented/deprecated? */
#define TRAXCTRL_SMPER_SHIFT 12 /* Send sync every 2^(9-smper) messages. 7=reserved, 0=no sync msg */
#define TRAXCTRL_SMPER_MASK 0x07 /* Synchronization message period */
#define TRAXCTRL_PTOWT BIT(16) /* Processor Trigger Out (OCD halt) enabled when stop triggered */
#define TRAXCTRL_PTOWS BIT(17) /* Processor Trigger Out (OCD halt) enabled when trace stop completes */
#define TRAXCTRL_CTOWT BIT(20) /* Cross-trigger Out enabled when stop triggered */
#define TRAXCTRL_CTOWS BIT(21) /* Cross-trigger Out enabled when trace stop completes */
#define TRAXCTRL_ITCTO BIT(22) /* Integration mode: cross-trigger output */
#define TRAXCTRL_ITCTIA BIT(23) /* Integration mode: cross-trigger ack */
#define TRAXCTRL_ITATV BIT(24) /* replaces ATID when in integration mode: ATVALID output */
#define TRAXCTRL_ATID_MASK 0x7F /* ARB source ID */
#define TRAXCTRL_ATID_SHIFT 24
#define TRAXCTRL_ATEN BIT(31) /* ATB interface enable */
#define TRAXSTAT_TRACT BIT(0) /* Trace active flag. */
#define TRAXSTAT_TRIG BIT(1) /* Trace stop trigger. Clears on TREN 1->0 */
#define TRAXSTAT_PCMTG BIT(2) /* Stop trigger caused by PC match. Clears on TREN 1->0 */
#define TRAXSTAT_PJTR BIT(3) /* JTAG transaction result. 1=err in preceding jtag transaction. */
#define TRAXSTAT_PTITG BIT(4) /* Stop trigger caused by Processor Trigger Input.Clears on TREN 1->0 */
#define TRAXSTAT_CTITG BIT(5) /* Stop trigger caused by Cross-Trigger Input. Clears on TREN 1->0 */
#define TRAXSTAT_MEMSZ_SHIFT 8 /* Traceram size inducator. Usable trace ram is 2^MEMSZ bytes. */
#define TRAXSTAT_MEMSZ_MASK 0x1F
#define TRAXSTAT_PTO BIT(16) /* Processor Trigger Output: current value */
#define TRAXSTAT_CTO BIT(17) /* Cross-Trigger Output: current value */
#define TRAXSTAT_ITCTOA BIT(22) /* Cross-Trigger Out Ack: current value */
#define TRAXSTAT_ITCTI BIT(23) /* Cross-Trigger Input: current value */
#define TRAXSTAT_ITATR BIT(24) /* ATREADY Input: current value */
#define TRAXADDR_TADDR_SHIFT 0 /* Trax memory address, in 32-bit words. */
#define TRAXADDR_TADDR_MASK 0x1FFFFF /* Actually is only as big as the trace buffer size max addr. */
#define TRAXADDR_TWRAP_SHIFT 21 /* Amount of times TADDR has overflown */
#define TRAXADDR_TWRAP_MASK 0x3FF
#define TRAXADDR_TWSAT BIT(31) /* 1 if TWRAP has overflown, clear by disabling tren.*/
#define PCMATCHCTRL_PCML_SHIFT 0 /* Amount of lower bits to ignore in pc trigger register */
#define PCMATCHCTRL_PCML_MASK 0x1F
#define PCMATCHCTRL_PCMS BIT(31) /* PC Match Sense, 0-match when procs PC is in-range, 1-match when
*out-of-range */
#define XTENSA_MAX_PERF_COUNTERS 2
#define XTENSA_MAX_PERF_SELECT 32
#define XTENSA_MAX_PERF_MASK 0xffff
#define XTENSA_STOPMASK_DISABLED UINT32_MAX
struct xtensa_debug_module;
struct xtensa_debug_ops {
/** enable operation */
int (*queue_enable)(struct xtensa_debug_module *dm);
/** register read. */
int (*queue_reg_read)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data);
/** register write. */
int (*queue_reg_write)(struct xtensa_debug_module *dm, unsigned int reg, uint32_t data);
};
struct xtensa_power_ops {
/** register read. */
int (*queue_reg_read)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data,
uint8_t clear);
/** register write. */
int (*queue_reg_write)(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data);
};
typedef uint8_t xtensa_pwrstat_t;
typedef uint32_t xtensa_ocdid_t;
typedef uint32_t xtensa_dsr_t;
typedef uint32_t xtensa_traxstat_t;
struct xtensa_power_status {
xtensa_pwrstat_t stat;
xtensa_pwrstat_t stath;
/* TODO: do not need to keep previous status to detect that core or debug module has been
* reset, */
/* we can clear PWRSTAT_DEBUGWASRESET and PWRSTAT_COREWASRESET after reading will do
* the job; */
/* upon next reet those bits will be set again. So we can get rid of
* xtensa_dm_power_status_cache_reset() and xtensa_dm_power_status_cache(). */
xtensa_pwrstat_t prev_stat;
};
struct xtensa_core_status {
xtensa_dsr_t dsr;
};
struct xtensa_trace_config {
uint32_t ctrl;
uint32_t memaddr_start;
uint32_t memaddr_end;
uint32_t addr;
};
struct xtensa_trace_status {
xtensa_traxstat_t stat;
};
struct xtensa_trace_start_config {
uint32_t stoppc;
bool after_is_words;
uint32_t after;
uint32_t stopmask; /* UINT32_MAX: disable PC match option */
};
struct xtensa_perfmon_config {
int select;
uint32_t mask;
int kernelcnt;
int tracelevel;
};
struct xtensa_perfmon_result {
uint64_t value;
bool overflow;
};
struct xtensa_debug_module_config {
const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops;
struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg;
};
struct xtensa_debug_module {
const struct xtensa_power_ops *pwr_ops;
const struct xtensa_debug_ops *dbg_ops;
struct jtag_tap *tap;
void (*queue_tdi_idle)(struct target *target);
void *queue_tdi_idle_arg;
struct xtensa_power_status power_status;
struct xtensa_core_status core_status;
xtensa_ocdid_t device_id;
};
int xtensa_dm_init(struct xtensa_debug_module *dm, const struct xtensa_debug_module_config *cfg);
int xtensa_dm_queue_enable(struct xtensa_debug_module *dm);
int xtensa_dm_queue_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *value);
int xtensa_dm_queue_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint32_t value);
int xtensa_dm_queue_pwr_reg_read(struct xtensa_debug_module *dm, unsigned int reg, uint8_t *data, uint8_t clear);
int xtensa_dm_queue_pwr_reg_write(struct xtensa_debug_module *dm, unsigned int reg, uint8_t data);
static inline void xtensa_dm_queue_tdi_idle(struct xtensa_debug_module *dm)
{
if (dm->queue_tdi_idle)
dm->queue_tdi_idle(dm->queue_tdi_idle_arg);
}
int xtensa_dm_power_status_read(struct xtensa_debug_module *dm, uint32_t clear);
static inline void xtensa_dm_power_status_cache_reset(struct xtensa_debug_module *dm)
{
dm->power_status.prev_stat = 0;
}
static inline void xtensa_dm_power_status_cache(struct xtensa_debug_module *dm)
{
dm->power_status.prev_stat = dm->power_status.stath;
}
static inline xtensa_pwrstat_t xtensa_dm_power_status_get(struct xtensa_debug_module *dm)
{
return dm->power_status.stat;
}
int xtensa_dm_core_status_read(struct xtensa_debug_module *dm);
int xtensa_dm_core_status_clear(struct xtensa_debug_module *dm, xtensa_dsr_t bits);
int xtensa_dm_core_status_check(struct xtensa_debug_module *dm);
static inline xtensa_dsr_t xtensa_dm_core_status_get(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr;
}
int xtensa_dm_device_id_read(struct xtensa_debug_module *dm);
static inline xtensa_ocdid_t xtensa_dm_device_id_get(struct xtensa_debug_module *dm)
{
return dm->device_id;
}
int xtensa_dm_trace_start(struct xtensa_debug_module *dm, struct xtensa_trace_start_config *cfg);
int xtensa_dm_trace_stop(struct xtensa_debug_module *dm, bool pto_enable);
int xtensa_dm_trace_config_read(struct xtensa_debug_module *dm, struct xtensa_trace_config *config);
int xtensa_dm_trace_status_read(struct xtensa_debug_module *dm, struct xtensa_trace_status *status);
int xtensa_dm_trace_data_read(struct xtensa_debug_module *dm, uint8_t *dest, uint32_t size);
static inline bool xtensa_dm_is_online(struct xtensa_debug_module *dm)
{
int res = xtensa_dm_device_id_read(dm);
if (res != ERROR_OK)
return false;
return (dm->device_id != 0xffffffff && dm->device_id != 0);
}
static inline bool xtensa_dm_tap_was_reset(struct xtensa_debug_module *dm)
{
return !(dm->power_status.prev_stat & PWRSTAT_DEBUGWASRESET) &&
dm->power_status.stat & PWRSTAT_DEBUGWASRESET;
}
static inline bool xtensa_dm_core_was_reset(struct xtensa_debug_module *dm)
{
return !(dm->power_status.prev_stat & PWRSTAT_COREWASRESET) &&
dm->power_status.stat & PWRSTAT_COREWASRESET;
}
static inline bool xtensa_dm_core_is_stalled(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr & OCDDSR_RUNSTALLSAMPLE;
}
static inline bool xtensa_dm_is_powered(struct xtensa_debug_module *dm)
{
return dm->core_status.dsr & OCDDSR_DBGMODPOWERON;
}
int xtensa_dm_perfmon_enable(struct xtensa_debug_module *dm, int counter_id,
const struct xtensa_perfmon_config *config);
int xtensa_dm_perfmon_dump(struct xtensa_debug_module *dm, int counter_id,
struct xtensa_perfmon_result *out_result);
#endif /* OPENOCD_TARGET_XTENSA_DEBUG_MODULE_H */

View File

@ -0,0 +1,278 @@
/***************************************************************************
* Generic Xtensa target API for OpenOCD *
* Copyright (C) 2016-2019 Espressif Systems Ltd. *
* Author: Angus Gratton gus@projectgus.com *
* Author: Jeroen Domburg <jeroen@espressif.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef OPENOCD_TARGET_XTENSA_REGS_H
#define OPENOCD_TARGET_XTENSA_REGS_H
struct reg_arch_type;
enum xtensa_reg_id {
XT_REG_IDX_PC = 0,
XT_REG_IDX_AR0,
XT_REG_IDX_AR1,
XT_REG_IDX_AR2,
XT_REG_IDX_AR3,
XT_REG_IDX_AR4,
XT_REG_IDX_AR5,
XT_REG_IDX_AR6,
XT_REG_IDX_AR7,
XT_REG_IDX_AR8,
XT_REG_IDX_AR9,
XT_REG_IDX_AR10,
XT_REG_IDX_AR11,
XT_REG_IDX_AR12,
XT_REG_IDX_AR13,
XT_REG_IDX_AR14,
XT_REG_IDX_AR15,
XT_REG_IDX_AR16,
XT_REG_IDX_AR17,
XT_REG_IDX_AR18,
XT_REG_IDX_AR19,
XT_REG_IDX_AR20,
XT_REG_IDX_AR21,
XT_REG_IDX_AR22,
XT_REG_IDX_AR23,
XT_REG_IDX_AR24,
XT_REG_IDX_AR25,
XT_REG_IDX_AR26,
XT_REG_IDX_AR27,
XT_REG_IDX_AR28,
XT_REG_IDX_AR29,
XT_REG_IDX_AR30,
XT_REG_IDX_AR31,
XT_REG_IDX_AR32,
XT_REG_IDX_AR33,
XT_REG_IDX_AR34,
XT_REG_IDX_AR35,
XT_REG_IDX_AR36,
XT_REG_IDX_AR37,
XT_REG_IDX_AR38,
XT_REG_IDX_AR39,
XT_REG_IDX_AR40,
XT_REG_IDX_AR41,
XT_REG_IDX_AR42,
XT_REG_IDX_AR43,
XT_REG_IDX_AR44,
XT_REG_IDX_AR45,
XT_REG_IDX_AR46,
XT_REG_IDX_AR47,
XT_REG_IDX_AR48,
XT_REG_IDX_AR49,
XT_REG_IDX_AR50,
XT_REG_IDX_AR51,
XT_REG_IDX_AR52,
XT_REG_IDX_AR53,
XT_REG_IDX_AR54,
XT_REG_IDX_AR55,
XT_REG_IDX_AR56,
XT_REG_IDX_AR57,
XT_REG_IDX_AR58,
XT_REG_IDX_AR59,
XT_REG_IDX_AR60,
XT_REG_IDX_AR61,
XT_REG_IDX_AR62,
XT_REG_IDX_AR63,
XT_REG_IDX_LBEG,
XT_REG_IDX_LEND,
XT_REG_IDX_LCOUNT,
XT_REG_IDX_SAR,
XT_REG_IDX_WINDOWBASE,
XT_REG_IDX_WINDOWSTART,
XT_REG_IDX_CONFIGID0,
XT_REG_IDX_CONFIGID1,
XT_REG_IDX_PS,
XT_REG_IDX_THREADPTR,
XT_REG_IDX_BR,
XT_REG_IDX_SCOMPARE1,
XT_REG_IDX_ACCLO,
XT_REG_IDX_ACCHI,
XT_REG_IDX_M0,
XT_REG_IDX_M1,
XT_REG_IDX_M2,
XT_REG_IDX_M3,
XT_REG_IDX_F0,
XT_REG_IDX_F1,
XT_REG_IDX_F2,
XT_REG_IDX_F3,
XT_REG_IDX_F4,
XT_REG_IDX_F5,
XT_REG_IDX_F6,
XT_REG_IDX_F7,
XT_REG_IDX_F8,
XT_REG_IDX_F9,
XT_REG_IDX_F10,
XT_REG_IDX_F11,
XT_REG_IDX_F12,
XT_REG_IDX_F13,
XT_REG_IDX_F14,
XT_REG_IDX_F15,
XT_REG_IDX_FCR,
XT_REG_IDX_FSR,
XT_REG_IDX_MMID,
XT_REG_IDX_IBREAKENABLE,
XT_REG_IDX_MEMCTL,
XT_REG_IDX_ATOMCTL,
XT_REG_IDX_IBREAKA0,
XT_REG_IDX_IBREAKA1,
XT_REG_IDX_DBREAKA0,
XT_REG_IDX_DBREAKA1,
XT_REG_IDX_DBREAKC0,
XT_REG_IDX_DBREAKC1,
XT_REG_IDX_EPC1,
XT_REG_IDX_EPC2,
XT_REG_IDX_EPC3,
XT_REG_IDX_EPC4,
XT_REG_IDX_EPC5,
XT_REG_IDX_EPC6,
XT_REG_IDX_EPC7,
XT_REG_IDX_DEPC,
XT_REG_IDX_EPS2,
XT_REG_IDX_EPS3,
XT_REG_IDX_EPS4,
XT_REG_IDX_EPS5,
XT_REG_IDX_EPS6,
XT_REG_IDX_EPS7,
XT_REG_IDX_EXCSAVE1,
XT_REG_IDX_EXCSAVE2,
XT_REG_IDX_EXCSAVE3,
XT_REG_IDX_EXCSAVE4,
XT_REG_IDX_EXCSAVE5,
XT_REG_IDX_EXCSAVE6,
XT_REG_IDX_EXCSAVE7,
XT_REG_IDX_CPENABLE,
XT_REG_IDX_INTERRUPT,
XT_REG_IDX_INTSET,
XT_REG_IDX_INTCLEAR,
XT_REG_IDX_INTENABLE,
XT_REG_IDX_VECBASE,
XT_REG_IDX_EXCCAUSE,
XT_REG_IDX_DEBUGCAUSE,
XT_REG_IDX_CCOUNT,
XT_REG_IDX_PRID,
XT_REG_IDX_ICOUNT,
XT_REG_IDX_ICOUNTLEVEL,
XT_REG_IDX_EXCVADDR,
XT_REG_IDX_CCOMPARE0,
XT_REG_IDX_CCOMPARE1,
XT_REG_IDX_CCOMPARE2,
XT_REG_IDX_MISC0,
XT_REG_IDX_MISC1,
XT_REG_IDX_MISC2,
XT_REG_IDX_MISC3,
XT_REG_IDX_LITBASE,
XT_REG_IDX_PTEVADDR,
XT_REG_IDX_RASID,
XT_REG_IDX_ITLBCFG,
XT_REG_IDX_DTLBCFG,
XT_REG_IDX_MEPC,
XT_REG_IDX_MEPS,
XT_REG_IDX_MESAVE,
XT_REG_IDX_MESR,
XT_REG_IDX_MECR,
XT_REG_IDX_MEVADDR,
XT_REG_IDX_A0,
XT_REG_IDX_A1,
XT_REG_IDX_A2,
XT_REG_IDX_A3,
XT_REG_IDX_A4,
XT_REG_IDX_A5,
XT_REG_IDX_A6,
XT_REG_IDX_A7,
XT_REG_IDX_A8,
XT_REG_IDX_A9,
XT_REG_IDX_A10,
XT_REG_IDX_A11,
XT_REG_IDX_A12,
XT_REG_IDX_A13,
XT_REG_IDX_A14,
XT_REG_IDX_A15,
XT_REG_IDX_PWRCTL,
XT_REG_IDX_PWRSTAT,
XT_REG_IDX_ERISTAT,
XT_REG_IDX_CS_ITCTRL,
XT_REG_IDX_CS_CLAIMSET,
XT_REG_IDX_CS_CLAIMCLR,
XT_REG_IDX_CS_LOCKACCESS,
XT_REG_IDX_CS_LOCKSTATUS,
XT_REG_IDX_CS_AUTHSTATUS,
XT_REG_IDX_FAULT_INFO,
XT_REG_IDX_TRAX_ID,
XT_REG_IDX_TRAX_CTRL,
XT_REG_IDX_TRAX_STAT,
XT_REG_IDX_TRAX_DATA,
XT_REG_IDX_TRAX_ADDR,
XT_REG_IDX_TRAX_PCTRIGGER,
XT_REG_IDX_TRAX_PCMATCH,
XT_REG_IDX_TRAX_DELAY,
XT_REG_IDX_TRAX_MEMSTART,
XT_REG_IDX_TRAX_MEMEND,
XT_REG_IDX_PMG,
XT_REG_IDX_PMPC,
XT_REG_IDX_PM0,
XT_REG_IDX_PM1,
XT_REG_IDX_PMCTRL0,
XT_REG_IDX_PMCTRL1,
XT_REG_IDX_PMSTAT0,
XT_REG_IDX_PMSTAT1,
XT_REG_IDX_OCD_ID,
XT_REG_IDX_OCD_DCRCLR,
XT_REG_IDX_OCD_DCRSET,
XT_REG_IDX_OCD_DSR,
XT_REG_IDX_OCD_DDR,
XT_NUM_REGS,
/* chip-specific user registers go after ISA-defined ones */
XT_USR_REG_START = XT_NUM_REGS
};
typedef uint32_t xtensa_reg_val_t;
enum xtensa_reg_type {
XT_REG_GENERAL = 0, /* General-purpose register; part of the windowed register set */
XT_REG_USER = 1, /* User register, needs RUR to read */
XT_REG_SPECIAL = 2, /* Special register, needs RSR to read */
XT_REG_DEBUG = 3, /* Register used for the debug interface. Don't mess with this. */
XT_REG_RELGEN = 4, /* Relative general address. Points to the absolute addresses plus the window
*index */
XT_REG_FR = 5, /* Floating-point register */
};
enum xtensa_reg_flags {
XT_REGF_NOREAD = 0x01, /* Register is write-only */
XT_REGF_COPROC0 = 0x02 /* Can't be read if coproc0 isn't enabled */
};
struct xtensa_reg_desc {
const char *name;
unsigned int reg_num; /* ISA register num (meaning depends on register type) */
enum xtensa_reg_type type;
enum xtensa_reg_flags flags;
};
struct xtensa_user_reg_desc {
const char *name;
/* ISA register num (meaning depends on register type) */
unsigned int reg_num;
enum xtensa_reg_flags flags;
uint32_t size;
const struct reg_arch_type *type;
};
extern const struct xtensa_reg_desc xtensa_regs[XT_NUM_REGS];
#endif /* OPENOCD_TARGET_XTENSA_REGS_H */

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Example OpenOCD configuration file for ESP32-S2 Kaluga board.
#
# For example, OpenOCD can be started for ESP32-S2 debugging on
#
# openocd -f board/esp32s2-kaluga-1.cfg
#
source [find interface/ftdi/esp32s2_kaluga_v1.cfg]
source [find target/esp32s2.cfg]
# The speed of the JTAG interface, in kHz. If you get DSR/DIR errors (and they
# do not relate to OpenOCD trying to read from a memory range without physical
# memory being present there), you can try lowering this.
# On ESP32-S2, this can go as high as 20MHz if CPU frequency is 80MHz, or 26MHz
# if CPU frequency is 160MHz or 240MHz.
adapter speed 20000

View File

@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Kontron SMARC-sAL28
transport select jtag
reset_config srst_only srst_nogate
jtag newtap unknown0 tap -irlen 12
set _CPUS 2
source [find target/ls1028a.cfg]
source [find tcl/cpld/altera-epm240.cfg]
adapter speed 2000

View File

@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later.
# This is an evaluation board with a single BlueNRG-LPS chip.
set CHIPNAME bluenrg-lps
source [find interface/cmsis-dap.cfg]
source [find target/bluenrg-x.cfg]

View File

@ -0,0 +1,28 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# BeagleBone native GPIO interface for JTAG
#
# This is best used with a fast buffer but it is also suitable for a direct
# connection if the target voltage matches the host's IO voltage (typically
# 3.3V) and the cable is short.
#
# DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH.
#
# Do not forget the GND connection.
adapter driver am335xgpio
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack
# am335xgpio speed SPEED_COEFF SPEED_OFFSET
am335xgpio speed_coeffs 600000 575
am335xgpio tdo_num 20
am335xgpio tdi_num 60
am335xgpio tms_num 4
am335xgpio tck_num 2
am335xgpio led_num 51
am335xgpio led_on_state on
am335xgpio srst_num 65
reset_config srst_only srst_push_pull

View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# BeagleBone native GPIO interface for SWD
#
# This is best used with a fast buffer but it is also suitable for a direct
# connection if the target voltage matches the host's IO voltage (typically
# 3.3V) and the cable is short.
#
# DO NOT APPLY VOLTAGE TO THE GPIO PINS UNTIL SYS_RESETN IS HIGH.
#
# Do not forget the GND connection.
adapter driver am335xgpio
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on the system clock, calibrated for stock 1 GHz BeagleBoneBlack
# am335xgpio speed SPEED_COEFF SPEED_OFFSET
am335xgpio speed_coeffs 600000 575
am335xgpio swclk_num 2
am335xgpio swdio_num 4
am335xgpio swdio_dir_num 60
am335xgpio swdio_dir_output_state on
# USR0 LED
am335xgpio led_num 53
am335xgpio led_on_state on
am335xgpio srst_num 65
reset_config srst_only srst_push_pull

View File

@ -0,0 +1,29 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Driver for the FT2232H JTAG chip on the Espressif Kaluga-1 ESP32-S2 board
# (and most other FT2232H and FT232H based boards)
#
# JTAG DIP switch (labelled SW5 in the schematic) should be "ON" for lines
# labelled TCK, TDO, TDI and TWS, to connect the FT2232H to the ESP32-S2.
#
adapter driver ftdi
ftdi vid_pid 0x0403 0x6010 0x0403 0x6014
# interface 1 is the uart
ftdi channel 0
# TCK, TDI, TDO, TMS: ADBUS0-3
# TRST/SRST: ADBUS5 (unused for now)
# LEDs: ACBUS3-4 (inverted)
ftdi layout_init 0x0008 0x180b
ftdi layout_signal LED -ndata 0x0800
ftdi layout_signal LED2 -ndata 0x1000
# ESP32* series chips do not have a TRST input, and the SRST line is connected
# to the EN pin.
# The target code doesn't handle SRST reset properly yet, so this is
# commented out:
# ftdi layout_signal nSRST -oe 0x0020
# reset_config srst_only

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Tigard: An FTDI FT2232H-based multi-protocol tool for hardware hacking.
# https://github.com/tigard-tools/tigard
adapter driver ftdi
ftdi device_desc "Tigard V1.1"
ftdi vid_pid 0x0403 0x6010
ftdi channel 1
ftdi layout_init 0x0038 0x003b
ftdi layout_signal nTRST -data 0x0010
ftdi layout_signal nSRST -data 0x0020
# This board doesn't support open-drain reset modes since its output buffer is
# always enabled.
reset_config srst_push_pull trst_push_pull

View File

@ -47,11 +47,14 @@ if {![using_hla]} {
cortex_m reset_config sysresetreq
}
set JTAG_IDCODE_B2 0x0200A041
set JTAG_IDCODE_B1 0x0
$_TARGETNAME configure -event halted {
global WDOG_VALUE
global WDOG_VALUE_SET
set _JTAG_IDCODE [mrw 0x40000004]
if {$_JTAG_IDCODE != 0x0201E041} {
if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} {
# Stop watchdog during halt, if enabled. Only Bluenrg-1/2
set WDOG_VALUE [mrw 0x40700008]
if [expr {$WDOG_VALUE & (1 << 1)}] {
@ -64,7 +67,7 @@ $_TARGETNAME configure -event resumed {
global WDOG_VALUE
global WDOG_VALUE_SET
set _JTAG_IDCODE [mrw 0x40000004]
if {$_JTAG_IDCODE != 0x0201E041} {
if {$_JTAG_IDCODE == $JTAG_IDCODE_B2 || $_JTAG_IDCODE == $JTAG_IDCODE_B1} {
if {$WDOG_VALUE_SET} {
# Restore watchdog enable value after resume. Only Bluenrg-1/2
mww 0x40700008 $WDOG_VALUE

30
tcl/target/esp32s2.cfg Normal file
View File

@ -0,0 +1,30 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# The ESP32-S2 only supports JTAG.
transport select jtag
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME esp32s2
}
if { [info exists CPUTAPID] } {
set _CPUTAPID $CPUTAPID
} else {
set _CPUTAPID 0x120034e5
}
set _TARGETNAME $_CHIPNAME
set _CPUNAME cpu
set _TAPNAME $_CHIPNAME.$_CPUNAME
jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID
target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME
xtensa maskisr on
$_TARGETNAME configure -event reset-assert-post { soft_reset_halt }
gdb_breakpoint_override hard

18
tcl/target/ls1028a.cfg Normal file
View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# NXP LS1028A
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME ls1028a
}
if { [info exists DAP_TAPID] } {
set _DAP_TAPID $DAP_TAPID
} else {
set _DAP_TAPID 0x6ba00477
}
set _CPUS 2
source [find target/lsch3_common.cfg]

View File

@ -13,62 +13,9 @@ if { [info exists DAP_TAPID] } {
set _DAP_TAPID 0x5ba00477
}
jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap
set _CPUS 8
target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1
set _CPU_BASE 0x81000000
set _CPU_STRIDE 0x100000
set _CPU_DBGOFF 0x10000
set _CPU_CTIOFF 0x20000
set _TARGETS {}
for {set i 0} {$i < 8} {incr i} {
set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}]
cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \
-baseaddr [expr {$_BASE + $_CPU_CTIOFF}]
target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \
-cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \
{*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }]
lappend _TARGETS $_CHIPNAME.cpu$i
}
target smp {*}$_TARGETS
# Service processor
target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000
# Normally you will not need to call this, but if you are using the hard-coded
# Reset Configuration Word (RCW) you will need to call this manually. The CPU's
# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit
# instructions. This will cause the CPU to almost immediately execute an
# illegal instruction.
#
# This code is idempotent; releasing a released CPU has no effect, although it
# will halt/resume the service processor.
add_help_text release_cpu "Release a cpu which is held off"
proc release_cpu {cpu} {
set RST_BRRL 0x1e60060
set old [target current]
targets $::_CHIPNAME.sp
set not_halted [string compare halted [$::_CHIPNAME.sp curstate]]
if {$not_halted} {
halt
}
# Release the cpu; it will start executing something bogus
mem2array regs 32 $RST_BRRL 1
mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}]
if {$not_halted} {
resume
}
targets $old
}
targets $_CHIPNAME.cpu0
source [find target/lsch3_common.cfg]
# Seems to work OK in testing
adapter speed 10000

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# This contains common configuration for NXP Layerscape chassis generation 3
if { ![info exists _CPUS] } {
error "_CPUS must be set to the number of cores"
}
jtag newtap $_CHIPNAME dap -irlen 4 -expected-id $_DAP_TAPID
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap
target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 1
set _CPU_BASE 0x81000000
set _CPU_STRIDE 0x100000
set _CPU_DBGOFF 0x10000
set _CPU_CTIOFF 0x20000
set _TARGETS {}
for {set i 0} {$i < $_CPUS} {incr i} {
set _BASE [expr {$_CPU_BASE + $_CPU_STRIDE * $i}]
cti create $_CHIPNAME.cti$i -dap $_CHIPNAME.dap -ap-num 0 \
-baseaddr [expr {$_BASE + $_CPU_CTIOFF}]
target create $_CHIPNAME.cpu$i aarch64 -dap $_CHIPNAME.dap \
-cti $_CHIPNAME.cti$i -dbgbase [expr {$_BASE + $_CPU_DBGOFF}] \
{*}[expr {$i ? "-coreid $i" : "-rtos hwthread" }]
lappend _TARGETS $_CHIPNAME.cpu$i
}
target smp {*}$_TARGETS
# Service processor
target create $_CHIPNAME.sp cortex_a -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80138000
# Normally you will not need to call this, but if you are using the hard-coded
# Reset Configuration Word (RCW) you will need to call this manually. The CPU's
# reset vector is 0, and the boot ROM at that location contains ARMv7-A 32-bit
# instructions. This will cause the CPU to almost immediately execute an
# illegal instruction.
#
# This code is idempotent; releasing a released CPU has no effect, although it
# will halt/resume the service processor.
add_help_text release_cpu "Release a cpu which is held off"
proc release_cpu {cpu} {
set RST_BRRL 0x1e60060
set old [target current]
targets $::_CHIPNAME.sp
set not_halted [string compare halted [$::_CHIPNAME.sp curstate]]
if {$not_halted} {
halt
}
# Release the cpu; it will start executing something bogus
mem2array regs 32 $RST_BRRL 1
mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}]
if {$not_halted} {
resume
}
targets $old
}
targets $_CHIPNAME.cpu0

View File

@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Renesas RZ/Five SoC
#
# General-purpose Microprocessors with RISC-V CPU Core (Andes AX45MP Single) (1.0 GHz)
transport select jtag
reset_config trst_and_srst srst_gates_jtag
adapter speed 4000
adapter srst delay 500
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME r9A07g043u
}
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME

View File

@ -6,11 +6,13 @@
# - Each SOC can boot through the Cortex-A5x cores
# Supported RZ/G2 SOCs and their cores:
# RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7
# RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7
# RZ/G2N: Cortex-A57 x2, Cortex-R7
# RZ/G2E: Cortex-A53 x2, Cortex-R7
# RZ/G2L: Cortex-A55 x2, Cortex-M33
# RZ/G2H: Cortex-A57 x4, Cortex-A53 x4, Cortex-R7
# RZ/G2M: Cortex-A57 x2, Cortex-A53 x4, Cortex-R7
# RZ/G2N: Cortex-A57 x2, Cortex-R7
# RZ/G2E: Cortex-A53 x2, Cortex-R7
# RZ/G2L: Cortex-A55 x2, Cortex-M33
# RZ/G2LC: Cortex-A55 x2, Cortex-M33
# RZ/G2UL: Cortex-A55 x1, Cortex-M33
# Usage:
# There are 2 configuration options:
@ -75,6 +77,20 @@ switch $_soc {
set _boot_core CA55
set _ap_num 0
}
G2LC {
set _CHIPNAME r9a07g044c
set _num_ca55 2
set _num_cm33 1
set _boot_core CA55
set _ap_num 0
}
G2UL {
set _CHIPNAME r9a07g043u
set _num_ca55 1
set _num_cm33 1
set _boot_core CA55
set _ap_num 0
}
default {
error "'$_soc' is invalid!"
}
@ -169,7 +185,7 @@ if { $_boot_core == "CA57" } {
echo "SMP targets:$smp_targets"
eval "target smp $smp_targets"
if { $_soc == "G2L"} {
if { $_soc == "G2L" || $_soc == "G2LC" || $_soc == "G2UL" } {
target create $_CHIPNAME.axi_ap mem_ap -dap $_DAPNAME -ap-num 1
}