mirror of
https://github.com/openocd-org/openocd.git
synced 2025-10-14 02:58:23 +08:00
Compare commits
12 Commits
e5888bda38
...
1f5da25ed1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f5da25ed1 | ||
![]() |
7c16c38eda | ||
![]() |
910e6ba2f0 | ||
![]() |
39ed0b0bba | ||
![]() |
6d51e6b900 | ||
![]() |
4805ecad76 | ||
![]() |
382f067b6e | ||
![]() |
34d76b805e | ||
![]() |
5fa74d4ee8 | ||
![]() |
8b43a967e5 | ||
![]() |
04da6e2c62 | ||
![]() |
2abf8daa80 |
5
README
5
README
@@ -191,6 +191,11 @@ and compiling the OpenOCD source code. That file is provided by
|
||||
default for all GNU autotools packages. If you are not familiar with
|
||||
the GNU autotools, then you should read those instructions first.
|
||||
|
||||
Note: if the INSTALL file is not present, it means you are using the
|
||||
source code from a development branch, not from an OpenOCD release.
|
||||
In this case, follow the instructions 'Compiling OpenOCD' below and
|
||||
the file will be created by the first command './bootstrap'.
|
||||
|
||||
The remainder of this document tries to provide some instructions for
|
||||
those looking for a quick-install.
|
||||
|
||||
|
66
configure.ac
66
configure.ac
@@ -69,6 +69,7 @@ AC_CHECK_HEADERS([netdb.h])
|
||||
AC_CHECK_HEADERS([poll.h])
|
||||
AC_CHECK_HEADERS([strings.h])
|
||||
AC_CHECK_HEADERS([sys/ioctl.h])
|
||||
AC_CHECK_HEADERS([sys/mman.h])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
AC_CHECK_HEADERS([sys/select.h])
|
||||
AC_CHECK_HEADERS([sys/stat.h])
|
||||
@@ -129,7 +130,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])])
|
||||
|
||||
m4_define([USB1_ADAPTERS],
|
||||
[[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
|
||||
[[ch347], [Mode 3 of CH347 based devices], [CH347]],
|
||||
[[ch347], [CH347 based devices], [CH347]],
|
||||
[[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]],
|
||||
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
|
||||
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
|
||||
@@ -300,15 +301,15 @@ AS_IF([test "x$debug_malloc" = "xyes" -a "x$have_glibc" = "xyes"], [
|
||||
])
|
||||
|
||||
m4_define([AC_ARG_ADAPTERS], [
|
||||
m4_foreach([adapterTuple], [$1],
|
||||
[AC_ARG_ENABLE(ADAPTER_OPT([adapterTuple]),
|
||||
AS_HELP_STRING([--enable-ADAPTER_OPT([adapterTuple])[[[=yes/no/auto]]]],
|
||||
[Enable building support for the ]ADAPTER_DESC([adapterTuple])[ (default is $2)]),
|
||||
m4_foreach([adapter_driver], [$1],
|
||||
[AC_ARG_ENABLE(ADAPTER_OPT([adapter_driver]),
|
||||
AS_HELP_STRING([--enable-ADAPTER_OPT([adapter_driver])[[[=yes/no/auto]]]],
|
||||
[Enable building support for the ]ADAPTER_DESC([adapter_driver])[ (default is $2)]),
|
||||
[case "${enableval}" in
|
||||
yes|no|auto) ;;
|
||||
*) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapterTuple]) has invalid value "${enableval}".]) ;;
|
||||
*) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapter_driver]) has invalid value "${enableval}".]) ;;
|
||||
esac],
|
||||
[ADAPTER_VAR([adapterTuple])=$2])
|
||||
[ADAPTER_VAR([adapter_driver])=$2])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -356,7 +357,7 @@ AC_ARG_ENABLE([parport_ppdev],
|
||||
|
||||
AC_ARG_ENABLE([parport_giveio],
|
||||
AS_HELP_STRING([--enable-parport-giveio],
|
||||
[Enable use of giveio for parport (for CygWin only)]),
|
||||
[Enable use of giveio for parport (deprecated, for CygWin only)]),
|
||||
[parport_use_giveio=$enableval], [parport_use_giveio=])
|
||||
|
||||
AC_ARG_ENABLE([gw16012],
|
||||
@@ -606,23 +607,24 @@ PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2],
|
||||
# Arg $3: What prerequisites are missing, to be shown in an error message
|
||||
# if an adapter was requested but cannot be enabled.
|
||||
m4_define([PROCESS_ADAPTERS], [
|
||||
m4_foreach([adapterTuple], [$1], [
|
||||
m4_foreach([adapter_driver], [$1], [
|
||||
AS_IF([test $2], [
|
||||
AS_IF([test "x$ADAPTER_VAR([adapterTuple])" != "xno"], [
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapterTuple]), [1],
|
||||
[1 if you want the ]ADAPTER_DESC([adapterTuple]).)
|
||||
AS_IF([test "x$ADAPTER_VAR([adapter_driver])" != "xno"], [
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [1],
|
||||
[1 if you want the ]ADAPTER_DESC([adapter_driver]).)
|
||||
], [
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapterTuple]), [0],
|
||||
[0 if you do not want the ]ADAPTER_DESC([adapterTuple]).)
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0],
|
||||
[0 if you do not want the ]ADAPTER_DESC([adapter_driver]).)
|
||||
])
|
||||
], [
|
||||
AS_IF([test "x$ADAPTER_VAR([adapterTuple])" = "xyes"], [
|
||||
AC_MSG_ERROR([$3 is required for [adapterTuple] "ADAPTER_DESC([adapterTuple])".])
|
||||
AS_IF([test "x$ADAPTER_VAR([adapter_driver])" = "xyes"], [
|
||||
AC_MSG_ERROR([$3 is required for [adapter_driver] "ADAPTER_DESC([adapter_driver])".])
|
||||
])
|
||||
ADAPTER_VAR([adapterTuple])=no
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapterTuple]), [0], [0 if you do not want the ]ADAPTER_DESC([adapterTuple]).)
|
||||
ADAPTER_VAR([adapter_driver])=no
|
||||
AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0],
|
||||
[0 if you do not want the ]ADAPTER_DESC([adapter_driver]).)
|
||||
])
|
||||
AM_CONDITIONAL(ADAPTER_SYM([adapterTuple]), [test "x$ADAPTER_VAR([adapterTuple])" != "xno"])
|
||||
AM_CONDITIONAL(ADAPTER_SYM([adapter_driver]), [test "x$ADAPTER_VAR([adapter_driver])" != "xno"])
|
||||
])
|
||||
])
|
||||
|
||||
@@ -632,12 +634,14 @@ PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libu
|
||||
PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi])
|
||||
PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x])
|
||||
PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpiod])
|
||||
PROCESS_ADAPTERS([DMEM_ADAPTER], ["x$is_linux" = "xyes"], [Linux /dev/mem])
|
||||
PROCESS_ADAPTERS([DMEM_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"], [Linux /dev/mem])
|
||||
PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs])
|
||||
PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused])
|
||||
PROCESS_ADAPTERS([CMSIS_DAP_TCP_ADAPTER], [true], [unused])
|
||||
PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2])
|
||||
PROCESS_ADAPTERS([XVC_ADAPTERS], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes"], [Linux build])
|
||||
PROCESS_ADAPTERS([XVC_ADAPTERS],
|
||||
["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"],
|
||||
[Linux build with headers linux/pci.h and sys/mman.h])
|
||||
PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"],
|
||||
[internal error: validation should happen beforehand])
|
||||
PROCESS_ADAPTERS([PARALLEL_PORT_ADAPTER], [true], [unused])
|
||||
@@ -649,8 +653,8 @@ PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused])
|
||||
PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"],
|
||||
[internal error: validation should happen beforehand])
|
||||
PROCESS_ADAPTERS([AMTJTAGACCEL_ADAPTER], [true], [unused])
|
||||
PROCESS_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS], [true], [unused])
|
||||
PROCESS_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], [true], [unused])
|
||||
PROCESS_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h])
|
||||
PROCESS_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h])
|
||||
PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused])
|
||||
|
||||
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
|
||||
@@ -825,11 +829,17 @@ AS_IF([test "x$build_gw16012" = "xyes"], [
|
||||
AC_MSG_WARN([Gateworks GW16012 JTAG adapter is deprecated and support will be removed in the next release!])
|
||||
])
|
||||
|
||||
AS_IF([test "x$parport_use_giveio" = "xyes" || test [ "x$enable_parport" != "xno" -a "x$parport_use_ppdev" = "xno"]], [
|
||||
echo
|
||||
echo
|
||||
AC_MSG_WARN([Parallel port access with direct I/O is deprecated and support will be removed in the next release!])
|
||||
])
|
||||
|
||||
echo
|
||||
echo
|
||||
echo OpenOCD configuration summary
|
||||
echo ---------------------------------------------------
|
||||
m4_foreach([adapterTuple], [USB1_ADAPTERS,
|
||||
m4_foreach([adapter_driver], [USB1_ADAPTERS,
|
||||
HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS,
|
||||
LIBFTDI_USB1_ADAPTERS,
|
||||
LIBGPIOD_ADAPTERS,
|
||||
@@ -851,8 +861,8 @@ m4_foreach([adapterTuple], [USB1_ADAPTERS,
|
||||
DUMMY_ADAPTER,
|
||||
OPTIONAL_LIBRARIES,
|
||||
COVERAGE],
|
||||
[s=m4_format(["%-49s"], ADAPTER_DESC([adapterTuple]))
|
||||
AS_CASE([$ADAPTER_VAR([adapterTuple])],
|
||||
[s=m4_format(["%-49s"], ADAPTER_DESC([adapter_driver]))
|
||||
AS_CASE([$ADAPTER_VAR([adapter_driver])],
|
||||
[auto], [
|
||||
echo "$s"yes '(auto)'
|
||||
],
|
||||
@@ -864,8 +874,8 @@ m4_foreach([adapterTuple], [USB1_ADAPTERS,
|
||||
],
|
||||
[
|
||||
AC_MSG_ERROR(m4_normalize([
|
||||
Error in [adapterTuple] "ADAPTER_ARG([adapterTuple])": Variable "ADAPTER_VAR([adapterTuple])"
|
||||
has invalid value "$ADAPTER_VAR([adapterTuple])".]))
|
||||
Error in [adapter_driver] "ADAPTER_ARG([adapter_driver])": Variable "ADAPTER_VAR([adapter_driver])"
|
||||
has invalid value "$ADAPTER_VAR([adapter_driver])".]))
|
||||
])
|
||||
])
|
||||
echo
|
||||
|
@@ -2590,6 +2590,9 @@ mitigates the problem.
|
||||
@end itemize
|
||||
@end itemize
|
||||
|
||||
The driver supports activity LED through the generic
|
||||
command @ref{adapter gpio, @command{adapter gpio led}}.
|
||||
|
||||
This driver has these driver-specific command:
|
||||
|
||||
@deffn {Config Command} {ch347 vid_pid} [vid pid]+
|
||||
@@ -2609,17 +2612,6 @@ and product ID will be connected.
|
||||
ch347 device_desc "EasyDevKit"
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {ch347 activity_led} [n]gpio_number
|
||||
If specified the drive let an activity LED blink during JTAG operations.
|
||||
The number is the GPIO number of the CH347T chip. If prefixed with "n",
|
||||
then this GPIO should be low active. The example configures GPIO4 as
|
||||
low active activity LED. For the CH347T chip only GPIO3 (Pin11 / SCL),
|
||||
GPIO4 (Pin15 / ACT), GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible.
|
||||
@example
|
||||
ch347 activity_led n4
|
||||
@end example
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Driver} {cmsis-dap}
|
||||
@@ -3225,14 +3217,16 @@ The pin direction is given in the following table.
|
||||
@tab 2
|
||||
@end multitable
|
||||
|
||||
@deffn {Config Command} {parport port} port_number
|
||||
Configure the number of the parallel port.
|
||||
@deffn {Config Command} {parport port} file
|
||||
Specify the device file of the parallel port device.
|
||||
The parallel port device file is usually @file{/dev/parportX} on Linux and @file{/dev/ppiX} on FreeBSD.
|
||||
|
||||
When using PPDEV to access the parallel port, use the number of the parallel port file @file{/dev/parport} (Linux) or @file{/dev/ppi} (FreeBSD).
|
||||
The default port number is 0.
|
||||
For legacy reason, the port number @var{X} can be specified instead of the device file.
|
||||
@b{Note:} Using the port number is a deprecated feature and will be removed in the future.
|
||||
|
||||
When using direct I/O, the number is the I/O port number.
|
||||
The default port number is 0x378 (LTP1).
|
||||
@b{Note:} Direct I/O support is deprecated and will be removed in the future.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off})
|
||||
@@ -11120,6 +11114,10 @@ Enable or disable trace output for all ITM stimulus ports.
|
||||
@subsection Cortex-M specific commands
|
||||
@cindex Cortex-M
|
||||
|
||||
@deffn {Command} {cortex_m cache_info}
|
||||
Report information about the type and size of the cache, if present.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly})
|
||||
Control masking (disabling) interrupts during target step/resume.
|
||||
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <helper/replacements.h>
|
||||
#include <helper/list.h>
|
||||
@@ -1805,32 +1806,6 @@ COMMAND_HANDLER(ch347_handle_device_desc_command)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The command handler for configuring which GPIO pin is used as activity LED
|
||||
*
|
||||
* @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise
|
||||
*/
|
||||
COMMAND_HANDLER(ch347_handle_activity_led_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
uint8_t gpio;
|
||||
if (CMD_ARGV[0][0] == 'n') {
|
||||
COMMAND_PARSE_NUMBER(u8, &CMD_ARGV[0][1], gpio);
|
||||
ch347_activity_led_active_high = false;
|
||||
} else {
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], gpio);
|
||||
ch347_activity_led_active_high = true;
|
||||
}
|
||||
|
||||
if (gpio >= GPIO_CNT || (BIT(gpio) & USEABLE_GPIOS) == 0)
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
|
||||
ch347_activity_led_gpio_pin = gpio;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration ch347_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "vid_pid",
|
||||
@@ -1846,13 +1821,6 @@ static const struct command_registration ch347_subcommand_handlers[] = {
|
||||
.help = "set the USB device description of the CH347 device",
|
||||
.usage = "description_string",
|
||||
},
|
||||
{
|
||||
.name = "activity_led",
|
||||
.handler = &ch347_handle_activity_led_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "if set this CH347 GPIO pin is the JTAG activity LED; start with n for active low output",
|
||||
.usage = "[n]gpio_number",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
@@ -1867,6 +1835,25 @@ static const struct command_registration ch347_command_handlers[] = {
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Configure which GPIO pin is used as the activity LED.
|
||||
*
|
||||
* Updates the global activity LED GPIO pin and polarity settings
|
||||
* based on the provided configuration. If the given GPIO is not
|
||||
* usable, the function returns without making changes.
|
||||
*
|
||||
* @param led_config Pointer to the GPIO configuration structure for the LED pin
|
||||
*/
|
||||
static void ch347_configure_activity_led(const struct adapter_gpio_config *led_config)
|
||||
{
|
||||
uint8_t gpio = led_config->gpio_num;
|
||||
if (gpio >= GPIO_CNT || (BIT(gpio) & USEABLE_GPIOS) == 0)
|
||||
return;
|
||||
|
||||
ch347_activity_led_gpio_pin = gpio;
|
||||
ch347_activity_led_active_high = !led_config->active_low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CH347 Initialization function
|
||||
*
|
||||
@@ -1893,6 +1880,8 @@ static int ch347_init(void)
|
||||
|
||||
ch347.pack_size = UNSET;
|
||||
|
||||
ch347_configure_activity_led(&adapter_gpio_get_config()[ADAPTER_GPIO_IDX_LED]);
|
||||
|
||||
if (!swd_mode) {
|
||||
tap_set_state(TAP_RESET);
|
||||
} else {
|
||||
|
@@ -47,8 +47,11 @@
|
||||
|
||||
static const struct adapter_gpio_config *adapter_gpio_config;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 0
|
||||
static uint16_t parport_port;
|
||||
#endif
|
||||
static bool parport_write_exit_state;
|
||||
static char *parport_device_file;
|
||||
static uint32_t parport_toggling_time_ns = 1000;
|
||||
static int wait_states;
|
||||
|
||||
@@ -258,13 +261,13 @@ static int parport_init(void)
|
||||
if (gpio.gpio_num < 10 || gpio.gpio_num > 15 || gpio.gpio_num == 14) {
|
||||
LOG_ERROR("The '%s' signal pin must be 10, 11, 12, 13, or 15",
|
||||
adapter_gpio_get_name(gpio_index));
|
||||
return ERROR_FAIL;
|
||||
goto init_fail;
|
||||
}
|
||||
} else {
|
||||
if (gpio.gpio_num < 2 || gpio.gpio_num > 9) {
|
||||
LOG_ERROR("The '%s' signal pin must be 2, 3, 4, 5, 6, 7, 8, or 9",
|
||||
adapter_gpio_get_name(gpio_index));
|
||||
return ERROR_FAIL;
|
||||
goto init_fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,35 +295,37 @@ static int parport_init(void)
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
if (device_handle > 0) {
|
||||
LOG_ERROR("Parallel port is already open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
char device_path[256];
|
||||
|
||||
if (!parport_device_file) {
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
snprintf(device_path, sizeof(device_path), "/dev/ppi%d", parport_port);
|
||||
parport_device_file = strdup("/dev/ppi0");
|
||||
#else
|
||||
snprintf(device_path, sizeof(device_path), "/dev/parport%d", parport_port);
|
||||
#endif /* __FreeBSD__, __FreeBSD_kernel__ */
|
||||
parport_device_file = strdup("/dev/parport0");
|
||||
#endif
|
||||
LOG_WARNING("No parallel port specified, using %s", parport_device_file);
|
||||
LOG_WARNING("DEPRECATED! The lack of a parallel port specification is deprecated and will no longer work in the future");
|
||||
}
|
||||
|
||||
LOG_DEBUG("Using parallel port %s", device_path);
|
||||
LOG_DEBUG("Using parallel port %s", parport_device_file);
|
||||
|
||||
device_handle = open(device_path, O_WRONLY);
|
||||
device_handle = open(parport_device_file, O_WRONLY);
|
||||
|
||||
if (device_handle < 0) {
|
||||
int err = errno;
|
||||
LOG_ERROR("Failed to open parallel port %s (errno = %d)", device_path,
|
||||
err);
|
||||
LOG_ERROR("Failed to open parallel port %s (errno = %d)",
|
||||
parport_device_file, err);
|
||||
LOG_ERROR("Check whether the device exists and if you have the required access rights");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
|
||||
int retval = ioctl(device_handle, PPCLAIM);
|
||||
|
||||
if (retval < 0) {
|
||||
LOG_ERROR("Failed to claim parallel port %s", device_path);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
LOG_ERROR("Failed to claim parallel port %s", parport_device_file);
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
int value = PARPORT_MODE_COMPAT;
|
||||
@@ -328,7 +333,7 @@ static int parport_init(void)
|
||||
|
||||
if (retval < 0) {
|
||||
LOG_ERROR("Cannot set compatible mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
value = IEEE1284_MODE_COMPAT;
|
||||
@@ -336,11 +341,13 @@ static int parport_init(void)
|
||||
|
||||
if (retval < 0) {
|
||||
LOG_ERROR("Cannot set compatible 1284 mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto init_fail;
|
||||
}
|
||||
#endif /* not __FreeBSD__, __FreeBSD_kernel__ */
|
||||
|
||||
#else /* not PARPORT_USE_PPDEV */
|
||||
LOG_WARNING("DEPRECATED: Parallel port access with direct I/O is deprecated and support will be removed in the next release");
|
||||
|
||||
if (!parport_port) {
|
||||
parport_port = 0x378;
|
||||
LOG_WARNING("No parallel port specified, using default 0x378 (LPT1)");
|
||||
@@ -357,7 +364,7 @@ static int parport_init(void)
|
||||
if (ioperm(dataport, 3, 1) != 0) {
|
||||
#endif /* PARPORT_USE_GIVEIO */
|
||||
LOG_ERROR("Missing privileges for direct I/O");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
// Make sure parallel port is in right mode (clear tristate and interrupt).
|
||||
@@ -370,21 +377,27 @@ static int parport_init(void)
|
||||
#endif /* PARPORT_USE_PPDEV */
|
||||
|
||||
if (parport_reset(0, 0) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
goto init_fail;
|
||||
|
||||
if (parport_write(0, 0, 0) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
goto init_fail;
|
||||
|
||||
if (parport_led(true) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
goto init_fail;
|
||||
|
||||
bitbang_interface = &parport_bitbang;
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
init_fail:
|
||||
free(parport_device_file);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
static int parport_quit(void)
|
||||
{
|
||||
free(parport_device_file);
|
||||
|
||||
// Deinitialize signal pin states.
|
||||
for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) {
|
||||
const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index;
|
||||
@@ -419,13 +432,46 @@ COMMAND_HANDLER(parport_handle_port_command)
|
||||
if (CMD_ARGC != 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
// Only if the port wasn't overwritten by command-line.
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
if (parport_device_file) {
|
||||
LOG_ERROR("The parallel port device file is already configured");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
char *tmp;
|
||||
|
||||
// We do not use the parse_xxx() or COMMAND_PARSE_xxx() functions here since
|
||||
// they generate an error message if parsing fails.
|
||||
char *endptr = NULL;
|
||||
unsigned long port_number = strtoul(CMD_ARGV[0], &endptr, 0);
|
||||
|
||||
if (*endptr == '\0' && endptr != CMD_ARGV[0]) {
|
||||
LOG_WARNING("DEPRECATED! Using a port number is deprecated, use the device file instead");
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
tmp = alloc_printf("/dev/ppi%lu", port_number);
|
||||
#else
|
||||
tmp = alloc_printf("/dev/parport%lu", port_number);
|
||||
#endif
|
||||
} else {
|
||||
tmp = strdup(CMD_ARGV[0]);
|
||||
}
|
||||
|
||||
if (!tmp) {
|
||||
LOG_ERROR("Failed to allocate memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
free(parport_device_file);
|
||||
parport_device_file = tmp;
|
||||
#else
|
||||
if (parport_port > 0) {
|
||||
command_print(CMD, "The parallel port is already configured");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port);
|
||||
#endif
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
@@ -487,9 +533,8 @@ static const struct command_registration parport_subcommand_handlers[] = {
|
||||
.name = "port",
|
||||
.handler = parport_handle_port_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Configure the address of the I/O port (e.g. 0x378) "
|
||||
"or the number of the '/dev/parport' (Linux) or '/dev/ppi' (FreeBSD) device used",
|
||||
.usage = "port_number",
|
||||
.help = "Specify the device file of the parallel port",
|
||||
.usage = "file",
|
||||
},
|
||||
{
|
||||
.name = "cable",
|
||||
|
@@ -75,6 +75,7 @@ ARMV6_SRC = \
|
||||
|
||||
ARMV7_SRC = \
|
||||
%D%/armv7m.c \
|
||||
%D%/armv7m_cache.c \
|
||||
%D%/armv7m_trace.c \
|
||||
%D%/cortex_m.c \
|
||||
%D%/armv7a.c \
|
||||
@@ -183,6 +184,7 @@ ARC_SRC = \
|
||||
%D%/armv4_5_cache.h \
|
||||
%D%/armv7a.h \
|
||||
%D%/armv7m.h \
|
||||
%D%/armv7m_cache.h \
|
||||
%D%/armv7m_trace.h \
|
||||
%D%/armv8.h \
|
||||
%D%/armv8_dpm.h \
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#define OPENOCD_TARGET_ARMV7M_H
|
||||
|
||||
#include "arm.h"
|
||||
#include "armv7m_cache.h"
|
||||
#include "armv7m_trace.h"
|
||||
|
||||
struct adiv5_ap;
|
||||
@@ -239,6 +240,8 @@ struct armv7m_common {
|
||||
/* hla_target uses a high level adapter that does not support all functions */
|
||||
bool is_hla_target;
|
||||
|
||||
struct armv7m_cache_common armv7m_cache;
|
||||
|
||||
struct armv7m_trace_config trace_config;
|
||||
|
||||
/* Direct processor core register read and writes */
|
||||
|
284
src/target/armv7m_cache.c
Normal file
284
src/target/armv7m_cache.c
Normal file
@@ -0,0 +1,284 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
/*
|
||||
* Copyright (C) 2025 by STMicroelectronics
|
||||
* Copyright (C) 2025 by Antonio Borneo <borneo.antonio@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <helper/align.h>
|
||||
#include <helper/bitfield.h>
|
||||
#include <helper/bits.h>
|
||||
#include <helper/command.h>
|
||||
#include <helper/log.h>
|
||||
#include <helper/types.h>
|
||||
#include <target/arm_adi_v5.h>
|
||||
#include <target/armv7m_cache.h>
|
||||
#include <target/cortex_m.h>
|
||||
|
||||
static int get_cache_info(struct adiv5_ap *ap, unsigned int cl,
|
||||
unsigned int ind, uint32_t *ccsidr)
|
||||
{
|
||||
uint32_t csselr = FIELD_PREP(CSSELR_LEVEL_MASK, cl)
|
||||
| FIELD_PREP(CSSELR_IND_MASK, ind);
|
||||
|
||||
int retval = mem_ap_write_u32(ap, CSSELR, csselr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return mem_ap_read_u32(ap, CCSIDR, ccsidr);
|
||||
}
|
||||
|
||||
static int get_d_u_cache_info(struct adiv5_ap *ap, unsigned int cl,
|
||||
uint32_t *ccsidr)
|
||||
{
|
||||
return get_cache_info(ap, cl, CSSELR_IND_DATA_OR_UNIFIED_CACHE, ccsidr);
|
||||
}
|
||||
|
||||
static int get_i_cache_info(struct adiv5_ap *ap, unsigned int cl,
|
||||
uint32_t *ccsidr)
|
||||
{
|
||||
return get_cache_info(ap, cl, CSSELR_IND_INSTRUCTION_CACHE, ccsidr);
|
||||
}
|
||||
|
||||
static struct armv7m_cache_size decode_ccsidr(uint32_t ccsidr)
|
||||
{
|
||||
struct armv7m_cache_size size;
|
||||
|
||||
size.line_len = 16 << FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr);
|
||||
size.associativity = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr) + 1;
|
||||
size.num_sets = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr) + 1;
|
||||
size.cache_size = size.line_len * size.associativity * size.num_sets / 1024;
|
||||
|
||||
// compute info for set way operation on cache
|
||||
size.index_shift = FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr) + 2;
|
||||
size.index = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr);
|
||||
size.way = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr);
|
||||
|
||||
unsigned int i = 0;
|
||||
while (((size.way << i) & 0x80000000) == 0)
|
||||
i++;
|
||||
size.way_shift = i;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int armv7m_identify_cache(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
uint32_t clidr;
|
||||
int retval = mem_ap_read_u32(armv7m->debug_ap, CLIDR, &clidr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t ctr;
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, CTR, &ctr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
// retrieve selected cache for later restore
|
||||
uint32_t csselr;
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, CSSELR, &csselr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (clidr == 0) {
|
||||
LOG_TARGET_DEBUG(target, "No cache detected");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (FIELD_GET(CTR_FORMAT_MASK, ctr) != CTR_FORMAT_PROVIDED) {
|
||||
LOG_ERROR("Wrong value in CTR register");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
cache->i_min_line_len = 4UL << FIELD_GET(CTR_IMINLINE_MASK, ctr);
|
||||
cache->d_min_line_len = 4UL << FIELD_GET(CTR_DMINLINE_MASK, ctr);
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"ctr=0x%" PRIx32 " ctr.i_min_line_len=%" PRIu32 " ctr.d_min_line_len=%" PRIu32,
|
||||
ctr, cache->i_min_line_len, cache->d_min_line_len);
|
||||
|
||||
cache->loc = FIELD_GET(CLIDR_LOC_MASK, clidr);
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"clidr=0x%" PRIx32 " Number of cache levels to PoC=%" PRIu32,
|
||||
clidr, cache->loc);
|
||||
|
||||
// retrieve all available inner caches
|
||||
uint32_t d_u_ccsidr[8], i_ccsidr[8];
|
||||
for (unsigned int cl = 0; cl < cache->loc; cl++) {
|
||||
unsigned int ctype = FIELD_GET(CLIDR_CTYPE_MASK(cl + 1), clidr);
|
||||
|
||||
// skip reserved values
|
||||
if (ctype > CLIDR_CTYPE_UNIFIED_CACHE)
|
||||
continue;
|
||||
|
||||
cache->arch[cl].ctype = ctype;
|
||||
|
||||
// separate d or unified d/i cache at this level ?
|
||||
if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) {
|
||||
// retrieve d-cache info
|
||||
retval = get_d_u_cache_info(armv7m->debug_ap, cl, &d_u_ccsidr[cl]);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctype & CLIDR_CTYPE_I_CACHE) {
|
||||
// retrieve i-cache info
|
||||
retval = get_i_cache_info(armv7m->debug_ap, cl, &i_ccsidr[cl]);
|
||||
if (retval != ERROR_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// restore selected cache
|
||||
int retval1 = mem_ap_write_atomic_u32(armv7m->debug_ap, CSSELR, csselr);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (retval1 != ERROR_OK)
|
||||
return retval1;
|
||||
|
||||
for (unsigned int cl = 0; cl < cache->loc; cl++) {
|
||||
unsigned int ctype = cache->arch[cl].ctype;
|
||||
|
||||
// separate d or unified d/i cache at this level ?
|
||||
if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) {
|
||||
cache->has_d_u_cache = true;
|
||||
cache->arch[cl].d_u_size = decode_ccsidr(d_u_ccsidr[cl]);
|
||||
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
|
||||
cache->arch[cl].d_u_size.index,
|
||||
cache->arch[cl].d_u_size.index_shift,
|
||||
cache->arch[cl].d_u_size.way,
|
||||
cache->arch[cl].d_u_size.way_shift);
|
||||
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
|
||||
cache->arch[cl].d_u_size.line_len,
|
||||
cache->arch[cl].d_u_size.cache_size,
|
||||
cache->arch[cl].d_u_size.associativity);
|
||||
}
|
||||
|
||||
if (ctype & CLIDR_CTYPE_I_CACHE) {
|
||||
cache->has_i_cache = true;
|
||||
cache->arch[cl].i_size = decode_ccsidr(i_ccsidr[cl]);
|
||||
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32,
|
||||
cache->arch[cl].i_size.index,
|
||||
cache->arch[cl].i_size.index_shift,
|
||||
cache->arch[cl].i_size.way,
|
||||
cache->arch[cl].i_size.way_shift);
|
||||
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways",
|
||||
cache->arch[cl].i_size.line_len,
|
||||
cache->arch[cl].i_size.cache_size,
|
||||
cache->arch[cl].i_size.associativity);
|
||||
}
|
||||
}
|
||||
|
||||
cache->info_valid = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int armv7m_d_cache_flush(struct target *target, uint32_t address,
|
||||
unsigned int length)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
if (!cache->info_valid || !cache->has_d_u_cache)
|
||||
return ERROR_OK;
|
||||
|
||||
uint32_t line_len = cache->d_min_line_len;
|
||||
uint32_t addr_line = ALIGN_DOWN(address, line_len);
|
||||
uint32_t addr_end = address + length;
|
||||
|
||||
while (addr_line < addr_end) {
|
||||
int retval = mem_ap_write_u32(armv7m->debug_ap, DCCIMVAC, addr_line);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
addr_line += line_len;
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
return dap_run(armv7m->debug_ap->dap);
|
||||
}
|
||||
|
||||
int armv7m_i_cache_inval(struct target *target, uint32_t address,
|
||||
unsigned int length)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
if (!cache->info_valid || !cache->has_i_cache)
|
||||
return ERROR_OK;
|
||||
|
||||
uint32_t line_len = cache->i_min_line_len;
|
||||
uint32_t addr_line = ALIGN_DOWN(address, line_len);
|
||||
uint32_t addr_end = address + length;
|
||||
|
||||
while (addr_line < addr_end) {
|
||||
int retval = mem_ap_write_u32(armv7m->debug_ap, ICIMVAU, addr_line);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
addr_line += line_len;
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
return dap_run(armv7m->debug_ap->dap);
|
||||
}
|
||||
|
||||
int armv7m_handle_cache_info_command(struct command_invocation *cmd,
|
||||
struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
command_print(cmd, "Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!cache->info_valid) {
|
||||
command_print(cmd, "No cache detected");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
for (unsigned int cl = 0; cl < cache->loc; cl++) {
|
||||
struct armv7m_arch_cache *arch = &cache->arch[cl];
|
||||
|
||||
if (arch->ctype & CLIDR_CTYPE_I_CACHE)
|
||||
command_print(cmd,
|
||||
"L%d I-Cache: line length %" PRIu32 ", associativity %" PRIu32
|
||||
", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes",
|
||||
cl + 1,
|
||||
arch->i_size.line_len,
|
||||
arch->i_size.associativity,
|
||||
arch->i_size.num_sets,
|
||||
arch->i_size.cache_size);
|
||||
|
||||
if (arch->ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE))
|
||||
command_print(cmd,
|
||||
"L%d %c-Cache: line length %" PRIu32 ", associativity %" PRIu32
|
||||
", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes",
|
||||
cl + 1,
|
||||
(arch->ctype & CLIDR_CTYPE_D_CACHE) ? 'D' : 'U',
|
||||
arch->d_u_size.line_len,
|
||||
arch->d_u_size.associativity,
|
||||
arch->d_u_size.num_sets,
|
||||
arch->d_u_size.cache_size);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
57
src/target/armv7m_cache.h
Normal file
57
src/target/armv7m_cache.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2025 by STMicroelectronics
|
||||
* Copyright (C) 2025 by Antonio Borneo <borneo.antonio@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef OPENOCD_TARGET_ARMV7M_CACHE_H
|
||||
#define OPENOCD_TARGET_ARMV7M_CACHE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <helper/types.h>
|
||||
|
||||
struct target;
|
||||
|
||||
struct armv7m_cache_size {
|
||||
// cache dimensioning
|
||||
uint32_t line_len;
|
||||
uint32_t associativity;
|
||||
uint32_t num_sets;
|
||||
uint32_t cache_size;
|
||||
// info for set way operation on cache
|
||||
uint32_t index;
|
||||
uint32_t index_shift;
|
||||
uint32_t way;
|
||||
uint32_t way_shift;
|
||||
};
|
||||
|
||||
// information about one architecture cache at any level
|
||||
struct armv7m_arch_cache {
|
||||
unsigned int ctype; // cache type, CLIDR encoding
|
||||
struct armv7m_cache_size d_u_size; // data cache
|
||||
struct armv7m_cache_size i_size; // instruction cache
|
||||
};
|
||||
|
||||
// common cache information
|
||||
struct armv7m_cache_common {
|
||||
bool info_valid;
|
||||
bool has_i_cache;
|
||||
bool has_d_u_cache;
|
||||
unsigned int loc; // level of coherency
|
||||
uint32_t d_min_line_len; // minimum d-cache line_len
|
||||
uint32_t i_min_line_len; // minimum i-cache line_len
|
||||
struct armv7m_arch_cache arch[6]; // cache info, L1 - L7
|
||||
};
|
||||
|
||||
int armv7m_identify_cache(struct target *target);
|
||||
int armv7m_d_cache_flush(struct target *target, uint32_t address,
|
||||
unsigned int length);
|
||||
int armv7m_i_cache_inval(struct target *target, uint32_t address,
|
||||
unsigned int length);
|
||||
int armv7m_handle_cache_info_command(struct command_invocation *cmd,
|
||||
struct target *target);
|
||||
|
||||
#endif /* OPENOCD_TARGET_ARMV7M_CACHE_H */
|
@@ -21,6 +21,7 @@
|
||||
#include "jtag/interface.h"
|
||||
#include "breakpoints.h"
|
||||
#include "cortex_m.h"
|
||||
#include "armv7m_cache.h"
|
||||
#include "target_request.h"
|
||||
#include "target_type.h"
|
||||
#include "arm_adi_v5.h"
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "arm_semihosting.h"
|
||||
#include "smp.h"
|
||||
#include <helper/nvp.h>
|
||||
#include <helper/string_choices.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <rtt/rtt.h>
|
||||
|
||||
@@ -873,6 +875,14 @@ static int cortex_m_debug_entry(struct target *target)
|
||||
return retval;
|
||||
}
|
||||
|
||||
// read caches state
|
||||
uint32_t ccr = 0;
|
||||
if (armv7m->armv7m_cache.info_valid) {
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, CCR, &ccr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Load all registers to arm.core_cache */
|
||||
if (!cortex_m->slow_register_read) {
|
||||
retval = cortex_m_fast_read_all_regs(target);
|
||||
@@ -926,6 +936,11 @@ static int cortex_m_debug_entry(struct target *target)
|
||||
secure_state ? "Secure" : "Non-Secure",
|
||||
target_state_name(target));
|
||||
|
||||
if (armv7m->armv7m_cache.info_valid)
|
||||
LOG_TARGET_DEBUG(target, "D-Cache %s, I-Cache %s",
|
||||
str_enabled_disabled(ccr & CCR_DC_MASK),
|
||||
str_enabled_disabled(ccr & CCR_IC_MASK));
|
||||
|
||||
/* Errata 3092511 workaround
|
||||
* Cortex-M7 can halt in an incorrect address when breakpoint
|
||||
* and exception occurs simultaneously */
|
||||
@@ -1938,12 +1953,25 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
|
||||
breakpoint->orig_instr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
// make sure data cache is cleaned & invalidated down to PoC
|
||||
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = target_write_memory(target,
|
||||
breakpoint->address & 0xFFFFFFFE,
|
||||
breakpoint->length, 1,
|
||||
code);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
// update i-cache at breakpoint location
|
||||
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
breakpoint->is_set = true;
|
||||
}
|
||||
|
||||
@@ -1986,12 +2014,25 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
|
||||
target_write_u32(target, comparator_list[fp_num].fpcr_address,
|
||||
comparator_list[fp_num].fpcr_value);
|
||||
} else {
|
||||
// make sure data cache is cleaned & invalidated down to PoC
|
||||
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* restore original instruction (kept in target endianness) */
|
||||
retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE,
|
||||
breakpoint->length, 1,
|
||||
breakpoint->orig_instr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
// update i-cache at breakpoint location
|
||||
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
breakpoint->is_set = false;
|
||||
|
||||
@@ -2000,6 +2041,15 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
|
||||
|
||||
int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
|
||||
{
|
||||
/*
|
||||
* GDB packets Z0 and z0 provide the 'kind' parameter that is target-specific
|
||||
* and typically indicates the size in bytes of the breakpoint.
|
||||
* But for 32-bit Thumb mode (Thumb-2) breakpoint, GDB provides 'kind = 3' to
|
||||
* be used to derive the length information. See:
|
||||
* https://sourceware.org/gdb/current/onlinedocs/gdb.html/ARM-Breakpoint-Kinds.html
|
||||
* Since there isn't a four byte Thumb-2 breakpoint instruction, always use
|
||||
* the two bytes breakpoint instruction.
|
||||
*/
|
||||
if (breakpoint->length == 3) {
|
||||
LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request");
|
||||
breakpoint->length = 2;
|
||||
@@ -2906,6 +2956,12 @@ int cortex_m_examine(struct target *target)
|
||||
LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints",
|
||||
cortex_m->fp_num_code,
|
||||
cortex_m->dwt_num_comp);
|
||||
|
||||
retval = armv7m_identify_cache(target);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Cannot detect cache");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
@@ -3194,47 +3250,60 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
int retval;
|
||||
char *reset_config;
|
||||
|
||||
retval = cortex_m_verify_pointer(CMD, cortex_m);
|
||||
int retval = cortex_m_verify_pointer(CMD, cortex_m);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (CMD_ARGC > 0) {
|
||||
if (strcmp(*CMD_ARGV, "sysresetreq") == 0)
|
||||
cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ;
|
||||
if (!CMD_ARGC) {
|
||||
char *reset_config;
|
||||
|
||||
else if (strcmp(*CMD_ARGV, "vectreset") == 0) {
|
||||
if (target_was_examined(target)
|
||||
&& !cortex_m->vectreset_supported)
|
||||
LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!");
|
||||
else
|
||||
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
|
||||
switch (cortex_m->soft_reset_config) {
|
||||
case CORTEX_M_RESET_SYSRESETREQ:
|
||||
reset_config = "sysresetreq";
|
||||
break;
|
||||
|
||||
} else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
case CORTEX_M_RESET_VECTRESET:
|
||||
reset_config = "vectreset";
|
||||
break;
|
||||
|
||||
default:
|
||||
reset_config = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
command_print(CMD, "%s", reset_config);
|
||||
return ERROR_OK;
|
||||
} else if (CMD_ARGC != 1) {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
switch (cortex_m->soft_reset_config) {
|
||||
case CORTEX_M_RESET_SYSRESETREQ:
|
||||
reset_config = "sysresetreq";
|
||||
break;
|
||||
|
||||
case CORTEX_M_RESET_VECTRESET:
|
||||
reset_config = "vectreset";
|
||||
break;
|
||||
|
||||
default:
|
||||
reset_config = "unknown";
|
||||
break;
|
||||
if (!strcmp(CMD_ARGV[0], "sysresetreq")) {
|
||||
cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ;
|
||||
} else if (!strcmp(CMD_ARGV[0], "vectreset")) {
|
||||
if (target_was_examined(target)
|
||||
&& !cortex_m->vectreset_supported)
|
||||
LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core");
|
||||
else
|
||||
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
|
||||
} else {
|
||||
command_print(CMD, "invalid reset config '%s'", CMD_ARGV[0]);
|
||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||
}
|
||||
|
||||
command_print(CMD, "cortex_m reset_config %s", reset_config);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_cortex_m_cache_info_command)
|
||||
{
|
||||
if (CMD_ARGC)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
return armv7m_handle_cache_info_command(CMD, target);
|
||||
}
|
||||
|
||||
static const struct command_registration cortex_m_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "maskisr",
|
||||
@@ -3257,6 +3326,13 @@ static const struct command_registration cortex_m_exec_command_handlers[] = {
|
||||
.help = "configure software reset handling",
|
||||
.usage = "['sysresetreq'|'vectreset']",
|
||||
},
|
||||
{
|
||||
.name = "cache_info",
|
||||
.handler = handle_cortex_m_cache_info_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.help = "display information about target caches",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.chain = smp_command_handlers,
|
||||
},
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#define OPENOCD_TARGET_CORTEX_M_H
|
||||
|
||||
#include "armv7m.h"
|
||||
#include "helper/bitfield.h"
|
||||
#include "helper/bits.h"
|
||||
|
||||
#define CORTEX_M_COMMON_MAGIC 0x1A451A45U
|
||||
@@ -114,6 +115,45 @@ struct cortex_m_part_info {
|
||||
#define FPU_FPCAR 0xE000EF38
|
||||
#define FPU_FPDSCR 0xE000EF3C
|
||||
|
||||
// Cache
|
||||
#define CCR 0xE000ED14
|
||||
#define CLIDR 0xE000ED78
|
||||
#define CTR 0xE000ED7C
|
||||
#define CCSIDR 0xE000ED80
|
||||
#define CSSELR 0xE000ED84
|
||||
#define ICIMVAU 0xE000EF58
|
||||
#define DCCIMVAC 0xE000EF70
|
||||
|
||||
#define CCR_IC_MASK BIT(17)
|
||||
#define CCR_DC_MASK BIT(16)
|
||||
|
||||
#define CLIDR_ICB_MASK GENMASK(31, 30)
|
||||
#define CLIDR_LOUU_MASK GENMASK(29, 27)
|
||||
#define CLIDR_LOC_MASK GENMASK(26, 24)
|
||||
#define CLIDR_LOUIS_MASK GENMASK(23, 21)
|
||||
#define CLIDR_CTYPE_MASK(i) (GENMASK(2, 0) << (3 * (i) - 3))
|
||||
|
||||
#define CLIDR_CTYPE_I_CACHE BIT(0)
|
||||
#define CLIDR_CTYPE_D_CACHE BIT(1)
|
||||
#define CLIDR_CTYPE_UNIFIED_CACHE BIT(2)
|
||||
|
||||
#define CTR_FORMAT_MASK GENMASK(31, 29)
|
||||
#define CTR_CWG_MASK GENMASK(27, 24)
|
||||
#define CTR_ERG_MASK GENMASK(23, 20)
|
||||
#define CTR_DMINLINE_MASK GENMASK(19, 16)
|
||||
#define CTR_IMINLINE_MASK GENMASK(3, 0)
|
||||
|
||||
#define CTR_FORMAT_PROVIDED 0x04
|
||||
|
||||
#define CCSIDR_NUMSETS_MASK GENMASK(27, 13)
|
||||
#define CCSIDR_ASSOCIATIVITY_MASK GENMASK(12, 3)
|
||||
#define CCSIDR_LINESIZE_MASK GENMASK(2, 0)
|
||||
|
||||
#define CSSELR_LEVEL_MASK GENMASK(3, 1)
|
||||
#define CSSELR_IND_MASK BIT(0)
|
||||
#define CSSELR_IND_DATA_OR_UNIFIED_CACHE 0
|
||||
#define CSSELR_IND_INSTRUCTION_CACHE 1
|
||||
|
||||
#define TPIU_SSPSR 0xE0040000
|
||||
#define TPIU_CSPSR 0xE0040004
|
||||
#define TPIU_ACPR 0xE0040010
|
||||
|
37
tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg
Normal file
37
tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg
Normal file
@@ -0,0 +1,37 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E FTDI JTAG DevKit.
|
||||
#
|
||||
# For example, OpenOCD can be started for ESP32 debugging on
|
||||
#
|
||||
# openocd -f board/esp32-wrover-e-ftdi-jtag-devkit.cfg
|
||||
#
|
||||
|
||||
# Select the FTDI JTAG driver
|
||||
adapter driver ftdi
|
||||
|
||||
# Identify the device
|
||||
ftdi device_desc "EasyDevKit"
|
||||
ftdi vid_pid 0x0403 0x6010
|
||||
# interface 0 is JTAG; interface 1 is the uart
|
||||
ftdi channel 0
|
||||
|
||||
# TCK, TDI, TDO, TMS: ADBUS0-3
|
||||
# activity LED: ADBUS4
|
||||
ftdi layout_init 0x0008 0x001b
|
||||
ftdi layout_signal LED -data 0x0010
|
||||
|
||||
# Source the ESP32 configuration file
|
||||
source [find target/esp32.cfg]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# JTAG speed (in kHz)
|
||||
#
|
||||
# If you encounter DSR/DIR errors that are not caused by OpenOCD
|
||||
# attempting to read unmapped memory regions, try lowering this value.
|
||||
#
|
||||
# Recommended settings for EasyDevKits:
|
||||
# - Do not exceed 20 MHz.
|
||||
# - Best results are typically achieved at 20 MHz.
|
||||
# ---------------------------------------------------------------------------
|
||||
adapter speed 20000
|
37
tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg
Normal file
37
tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg
Normal file
@@ -0,0 +1,37 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E WCH JTAG DevKit.
|
||||
#
|
||||
# For example, OpenOCD can be started for ESP32 debugging on
|
||||
#
|
||||
# openocd -f board/esp32-wrover-e-wch-jtag-devkit.cfg
|
||||
#
|
||||
|
||||
# Select the CH347 JTAG driver
|
||||
adapter driver ch347
|
||||
|
||||
# Identify the device
|
||||
ch347 device_desc "EasyDevKit"
|
||||
ch347 vid_pid 0x1a86 0x55dd
|
||||
|
||||
# Configure activity LED
|
||||
# Note: The LED is active-low on GPIO4.
|
||||
adapter gpio led 4 -active-low
|
||||
|
||||
# Source the ESP32 configuration file
|
||||
source [find target/esp32.cfg]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# JTAG speed (in kHz)
|
||||
#
|
||||
# If you encounter DSR/DIR errors that are not caused by OpenOCD
|
||||
# attempting to read unmapped memory regions, try lowering this value.
|
||||
#
|
||||
# Recommended settings for EasyDevKits:
|
||||
# - Do not exceed 30 MHz.
|
||||
# - Best results are typically achieved at 15 MHz.
|
||||
#
|
||||
# Supported frequencies (kHz):
|
||||
# 469, 938, 1875, 3750, 7500, 15000, 30000, 60000
|
||||
# ---------------------------------------------------------------------------
|
||||
adapter speed 15000
|
@@ -20,4 +20,6 @@ set _file_renaming {
|
||||
board/stm32mp13x_dk.cfg board/st/stm32mp135f-dk.cfg
|
||||
board/stm32mp15x_dk2.cfg board/st/stm32mp157f-dk2.cfg
|
||||
board/sifive-hifive1-revb.cfg board/sifive/hifive1-rev-b.cfg
|
||||
interface/chameleon.cfg interface/parport/chameleon.cfg
|
||||
interface/flashlink.cfg interface/parport/flashlink.cfg
|
||||
}
|
||||
|
@@ -1,10 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#
|
||||
# Amontec Chameleon POD
|
||||
#
|
||||
# http://www.amontec.com/chameleon.shtml
|
||||
#
|
||||
|
||||
adapter driver parport
|
||||
parport cable chameleon
|
@@ -1,18 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#
|
||||
# ST FlashLINK JTAG parallel cable
|
||||
#
|
||||
# http://www.st.com/internet/evalboard/product/94023.jsp
|
||||
# http://www.st.com/stonline/products/literature/um/7889.pdf
|
||||
#
|
||||
|
||||
if { [info exists PARPORTADDR] } {
|
||||
set _PARPORTADDR $PARPORTADDR
|
||||
} else {
|
||||
set _PARPORTADDR 0
|
||||
}
|
||||
|
||||
adapter driver parport
|
||||
parport port $_PARPORTADDR
|
||||
parport cable flashlink
|
145
tcl/target/bl616.cfg
Normal file
145
tcl/target/bl616.cfg
Normal file
@@ -0,0 +1,145 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Author: Marek Kraus <gamelaster@gami.ee>
|
||||
|
||||
#
|
||||
# Bouffalo Labs BL616 and BL618 target
|
||||
#
|
||||
# Default JTAG pins: (if not changed by eFuse configuration)
|
||||
# TMS - GPIO0
|
||||
# TCK - GPIO1
|
||||
# TDO - GPIO2
|
||||
# TDI - GPIO3
|
||||
#
|
||||
|
||||
source [find mem_helper.tcl]
|
||||
|
||||
transport select jtag
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME bl616
|
||||
}
|
||||
|
||||
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000b6f
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
|
||||
|
||||
riscv set_mem_access progbuf
|
||||
riscv set_enable_virt2phys off
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x10000 -work-area-backup 1
|
||||
|
||||
adapter speed 4000
|
||||
|
||||
# Useful functions
|
||||
set dmcontrol 0x10
|
||||
set dmcontrol_dmactive [expr {1 << 0}]
|
||||
set dmcontrol_haltreq [expr {1 << 31}]
|
||||
|
||||
# By spec, ndmreset should reset whole chip. This implementation resets only few parts of the chip.
|
||||
# CTRL_PWRON_RESET register in GLB core triggers full "power-on like" reset, so we use it instead
|
||||
# for full software reset.
|
||||
$_TARGETNAME configure -event reset-assert {
|
||||
halt
|
||||
|
||||
# To stay in BootROM until JTAG re-attaches, we are using BootROM functionality
|
||||
# to force ISP mode, so BootROM looks out for external ISP communication.
|
||||
|
||||
# In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4)
|
||||
# and HBN_USER_BOOT_SEL to 1 (ISP)
|
||||
mww 0x2000f108 0x44000000
|
||||
|
||||
# Switch clock to internal RC32M
|
||||
# In HBN_GLB, set ROOT_CLK_SEL = 0
|
||||
mmw 0x2000f030 0x0 0x00000002
|
||||
|
||||
# In GLB_SYS_CFG0, set REG_BCLK_DIV and REG_HCLK_DIV = 0
|
||||
mmw 0x20000090 0x0 0x00FFFF00
|
||||
|
||||
# Trigger BCLK ACT pulse
|
||||
# In GLB_SYS_CFG1, set BCLK_DIV_ACT_PULSE = 1
|
||||
mmw 0x20000094 0x1 0x00000001
|
||||
# In GLB_SYS_CFG1, wait for GLB_STS_BCLK_PROT_DONE to become 1
|
||||
while { [expr {[mrw 0x20000094] & 4}] == 0 } { sleep 1 }
|
||||
|
||||
# In GLB_SWRST_CFG2, clear CTRL_PWRON_RESET
|
||||
mmw 0x20000548 0x0 0x00000001
|
||||
|
||||
# This Software reset method resets everything, so CPU as well.
|
||||
# It does that in not much good way, resulting in Debug Module being reset as well.
|
||||
# This also means, that right after CPU and Debug Module are turned on, we need to
|
||||
# enable Debug Module and halt CPU if needed. Additionally, we trigger this SW reset
|
||||
# through program buffer access directly with DMI commands, to avoid errors printed by
|
||||
# OpenOCD about unsuccessful register write.
|
||||
|
||||
# In GLB_SWRST_CFG2, set CTRL_PWRON_RESET to 1
|
||||
set_reg {fp 0x20000548 s1 0x01}
|
||||
riscv dmi_write 0x20 0x00942023
|
||||
riscv dmi_write 0x17 0x40000
|
||||
|
||||
# We need to wait for chip to finish reset and execute BootROM
|
||||
sleep 10
|
||||
|
||||
# JTAG Debug Transport Module is reset as well, so we need to get into RUN/IDLE state
|
||||
runtest 10
|
||||
|
||||
# We need to enable Debug Module and halt the CPU, so we can reset Program Counter
|
||||
# and to do additional clean-ups. If reset was called without halt, resume is handled
|
||||
# by reset-deassert-post event handler.
|
||||
|
||||
# In Debug Module Control (dmcontrol), set dmactive to 1 and then haltreq to 1
|
||||
riscv dmi_write $::dmcontrol $::dmcontrol_dmactive
|
||||
riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_haltreq} ]
|
||||
}
|
||||
|
||||
$_TARGETNAME configure -event reset-deassert-post {
|
||||
# Set Program Counter to start of BootROM and execute one instruction
|
||||
step 0x90000000
|
||||
|
||||
# When using default JTAG pinout, BOOT pin is the same as JTAG TDO pin.
|
||||
# Since after reset we set PC to start of the BootROM,
|
||||
# BootROM will execute also check of BOOT pin, which will disable TDO pin,
|
||||
# to check the BOOT pin state. This leads to temporary loss of JTAG access
|
||||
# and causes (recoverable) errors in OpenOCD. We can bypass the BOOT pin check
|
||||
# function, by forcing booting from Media/SPI Flash.
|
||||
|
||||
# In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4)
|
||||
# and HBN_USER_BOOT_SEL to 2 (Media/SPI Flash)
|
||||
mww 0x2000f108 0x48000000
|
||||
|
||||
# Resume the processor if reset was triggered without halt request
|
||||
if {$halt == 0} {
|
||||
resume
|
||||
}
|
||||
}
|
||||
|
||||
# According to JTAG spec (IEEE 1149.1), when chip enters "Test-Logic-Reset" state,
|
||||
# the IR instruction should be set to "IDCODE" or "BYPASS" (when chip does not have IDCODE).
|
||||
# This is done so automatic chain scan can detect all the chips within JTAG chain without knowing IDCODE.
|
||||
# JTAG Debug Transport Module (DTM) used in this chip, developed by T-Head (formerly C-Sky)
|
||||
# does not implement this, so OpenOCD can't detect the chip anymore after the IR instruction is changed.
|
||||
# This workaround gets chip into known state, and manually set IR instruction to IDCODE,
|
||||
# which is 0x01, standardized by RISC-V Debug Specification.
|
||||
proc init_reset { mode } {
|
||||
if {[using_jtag]} {
|
||||
# Get JTAG SM to known state
|
||||
runtest 10
|
||||
# Set IR to IDCODE
|
||||
irscan $::_CHIPNAME.cpu 0x01
|
||||
jtag arp_init-reset
|
||||
}
|
||||
}
|
||||
|
||||
proc jtag_init {} {
|
||||
# Get JTAG SM to known state
|
||||
runtest 10
|
||||
# Set IR to IDCODE
|
||||
irscan $::_CHIPNAME.cpu 0x01
|
||||
|
||||
if {[catch {jtag arp_init} err]!=0} {
|
||||
# try resetting additionally
|
||||
init_reset startup
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user