Merge commit '9f23a1d7c1e27c556ef9787b9d3f263f5c1ecf24' into from_upstream
Conflicts: HACKING src/target/riscv/riscv-013.c Change-Id: I43ccb143cae8daa39212d66a8824ae3ad2af6fef
This commit is contained in:
commit
f02fe0960c
15
HACKING
15
HACKING
|
@ -103,6 +103,21 @@ patch:
|
||||||
Now every time OpenOCD is run, coverage info in your build directory is
|
Now every time OpenOCD is run, coverage info in your build directory is
|
||||||
updated. Running `gcov src/path/file.c` will generate a report.
|
updated. Running `gcov src/path/file.c` will generate a report.
|
||||||
|
|
||||||
|
- Sparse Static Analyzer
|
||||||
|
|
||||||
|
Using this tool allows identifying some bug in C code.
|
||||||
|
In the future, OpenOCD would use the sparse attribute 'bitwise' to
|
||||||
|
detect incorrect endianness assignments.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
@code
|
||||||
|
mkdir build-sparse; cd build-sparse
|
||||||
|
../configure CC=cgcc CFLAGS="-Wsparse-all -Wno-declaration-after-statement \
|
||||||
|
-Wno-unknown-attribute -Wno-transparent-union -Wno-tautological-compare \
|
||||||
|
-Wno-vla -Wno-flexible-array-array -D__FLT_EVAL_METHOD__=0"
|
||||||
|
make
|
||||||
|
@endcode
|
||||||
|
|
||||||
Please consider performing these additional checks where appropriate
|
Please consider performing these additional checks where appropriate
|
||||||
(especially Clang Static Analyzer for big portions of new code) and
|
(especially Clang Static Analyzer for big portions of new code) and
|
||||||
mention the results (e.g. "Valgrind-clean, no new Clang analyzer
|
mention the results (e.g. "Valgrind-clean, no new Clang analyzer
|
||||||
|
|
165
doc/openocd.texi
165
doc/openocd.texi
|
@ -3322,15 +3322,32 @@ GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is
|
||||||
handled by the generic command @ref{adapter gpio, @command{adapter gpio}}.
|
handled by the generic command @ref{adapter gpio, @command{adapter gpio}}.
|
||||||
|
|
||||||
See @file{interface/raspberrypi-native.cfg} for a sample config and
|
See @file{interface/raspberrypi-native.cfg} for a sample config and
|
||||||
pinout.
|
@file{interface/raspberrypi-gpio-connector.cfg} for pinout.
|
||||||
|
|
||||||
@deffn {Config Command} {bcm2835gpio speed_coeffs} @var{speed_coeff} @var{speed_offset}
|
@deffn {Config Command} {bcm2835gpio speed_coeffs} @var{speed_coeff} @var{speed_offset}
|
||||||
Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified,
|
Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified,
|
||||||
speed_coeff defaults to 113714, and speed_offset defaults to 28.
|
speed_coeff defaults to 113714, and speed_offset defaults to 28.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Config Command} {bcm2835gpio peripheral_mem_dev} @var{device}
|
||||||
|
Set the device path for access to the memory mapped GPIO control registers.
|
||||||
|
Uses @file{/dev/gpiomem} by default, this is also the preferred option with
|
||||||
|
respect to system security.
|
||||||
|
If overridden to @file{/dev/mem}:
|
||||||
|
@itemize @minus
|
||||||
|
@item OpenOCD needs @code{cap_sys_rawio} or run as root to open @file{/dev/mem}.
|
||||||
|
Please be aware of security issues imposed by running OpenOCD with
|
||||||
|
elevated user rights and by @file{/dev/mem} itself.
|
||||||
|
@item correct @command{peripheral_base} must be configured.
|
||||||
|
@item GPIO 0-27 pads are set to the limited slew rate
|
||||||
|
and drive strength is reduced to 4 mA (2 mA on RPi 4).
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Config Command} {bcm2835gpio peripheral_base} @var{base}
|
@deffn {Config Command} {bcm2835gpio peripheral_base} @var{base}
|
||||||
Set the peripheral base register address to access GPIOs. For the RPi1, use
|
Set the peripheral base register address to access GPIOs.
|
||||||
|
Ignored if @file{/dev/gpiomem} is used. For the RPi1, use
|
||||||
0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full
|
0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full
|
||||||
list can be found in the
|
list can be found in the
|
||||||
@uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}.
|
@uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}.
|
||||||
|
@ -7355,6 +7372,116 @@ Note: only Main and Work flash regions support Erase operation.
|
||||||
@end deffn
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} {qn908x}
|
||||||
|
The NXP QN908x microcontrollers feature a Cortex-M4F with integrated Bluetooth
|
||||||
|
LE 5 support and an internal flash of up to 512 KiB. These chips only support
|
||||||
|
the SWD interface.
|
||||||
|
|
||||||
|
The @var{qn908x} driver uses the internal "Flash Memory Controller" block via
|
||||||
|
SWD to erase, program and read the internal flash. This driver does not
|
||||||
|
support the ISP (In-System Programming) mode which is an alternate way to
|
||||||
|
program the flash via UART, SPI or USB.
|
||||||
|
|
||||||
|
The internal flash is 512 KiB in size in all released chips and it starts at
|
||||||
|
the address 0x01000000, although it can be mapped to address 0 and it is
|
||||||
|
aliased to other addresses. This driver only recognizes the bank starting at
|
||||||
|
address 0x01000000.
|
||||||
|
|
||||||
|
The internal bootloader stored in ROM is in charge of loading and verifying
|
||||||
|
the image from flash, or enter ISP mode. The programmed image must start at
|
||||||
|
the beginning of the flash and contain a valid header and a matching CRC32
|
||||||
|
checksum. Additionally, the image header contains a "Code Read Protection"
|
||||||
|
(CRP) word which indicates whether SWD access is enabled, as well as whether
|
||||||
|
ISP mode is enabled. Therefore, it is possible to program an image that
|
||||||
|
disables SWD and ISP making it impossible to program another image in the
|
||||||
|
future through these interfaces, or even debug the current image. While this is
|
||||||
|
a valid use case for production deployments where the chips are locked down, by
|
||||||
|
default this driver doesn't allow such images that disable the SWD interface.
|
||||||
|
To program such images see the @command{qn908x allow_brick} command.
|
||||||
|
|
||||||
|
Apart from the CRP field which is located in the image header, the last page
|
||||||
|
of the flash memory contains a "Flash lock and protect" descriptor which allows
|
||||||
|
to individually protect each 2 KiB page, as well as disabling SWD access to the
|
||||||
|
flash and RAM. If this access is disabled it is not possible to read, erase or
|
||||||
|
program individual pages from the SWD interface or even access the read-only
|
||||||
|
"Flash information page" with information about the bootloader version and
|
||||||
|
flash size. However when this protection is in place, it is still possible to
|
||||||
|
mass erase the whole chip and then program a new image, for which you can use
|
||||||
|
the @command{qn908x mass_erase}.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@example
|
||||||
|
flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
@itemize
|
||||||
|
@item @option{calc_checksum} optional parameter to compute the required
|
||||||
|
checksum of the first bytes in the vector table.
|
||||||
|
@quotation Note
|
||||||
|
If the checksum in the header of your image is invalid and you don't provide the
|
||||||
|
@option{calc_checksum} option the boot ROM will not boot your image and it may
|
||||||
|
render the flash inaccessible. On the other hand, if you use this option to
|
||||||
|
compute the checksum keep in mind that @command{verify_image} will fail on
|
||||||
|
those four bytes of the checksum since those bytes in the flash will have the
|
||||||
|
updated checksum.
|
||||||
|
@end quotation
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x allow_brick}
|
||||||
|
Allow the qn908x driver to program images with a "Code Read Protection" byte
|
||||||
|
that disables the SWD access. Programming such image will cause OpenOCD to
|
||||||
|
not be able to reach the target over SWD anymore after the new image is
|
||||||
|
programmed and its configuration takes effect, e.g. after a reboot. After
|
||||||
|
executing @command{qn908x allow_brick} these images will be allowed to be
|
||||||
|
programmed when writing to the flash.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x disable_wdog}
|
||||||
|
Disable the watchdog timer (WDT) by resetting its CTRL field. The WDT starts
|
||||||
|
enabled after a @command{reset halt} and it doesn't run while the target is
|
||||||
|
halted. However, the verification process in this driver uses the generic
|
||||||
|
Cortex-M verification process which executes a payload in RAM and thus
|
||||||
|
requires the watchdog to be disabled before running @command{verify_image}
|
||||||
|
after a reset halt or any other condition where the watchdog is running.
|
||||||
|
Note that this is not done automatically and you must run this command in
|
||||||
|
those scenarios.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x mass_erase}
|
||||||
|
Erases the complete flash using the mass_erase method. Mass erase is only
|
||||||
|
allowed if enabled in the Lock Status Register 8 (LOCK_STAT_8) which is read
|
||||||
|
from the last sector of the flash on boot. However, this mass_erase lock
|
||||||
|
protection can be bypassed and this command does so automatically.
|
||||||
|
|
||||||
|
In the same LOCK_STAT_8 the flash and RAM access from SWD can be disabled by
|
||||||
|
setting two bits in this register. After a mass_erase, all the bits of the
|
||||||
|
flash would be set, making it the default to restrict SWD access to the flash
|
||||||
|
and RAM regions. This new after erase LOCK_STAT_8 value only takes effect after
|
||||||
|
being read from flash on the next reboot for example. After a mass_erase the
|
||||||
|
LOCK_STAT_8 register is changed by the hardware to allow access to flash and
|
||||||
|
RAM regardless of the value on flash, but only right after a mass_erase and
|
||||||
|
until the next boot. Therefore it is possible to perform a mass_erase, program
|
||||||
|
a new image, verify it and then reboot to a valid image that's locked from the
|
||||||
|
SWD access.
|
||||||
|
|
||||||
|
The @command{qn908x mass_erase} command clears the bits that would be loaded
|
||||||
|
from the flash into LOCK_STAT_8 after erasing the whole chip to allow SWD
|
||||||
|
access for debugging or re-flashing an image without a mass_erase by default.
|
||||||
|
If the image being programmed also programs the last page of the flash with its
|
||||||
|
own settings, this mass_erase behavior will interfere with that write since a
|
||||||
|
new erase of at least the last page would need to be performed before writing
|
||||||
|
to it again. For this reason the optional @option{keep_lock} argument can be
|
||||||
|
used to leave the flash and RAM lock set. For development environments, the
|
||||||
|
default behavior is desired.
|
||||||
|
|
||||||
|
The mass erase locking mechanism is independent from the individual page
|
||||||
|
locking bits, so it is possible that you can't erase a given page that is
|
||||||
|
locked and you can't unprotect that page because the locking bits are also
|
||||||
|
locked, but can still mass erase the whole flash.
|
||||||
|
@end deffn
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} {rp2040}
|
@deffn {Flash Driver} {rp2040}
|
||||||
Supports RP2040 "Raspberry Pi Pico" microcontroller.
|
Supports RP2040 "Raspberry Pi Pico" microcontroller.
|
||||||
RP2040 is a dual-core device with two CM0+ cores. Both cores share the same
|
RP2040 is a dual-core device with two CM0+ cores. Both cores share the same
|
||||||
|
@ -11487,6 +11614,40 @@ w/o OpenOCD command and keeps only the latest data window which fit into the buf
|
||||||
Data will be stored to specified destination.
|
Data will be stored to specified destination.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview} (start file://<outfile1> [file://<outfile2>] [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
|
||||||
|
Starts @uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView}
|
||||||
|
compatible tracing. Data will be stored to specified destination.
|
||||||
|
For dual-core chips traces from every core will be saved to separate files.
|
||||||
|
Resulting files can be open in "SEGGER SystemView" application.
|
||||||
|
@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
|
||||||
|
The meaning of the arguments is identical to @command{esp apptrace start}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview} (stop)
|
||||||
|
Stops SystremView compatible tracing started with above command.
|
||||||
|
@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview} (status)
|
||||||
|
Requests ongoing SystremView compatible tracing status.
|
||||||
|
@url{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#openocd-systemview-tracing-command-options}
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview_mcore} (start file://<outfile> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
|
||||||
|
This command is identical to @command{esp sysview start}, but uses Espressif multi-core extension to
|
||||||
|
@uref{https://www.segger.com/products/development-tools/systemview/, SEGGER SystemView} data format.
|
||||||
|
Data will be stored to specified destination. Tracing data from all cores are saved in the same file.
|
||||||
|
The meaning of the arguments is identical to @command{esp sysview start}.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview_mcore} (stop)
|
||||||
|
Stops Espressif multi-core SystremView tracing started with above command.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {esp sysview_mcore} (status)
|
||||||
|
Requests ongoing Espressif multi-core SystremView tracing status.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@anchor{softwaredebugmessagesandtracing}
|
@anchor{softwaredebugmessagesandtracing}
|
||||||
@section Software Debug Messages and Tracing
|
@section Software Debug Messages and Tracing
|
||||||
@cindex Linux-ARM DCC support
|
@cindex Linux-ARM DCC support
|
||||||
|
|
|
@ -179,6 +179,7 @@ enum oob_formats {
|
||||||
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
|
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern struct nand_device *nand_devices;
|
||||||
|
|
||||||
struct nand_device *get_nand_device_by_num(int num);
|
struct nand_device *get_nand_device_by_num(int num);
|
||||||
|
|
||||||
|
@ -202,6 +203,8 @@ int nand_calculate_ecc(struct nand_device *nand,
|
||||||
const uint8_t *dat, uint8_t *ecc_code);
|
const uint8_t *dat, uint8_t *ecc_code);
|
||||||
int nand_calculate_ecc_kw(struct nand_device *nand,
|
int nand_calculate_ecc_kw(struct nand_device *nand,
|
||||||
const uint8_t *dat, uint8_t *ecc_code);
|
const uint8_t *dat, uint8_t *ecc_code);
|
||||||
|
int nand_correct_data(struct nand_device *nand, u_char *dat,
|
||||||
|
u_char *read_ecc, u_char *calc_ecc);
|
||||||
|
|
||||||
int nand_register_commands(struct command_context *cmd_ctx);
|
int nand_register_commands(struct command_context *cmd_ctx);
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
static int lpc32xx_reset(struct nand_device *nand);
|
static int lpc32xx_reset(struct nand_device *nand);
|
||||||
static int lpc32xx_controller_ready(struct nand_device *nand, int timeout);
|
static int lpc32xx_controller_ready(struct nand_device *nand, int timeout);
|
||||||
static int lpc32xx_tc_ready(struct nand_device *nand, int timeout);
|
static int lpc32xx_tc_ready(struct nand_device *nand, int timeout);
|
||||||
extern int nand_correct_data(struct nand_device *nand, u_char *dat,
|
|
||||||
u_char *read_ecc, u_char *calc_ecc);
|
|
||||||
|
|
||||||
/* These are offset with the working area in IRAM when using DMA to
|
/* These are offset with the working area in IRAM when using DMA to
|
||||||
* read/write data to the SLC controller.
|
* read/write data to the SLC controller.
|
||||||
|
|
|
@ -17,9 +17,6 @@
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include <target/target.h>
|
#include <target/target.h>
|
||||||
|
|
||||||
/* to be removed */
|
|
||||||
extern struct nand_device *nand_devices;
|
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_nand_list_command)
|
COMMAND_HANDLER(handle_nand_list_command)
|
||||||
{
|
{
|
||||||
struct nand_device *p;
|
struct nand_device *p;
|
||||||
|
|
|
@ -54,6 +54,7 @@ NOR_DRIVERS = \
|
||||||
%D%/psoc4.c \
|
%D%/psoc4.c \
|
||||||
%D%/psoc5lp.c \
|
%D%/psoc5lp.c \
|
||||||
%D%/psoc6.c \
|
%D%/psoc6.c \
|
||||||
|
%D%/qn908x.c \
|
||||||
%D%/renesas_rpchf.c \
|
%D%/renesas_rpchf.c \
|
||||||
%D%/rp2040.c \
|
%D%/rp2040.c \
|
||||||
%D%/rsl10.c \
|
%D%/rsl10.c \
|
||||||
|
|
|
@ -252,6 +252,19 @@ int get_flash_bank_by_num(unsigned int num, struct flash_bank **bank);
|
||||||
*/
|
*/
|
||||||
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
|
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
|
||||||
struct flash_bank **bank);
|
struct flash_bank **bank);
|
||||||
|
/**
|
||||||
|
* Retrieves @a bank from a command argument, reporting errors parsing
|
||||||
|
* the bank identifier or retrieving the specified bank. The bank
|
||||||
|
* may be identified by its bank number or by @c name.instance, where
|
||||||
|
* @a instance is driver-specific.
|
||||||
|
* @param name_index The index to the string in args containing the
|
||||||
|
* bank identifier.
|
||||||
|
* @param bank On output, contains a pointer to the bank or NULL.
|
||||||
|
* @param do_probe Does auto-probing when set, otherwise without probing.
|
||||||
|
* @returns ERROR_OK on success, or an error indicating the problem.
|
||||||
|
*/
|
||||||
|
COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index,
|
||||||
|
struct flash_bank **bank, bool do_probe);
|
||||||
/**
|
/**
|
||||||
* Returns the flash bank like get_flash_bank_by_num(), without probing.
|
* Returns the flash bank like get_flash_bank_by_num(), without probing.
|
||||||
* @param num The flash bank number.
|
* @param num The flash bank number.
|
||||||
|
|
|
@ -285,6 +285,7 @@ extern const struct flash_driver psoc5lp_eeprom_flash;
|
||||||
extern const struct flash_driver psoc5lp_flash;
|
extern const struct flash_driver psoc5lp_flash;
|
||||||
extern const struct flash_driver psoc5lp_nvl_flash;
|
extern const struct flash_driver psoc5lp_nvl_flash;
|
||||||
extern const struct flash_driver psoc6_flash;
|
extern const struct flash_driver psoc6_flash;
|
||||||
|
extern const struct flash_driver qn908x_flash;
|
||||||
extern const struct flash_driver renesas_rpchf_flash;
|
extern const struct flash_driver renesas_rpchf_flash;
|
||||||
extern const struct flash_driver rp2040_flash;
|
extern const struct flash_driver rp2040_flash;
|
||||||
extern const struct flash_driver rsl10_flash;
|
extern const struct flash_driver rsl10_flash;
|
||||||
|
|
|
@ -62,6 +62,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&psoc5lp_eeprom_flash,
|
&psoc5lp_eeprom_flash,
|
||||||
&psoc5lp_nvl_flash,
|
&psoc5lp_nvl_flash,
|
||||||
&psoc6_flash,
|
&psoc6_flash,
|
||||||
|
&qn908x_flash,
|
||||||
&renesas_rpchf_flash,
|
&renesas_rpchf_flash,
|
||||||
&rp2040_flash,
|
&rp2040_flash,
|
||||||
&sh_qspi_flash,
|
&sh_qspi_flash,
|
||||||
|
|
|
@ -41,7 +41,11 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
|
||||||
bank->sectors = NULL;
|
bank->sectors = NULL;
|
||||||
bank->driver_priv = info;
|
bank->driver_priv = info;
|
||||||
|
|
||||||
info->tap = NULL;
|
if (!bank->target->tap) {
|
||||||
|
LOG_ERROR("Target has no JTAG tap");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
info->tap = bank->target->tap;
|
||||||
info->probed = false;
|
info->probed = false;
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->ir);
|
||||||
|
|
||||||
|
@ -161,7 +165,12 @@ COMMAND_HANDLER(jtagspi_handle_set)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
/* calling flash_command_get_bank without probing because handle_set is used
|
||||||
|
to set device parameters if not autodetected. So probing would fail
|
||||||
|
anyhow.
|
||||||
|
*/
|
||||||
|
retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0,
|
||||||
|
&bank, false);
|
||||||
if (ERROR_OK != retval)
|
if (ERROR_OK != retval)
|
||||||
return retval;
|
return retval;
|
||||||
info = bank->driver_priv;
|
info = bank->driver_priv;
|
||||||
|
@ -292,52 +301,50 @@ COMMAND_HANDLER(jtagspi_handle_set)
|
||||||
COMMAND_HANDLER(jtagspi_handle_cmd)
|
COMMAND_HANDLER(jtagspi_handle_cmd)
|
||||||
{
|
{
|
||||||
struct flash_bank *bank;
|
struct flash_bank *bank;
|
||||||
unsigned int index = 1;
|
const unsigned int max = 20;
|
||||||
const int max = 21;
|
uint8_t cmd_byte, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT];
|
||||||
uint8_t num_write, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT];
|
|
||||||
uint8_t data, *ptr;
|
|
||||||
char temp[4], output[(2 + max + (1 << CHAR_BIT)) * 3 + 8];
|
|
||||||
int retval;
|
|
||||||
|
|
||||||
LOG_DEBUG("%s", __func__);
|
LOG_DEBUG("%s", __func__);
|
||||||
|
|
||||||
if (CMD_ARGC < 3) {
|
if (CMD_ARGC < 3)
|
||||||
command_print(CMD, "jtagspi: not enough arguments");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
num_write = CMD_ARGC - 2;
|
uint8_t num_write = CMD_ARGC - 3;
|
||||||
if (num_write > max) {
|
if (num_write > max) {
|
||||||
LOG_ERROR("at most %d bytes may be send", max);
|
command_print(CMD, "at most %d bytes may be send", max);
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
/* calling flash_command_get_bank without probing because we like to be
|
||||||
if (ERROR_OK != retval)
|
able to send commands before auto-probing occurred. For example sending
|
||||||
return retval;
|
"release from power down" is needed before probing when flash is in
|
||||||
|
power down mode.
|
||||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], num_read);
|
*/
|
||||||
|
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0,
|
||||||
snprintf(output, sizeof(output), "spi: ");
|
&bank, false);
|
||||||
for (ptr = &write_buffer[0] ; index < CMD_ARGC; index++) {
|
|
||||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index], data);
|
|
||||||
*ptr++ = data;
|
|
||||||
snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data);
|
|
||||||
strncat(output, temp, sizeof(output) - strlen(output) - 1);
|
|
||||||
}
|
|
||||||
strncat(output, "-> ", sizeof(output) - strlen(output) - 1);
|
|
||||||
|
|
||||||
/* process command */
|
|
||||||
ptr = &read_buffer[0];
|
|
||||||
jtagspi_cmd(bank, write_buffer[0], &write_buffer[1], num_write - 1, ptr, -num_read);
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
for ( ; num_read > 0; num_read--) {
|
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read);
|
||||||
snprintf(temp, sizeof(temp), "%02" PRIx8 " ", *ptr++);
|
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte);
|
||||||
strncat(output, temp, sizeof(output) - strlen(output) - 1);
|
|
||||||
}
|
for (unsigned int i = 0; i < num_write; i++)
|
||||||
command_print(CMD, "%s", output);
|
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[i + 3], write_buffer[i]);
|
||||||
|
|
||||||
|
/* process command */
|
||||||
|
retval = jtagspi_cmd(bank, cmd_byte, write_buffer, num_write, read_buffer, -num_read);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
command_print_sameline(CMD, "spi: %02" PRIx8, cmd_byte);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_write; i++)
|
||||||
|
command_print_sameline(CMD, " %02" PRIx8, write_buffer[i]);
|
||||||
|
|
||||||
|
command_print_sameline(CMD, " ->");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_read; i++)
|
||||||
|
command_print_sameline(CMD, " %02" PRIx8, read_buffer[i]);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -381,12 +388,6 @@ static int jtagspi_probe(struct flash_bank *bank)
|
||||||
}
|
}
|
||||||
info->probed = false;
|
info->probed = false;
|
||||||
|
|
||||||
if (!bank->target->tap) {
|
|
||||||
LOG_ERROR("Target has no JTAG tap");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
info->tap = bank->target->tap;
|
|
||||||
|
|
||||||
jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, 0, in_buf, -3);
|
jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, 0, in_buf, -3);
|
||||||
/* the table in spi.c has the manufacturer byte (first) as the lsb */
|
/* the table in spi.c has the manufacturer byte (first) as the lsb */
|
||||||
id = le_to_h_u24(in_buf);
|
id = le_to_h_u24(in_buf);
|
||||||
|
@ -518,7 +519,7 @@ static int jtagspi_bulk_erase(struct flash_bank *bank)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0);
|
retval = jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
|
|
@ -779,7 +779,7 @@ static int psoc4_probe(struct flash_bank *bank)
|
||||||
flash_size_in_kb = psoc4_info->user_bank_size / 1024;
|
flash_size_in_kb = psoc4_info->user_bank_size / 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
char macros_txt[20] = "";
|
char macros_txt[22] = "";
|
||||||
if (num_macros > 1)
|
if (num_macros > 1)
|
||||||
snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros);
|
snprintf(macros_txt, sizeof(macros_txt), " in %" PRIu32 " macros", num_macros);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -91,7 +91,7 @@ static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
|
static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
|
||||||
uint16_t func_offset, uint32_t argdata[], unsigned int n_args, int timeout_ms)
|
uint16_t func_offset, uint32_t argdata[], unsigned int n_args, unsigned int timeout_ms)
|
||||||
{
|
{
|
||||||
char *regnames[4] = { "r0", "r1", "r2", "r3" };
|
char *regnames[4] = { "r0", "r1", "r2", "r3" };
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsig
|
||||||
an optional larger "block" (size and command provided in args).
|
an optional larger "block" (size and command provided in args).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int timeout_ms = 2000 * (last - first) + 1000;
|
unsigned int timeout_ms = 2000 * (last - first) + 1000;
|
||||||
err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase,
|
err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_erase,
|
||||||
args, ARRAY_SIZE(args), timeout_ms);
|
args, ARRAY_SIZE(args), timeout_ms);
|
||||||
|
|
||||||
|
|
|
@ -230,11 +230,11 @@ static int stm32x_otp_enable(struct flash_bank *bank)
|
||||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||||
|
|
||||||
if (!stm32x_info->otp_unlocked) {
|
if (!stm32x_info->otp_unlocked) {
|
||||||
LOG_INFO("OTP memory bank #%u is is enabled for write commands.",
|
LOG_INFO("OTP memory bank #%u is enabled for write commands.",
|
||||||
bank->bank_number);
|
bank->bank_number);
|
||||||
stm32x_info->otp_unlocked = true;
|
stm32x_info->otp_unlocked = true;
|
||||||
} else {
|
} else {
|
||||||
LOG_WARNING("OTP memory bank #%u is is already enabled for write commands.",
|
LOG_WARNING("OTP memory bank #%u is already enabled for write commands.",
|
||||||
bank->bank_number);
|
bank->bank_number);
|
||||||
}
|
}
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -659,8 +659,10 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stm32x_is_otp(bank)) {
|
if (stm32x_is_otp(bank)) {
|
||||||
if (!set)
|
if (!set) {
|
||||||
|
LOG_ERROR("OTP protection can only be enabled");
|
||||||
return ERROR_COMMAND_ARGUMENT_INVALID;
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
return stm32x_otp_protect(bank, first, last);
|
return stm32x_otp_protect(bank, first, last);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,12 @@
|
||||||
* http://www.st.com/resource/en/reference_manual/dm00451556.pdf
|
* http://www.st.com/resource/en/reference_manual/dm00451556.pdf
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* STM32C0xxx series for reference.
|
||||||
|
*
|
||||||
|
* RM0490 (STM32C0x1)
|
||||||
|
* http://www.st.com/resource/en/reference_manual/dm00781702.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
/* STM32G0xxx series for reference.
|
/* STM32G0xxx series for reference.
|
||||||
*
|
*
|
||||||
* RM0444 (STM32G0x1)
|
* RM0444 (STM32G0x1)
|
||||||
|
@ -263,7 +269,7 @@ struct stm32l4_wrp {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* human readable list of families this drivers supports (sorted alphabetically) */
|
/* human readable list of families this drivers supports (sorted alphabetically) */
|
||||||
static const char *device_families = "STM32G0/G4/L4/L4+/L5/U5/WB/WL";
|
static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U5/WB/WL";
|
||||||
|
|
||||||
static const struct stm32l4_rev stm32l47_l48xx_revs[] = {
|
static const struct stm32l4_rev stm32l47_l48xx_revs[] = {
|
||||||
{ 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
|
{ 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
|
||||||
|
@ -273,6 +279,15 @@ static const struct stm32l4_rev stm32l43_l44xx_revs[] = {
|
||||||
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
|
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct stm32l4_rev stm32c01xx_revs[] = {
|
||||||
|
{ 0x1000, "A" }, { 0x1001, "Z" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct stm32l4_rev stm32c03xx_revs[] = {
|
||||||
|
{ 0x1000, "A" }, { 0x1001, "Z" },
|
||||||
|
};
|
||||||
|
|
||||||
static const struct stm32l4_rev stm32g05_g06xx_revs[] = {
|
static const struct stm32l4_rev stm32g05_g06xx_revs[] = {
|
||||||
{ 0x1000, "A" },
|
{ 0x1000, "A" },
|
||||||
};
|
};
|
||||||
|
@ -371,6 +386,30 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
|
||||||
.otp_base = 0x1FFF7000,
|
.otp_base = 0x1FFF7000,
|
||||||
.otp_size = 1024,
|
.otp_size = 1024,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = DEVID_STM32C01XX,
|
||||||
|
.revs = stm32c01xx_revs,
|
||||||
|
.num_revs = ARRAY_SIZE(stm32c01xx_revs),
|
||||||
|
.device_str = "STM32C01xx",
|
||||||
|
.max_flash_size_kb = 32,
|
||||||
|
.flags = F_NONE,
|
||||||
|
.flash_regs_base = 0x40022000,
|
||||||
|
.fsize_addr = 0x1FFF75A0,
|
||||||
|
.otp_base = 0x1FFF7000,
|
||||||
|
.otp_size = 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = DEVID_STM32C03XX,
|
||||||
|
.revs = stm32c03xx_revs,
|
||||||
|
.num_revs = ARRAY_SIZE(stm32c03xx_revs),
|
||||||
|
.device_str = "STM32C03xx",
|
||||||
|
.max_flash_size_kb = 32,
|
||||||
|
.flags = F_NONE,
|
||||||
|
.flash_regs_base = 0x40022000,
|
||||||
|
.fsize_addr = 0x1FFF75A0,
|
||||||
|
.otp_base = 0x1FFF7000,
|
||||||
|
.otp_size = 1024,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.id = DEVID_STM32G05_G06XX,
|
.id = DEVID_STM32G05_G06XX,
|
||||||
.revs = stm32g05_g06xx_revs,
|
.revs = stm32g05_g06xx_revs,
|
||||||
|
@ -1855,6 +1894,8 @@ static int stm32l4_probe(struct flash_bank *bank)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DEVID_STM32L43_L44XX:
|
case DEVID_STM32L43_L44XX:
|
||||||
|
case DEVID_STM32C01XX:
|
||||||
|
case DEVID_STM32C03XX:
|
||||||
case DEVID_STM32G05_G06XX:
|
case DEVID_STM32G05_G06XX:
|
||||||
case DEVID_STM32G07_G08XX:
|
case DEVID_STM32G07_G08XX:
|
||||||
case DEVID_STM32L45_L46XX:
|
case DEVID_STM32L45_L46XX:
|
||||||
|
|
|
@ -87,6 +87,8 @@
|
||||||
/* Supported device IDs */
|
/* Supported device IDs */
|
||||||
#define DEVID_STM32L47_L48XX 0x415
|
#define DEVID_STM32L47_L48XX 0x415
|
||||||
#define DEVID_STM32L43_L44XX 0x435
|
#define DEVID_STM32L43_L44XX 0x435
|
||||||
|
#define DEVID_STM32C01XX 0x443
|
||||||
|
#define DEVID_STM32C03XX 0x453
|
||||||
#define DEVID_STM32G05_G06XX 0x456
|
#define DEVID_STM32G05_G06XX 0x456
|
||||||
#define DEVID_STM32G07_G08XX 0x460
|
#define DEVID_STM32G07_G08XX 0x460
|
||||||
#define DEVID_STM32L49_L4AXX 0x461
|
#define DEVID_STM32L49_L4AXX 0x461
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
* Implements Tcl commands used to access NOR flash facilities.
|
* Implements Tcl commands used to access NOR flash facilities.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
|
COMMAND_HELPER(flash_command_get_bank_probe_optional, unsigned int name_index,
|
||||||
struct flash_bank **bank, bool do_probe)
|
struct flash_bank **bank, bool do_probe)
|
||||||
{
|
{
|
||||||
const char *name = CMD_ARGV[name_index];
|
const char *name = CMD_ARGV[name_index];
|
||||||
|
@ -51,7 +51,7 @@ static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
|
||||||
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
|
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
|
||||||
struct flash_bank **bank)
|
struct flash_bank **bank)
|
||||||
{
|
{
|
||||||
return CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe,
|
return CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional,
|
||||||
name_index, bank, true);
|
name_index, bank, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ COMMAND_HANDLER(handle_flash_probe_command)
|
||||||
if (CMD_ARGC != 1)
|
if (CMD_ARGC != 1)
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, 0, &p, false);
|
retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &p, false);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#endif
|
#endif
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
|
#include "hello.h"
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_foo_command)
|
COMMAND_HANDLER(handle_foo_command)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "replacements.h"
|
#include "replacements.h"
|
||||||
#include "time_support.h"
|
#include "time_support.h"
|
||||||
|
#include <server/gdb_server.h>
|
||||||
#include <server/server.h>
|
#include <server/server.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
@ -399,9 +400,7 @@ char *alloc_printf(const char *format, ...)
|
||||||
|
|
||||||
static void gdb_timeout_warning(int64_t delta_time)
|
static void gdb_timeout_warning(int64_t delta_time)
|
||||||
{
|
{
|
||||||
extern int gdb_actual_connections;
|
if (gdb_get_actual_connections())
|
||||||
|
|
||||||
if (gdb_actual_connections)
|
|
||||||
LOG_WARNING("keep_alive() was not invoked in the "
|
LOG_WARNING("keep_alive() was not invoked in the "
|
||||||
"%d ms timelimit. GDB alive packet not "
|
"%d ms timelimit. GDB alive packet not "
|
||||||
"sent! (%" PRId64 " ms). Workaround: increase "
|
"sent! (%" PRId64 " ms). Workaround: increase "
|
||||||
|
|
|
@ -10,10 +10,18 @@
|
||||||
* Copyright (C) 2008 by Spencer Oliver *
|
* Copyright (C) 2008 by Spencer Oliver *
|
||||||
* spen@spen-soft.co.uk *
|
* spen@spen-soft.co.uk *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
/* DANGER!!!! These must be defined *BEFORE* replacements.h and the malloc() macro!!!! */
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* define IN_REPLACEMENTS_C before include replacements.h */
|
||||||
|
#define IN_REPLACEMENTS_C
|
||||||
|
#include "replacements.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* clear_malloc
|
* clear_malloc
|
||||||
*
|
*
|
||||||
|
@ -41,10 +49,6 @@ void *fill_malloc(size_t size)
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IN_REPLACEMENTS_C
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_STRINGS_H
|
#ifdef HAVE_STRINGS_H
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,12 +66,10 @@ int gettimeofday(struct timeval *tv, struct timezone *tz);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef IN_REPLACEMENTS_C
|
|
||||||
/**** clear_malloc & fill_malloc ****/
|
|
||||||
void *clear_malloc(size_t size);
|
void *clear_malloc(size_t size);
|
||||||
void *fill_malloc(size_t size);
|
void *fill_malloc(size_t size);
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#ifndef IN_REPLACEMENTS_C
|
||||||
/*
|
/*
|
||||||
* Now you have 3 ways for the malloc function:
|
* Now you have 3 ways for the malloc function:
|
||||||
*
|
*
|
||||||
|
@ -100,6 +98,7 @@ void *fill_malloc(size_t size);
|
||||||
|
|
||||||
/* #define malloc(_a) clear_malloc(_a)
|
/* #define malloc(_a) clear_malloc(_a)
|
||||||
* #define malloc(_a) fill_malloc(_a) */
|
* #define malloc(_a) fill_malloc(_a) */
|
||||||
|
#endif /* IN_REPLACEMENTS_C */
|
||||||
|
|
||||||
/* GNU extensions to the C library that may be missing on some systems */
|
/* GNU extensions to the C library that may be missing on some systems */
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
|
|
|
@ -177,44 +177,44 @@ static inline void h_u64_to_be(uint8_t *buf, uint64_t val)
|
||||||
|
|
||||||
static inline void h_u32_to_le(uint8_t *buf, uint32_t val)
|
static inline void h_u32_to_le(uint8_t *buf, uint32_t val)
|
||||||
{
|
{
|
||||||
buf[3] = (uint8_t) (val >> 24);
|
buf[3] = (val >> 24) & 0xff;
|
||||||
buf[2] = (uint8_t) (val >> 16);
|
buf[2] = (val >> 16) & 0xff;
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (val >> 8) & 0xff;
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u32_to_be(uint8_t *buf, uint32_t val)
|
static inline void h_u32_to_be(uint8_t *buf, uint32_t val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 24);
|
buf[0] = (val >> 24) & 0xff;
|
||||||
buf[1] = (uint8_t) (val >> 16);
|
buf[1] = (val >> 16) & 0xff;
|
||||||
buf[2] = (uint8_t) (val >> 8);
|
buf[2] = (val >> 8) & 0xff;
|
||||||
buf[3] = (uint8_t) (val >> 0);
|
buf[3] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u24_to_le(uint8_t *buf, unsigned int val)
|
static inline void h_u24_to_le(uint8_t *buf, unsigned int val)
|
||||||
{
|
{
|
||||||
buf[2] = (uint8_t) (val >> 16);
|
buf[2] = (val >> 16) & 0xff;
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (val >> 8) & 0xff;
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u24_to_be(uint8_t *buf, unsigned int val)
|
static inline void h_u24_to_be(uint8_t *buf, unsigned int val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 16);
|
buf[0] = (val >> 16) & 0xff;
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (val >> 8) & 0xff;
|
||||||
buf[2] = (uint8_t) (val >> 0);
|
buf[2] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u16_to_le(uint8_t *buf, uint16_t val)
|
static inline void h_u16_to_le(uint8_t *buf, uint16_t val)
|
||||||
{
|
{
|
||||||
buf[1] = (uint8_t) (val >> 8);
|
buf[1] = (val >> 8) & 0xff;
|
||||||
buf[0] = (uint8_t) (val >> 0);
|
buf[0] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void h_u16_to_be(uint8_t *buf, uint16_t val)
|
static inline void h_u16_to_be(uint8_t *buf, uint16_t val)
|
||||||
{
|
{
|
||||||
buf[0] = (uint8_t) (val >> 8);
|
buf[0] = (val >> 8) & 0xff;
|
||||||
buf[1] = (uint8_t) (val >> 0);
|
buf[1] = (val >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
static uint32_t bcm2835_peri_base = 0x20000000;
|
static char *bcm2835_peri_mem_dev;
|
||||||
|
static off_t bcm2835_peri_base = 0x20000000;
|
||||||
#define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
|
#define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
|
||||||
|
|
||||||
#define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
|
#define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
|
||||||
|
@ -57,6 +58,14 @@ static struct initial_gpio_state {
|
||||||
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
|
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
|
||||||
static uint32_t initial_drive_strength_etc;
|
static uint32_t initial_drive_strength_etc;
|
||||||
|
|
||||||
|
static inline const char *bcm2835_get_mem_dev(void)
|
||||||
|
{
|
||||||
|
if (bcm2835_peri_mem_dev)
|
||||||
|
return bcm2835_peri_mem_dev;
|
||||||
|
|
||||||
|
return "/dev/gpiomem";
|
||||||
|
}
|
||||||
|
|
||||||
static inline void bcm2835_gpio_synchronize(void)
|
static inline void bcm2835_gpio_synchronize(void)
|
||||||
{
|
{
|
||||||
/* Ensure that previous writes to GPIO registers are flushed out of
|
/* Ensure that previous writes to GPIO registers are flushed out of
|
||||||
|
@ -300,13 +309,29 @@ COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC == 1) {
|
||||||
|
free(bcm2835_peri_mem_dev);
|
||||||
|
bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s",
|
||||||
|
bcm2835_get_mem_dev());
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
|
COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC == 1)
|
uint64_t tmp_base;
|
||||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bcm2835_peri_base);
|
if (CMD_ARGC == 1) {
|
||||||
|
COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], tmp_base);
|
||||||
|
bcm2835_peri_base = (off_t)tmp_base;
|
||||||
|
}
|
||||||
|
|
||||||
command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08x",
|
tmp_base = bcm2835_peri_base;
|
||||||
bcm2835_peri_base);
|
command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIu64,
|
||||||
|
tmp_base);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,11 +343,18 @@ static const struct command_registration bcm2835gpio_subcommand_handlers[] = {
|
||||||
.help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
|
.help = "SPEED_COEFF and SPEED_OFFSET for delay calculations.",
|
||||||
.usage = "[SPEED_COEFF SPEED_OFFSET]",
|
.usage = "[SPEED_COEFF SPEED_OFFSET]",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "peripheral_mem_dev",
|
||||||
|
.handler = &bcm2835gpio_handle_peripheral_mem_dev,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "device to map memory mapped GPIOs from.",
|
||||||
|
.usage = "[device]",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "peripheral_base",
|
.name = "peripheral_base",
|
||||||
.handler = &bcm2835gpio_handle_peripheral_base,
|
.handler = &bcm2835gpio_handle_peripheral_base,
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.help = "peripheral base to access GPIOs (RPi1 0x20000000, RPi2 0x3F000000).",
|
.help = "peripheral base to access GPIOs, not needed with /dev/gpiomem.",
|
||||||
.usage = "[base]",
|
.usage = "[base]",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -409,13 +441,16 @@ static int bcm2835gpio_init(void)
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
|
bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0;
|
||||||
|
bool pad_mapping_possible = !is_gpiomem;
|
||||||
|
|
||||||
|
dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC);
|
||||||
if (dev_mem_fd < 0) {
|
if (dev_mem_fd < 0) {
|
||||||
LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
|
LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno));
|
||||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
/* TODO: add /dev/mem specific doc and refer to it
|
||||||
}
|
* if (!is_gpiomem && (errno == EACCES || errno == EPERM))
|
||||||
if (dev_mem_fd < 0) {
|
* LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities");
|
||||||
LOG_ERROR("open: %s", strerror(errno));
|
*/
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,21 +463,28 @@ static int bcm2835gpio_init(void)
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
return ERROR_JTAG_INIT_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
|
/* TODO: move pads config to a separate utility */
|
||||||
|
if (pad_mapping_possible) {
|
||||||
|
pads_base = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
|
MAP_SHARED, dev_mem_fd, BCM2835_PADS_GPIO_0_27);
|
||||||
|
|
||||||
if (pads_base == MAP_FAILED) {
|
if (pads_base == MAP_FAILED) {
|
||||||
LOG_ERROR("mmap: %s", strerror(errno));
|
LOG_ERROR("mmap pads: %s", strerror(errno));
|
||||||
bcm2835gpio_munmap();
|
LOG_WARNING("Continuing with unchanged GPIO pad settings (drive strength and slew rate)");
|
||||||
close(dev_mem_fd);
|
}
|
||||||
return ERROR_JTAG_INIT_FAILED;
|
} else {
|
||||||
|
pads_base = MAP_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(dev_mem_fd);
|
close(dev_mem_fd);
|
||||||
|
|
||||||
/* set 4mA drive strength, slew rate limited, hysteresis on */
|
if (pads_base != MAP_FAILED) {
|
||||||
initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
|
/* set 4mA drive strength, slew rate limited, hysteresis on */
|
||||||
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
|
initial_drive_strength_etc = pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] & 0x1f;
|
||||||
|
LOG_INFO("initial pads conf %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
|
||||||
|
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5a000008 + 1;
|
||||||
|
LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
|
||||||
|
}
|
||||||
|
|
||||||
/* Configure JTAG/SWD signals. Default directions and initial states are handled
|
/* Configure JTAG/SWD signals. Default directions and initial states are handled
|
||||||
* by adapter.c and "adapter gpio" command.
|
* by adapter.c and "adapter gpio" command.
|
||||||
|
@ -513,9 +555,12 @@ static int bcm2835gpio_quit(void)
|
||||||
restore_gpio(ADAPTER_GPIO_IDX_SRST);
|
restore_gpio(ADAPTER_GPIO_IDX_SRST);
|
||||||
restore_gpio(ADAPTER_GPIO_IDX_LED);
|
restore_gpio(ADAPTER_GPIO_IDX_LED);
|
||||||
|
|
||||||
/* Restore drive strength. MSB is password ("5A") */
|
if (pads_base != MAP_FAILED) {
|
||||||
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
|
/* Restore drive strength. MSB is password ("5A") */
|
||||||
|
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
|
||||||
|
}
|
||||||
bcm2835gpio_munmap();
|
bcm2835gpio_munmap();
|
||||||
|
free(bcm2835_peri_mem_dev);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
#include "helper/log.h"
|
#include "helper/log.h"
|
||||||
#include "helper/list.h"
|
#include "helper/list.h"
|
||||||
|
|
||||||
#define VD_VERSION 44
|
#define VD_VERSION 46
|
||||||
#define VD_BUFFER_LEN 4024
|
#define VD_BUFFER_LEN 4024
|
||||||
#define VD_CHEADER_LEN 24
|
#define VD_CHEADER_LEN 24
|
||||||
#define VD_SHEADER_LEN 16
|
#define VD_SHEADER_LEN 16
|
||||||
|
@ -272,7 +272,7 @@ static int vdebug_socket_open(char *server_addr, uint32_t port)
|
||||||
LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error());
|
LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error());
|
||||||
rc = VD_ERR_SOC_ADDR;
|
rc = VD_ERR_SOC_ADDR;
|
||||||
} else {
|
} else {
|
||||||
buf_set_u32((uint8_t *)ainfo->ai_addr->sa_data, 0, 16, htons(port));
|
h_u16_to_be((uint8_t *)ainfo->ai_addr->sa_data, port);
|
||||||
if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) {
|
if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) {
|
||||||
LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error());
|
LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error());
|
||||||
rc = VD_ERR_SOC_CONN;
|
rc = VD_ERR_SOC_CONN;
|
||||||
|
@ -942,10 +942,10 @@ static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush)
|
||||||
{
|
{
|
||||||
int rc = ERROR_OK;
|
int rc = ERROR_OK;
|
||||||
|
|
||||||
uint8_t cur = tap_get_state();
|
tap_state_t cur = tap_get_state();
|
||||||
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
||||||
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
||||||
LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state);
|
LOG_INFO("tlr from %x to %x", cur, state);
|
||||||
if (cur != state) {
|
if (cur != state) {
|
||||||
rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush);
|
rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush);
|
||||||
tap_set_state(state);
|
tap_set_state(state);
|
||||||
|
@ -958,7 +958,7 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush)
|
||||||
{
|
{
|
||||||
int rc = ERROR_OK;
|
int rc = ERROR_OK;
|
||||||
|
|
||||||
uint8_t cur = tap_get_state();
|
tap_state_t cur = tap_get_state();
|
||||||
uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT;
|
uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT;
|
||||||
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
||||||
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
||||||
|
@ -988,7 +988,7 @@ static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush)
|
||||||
|
|
||||||
static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush)
|
static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush)
|
||||||
{
|
{
|
||||||
uint8_t cur = tap_get_state();
|
tap_state_t cur = tap_get_state();
|
||||||
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
uint8_t tms_pre = tap_get_tms_path(cur, state);
|
||||||
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
uint8_t num_pre = tap_get_tms_path_len(cur, state);
|
||||||
LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state);
|
LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state);
|
||||||
|
@ -1125,7 +1125,7 @@ static int vdebug_dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
|
||||||
|
|
||||||
static int vdebug_dap_run(struct adiv5_dap *dap)
|
static int vdebug_dap_run(struct adiv5_dap *dap)
|
||||||
{
|
{
|
||||||
if (pbuf->waddr)
|
if (le_to_h_u16(pbuf->waddr))
|
||||||
return vdebug_run_reg_queue(vdc.hsocket, pbuf, le_to_h_u16(pbuf->waddr));
|
return vdebug_run_reg_queue(vdc.hsocket, pbuf, le_to_h_u16(pbuf->waddr));
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
|
@ -37,8 +37,15 @@ static const struct command_registration hl_swd_transport_subcommand_handlers[]
|
||||||
{
|
{
|
||||||
.name = "newdap",
|
.name = "newdap",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.help = "declare a new SWD DAP",
|
.help = "declare a new SWD DAP",
|
||||||
|
.usage = "basename dap_type ['-irlen' count] "
|
||||||
|
"['-enable'|'-disable'] "
|
||||||
|
"['-expected_id' number] "
|
||||||
|
"['-ignore-version'] "
|
||||||
|
"['-ignore-bypass'] "
|
||||||
|
"['-ircapture' number] "
|
||||||
|
"['-mask' number]",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
@ -58,11 +65,16 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[]
|
||||||
{
|
{
|
||||||
.name = "newtap",
|
.name = "newtap",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.help = "Create a new TAP instance named basename.tap_type, "
|
.help = "Create a new TAP instance named basename.tap_type, "
|
||||||
"and appends it to the scan chain.",
|
"and appends it to the scan chain.",
|
||||||
.usage = "basename tap_type '-irlen' count "
|
.usage = "basename tap_type '-irlen' count "
|
||||||
"['-expected_id' number]",
|
"['-enable'|'-disable'] "
|
||||||
|
"['-expected_id' number] "
|
||||||
|
"['-ignore-version'] "
|
||||||
|
"['-ignore-bypass'] "
|
||||||
|
"['-ircapture' number] "
|
||||||
|
"['-mask' number]",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "init",
|
.name = "init",
|
||||||
|
@ -85,12 +97,18 @@ static const struct command_registration hl_transport_jtag_subcommand_handlers[]
|
||||||
{
|
{
|
||||||
.name = "tapisenabled",
|
.name = "tapisenabled",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
|
.help = "Returns a Tcl boolean (0/1) indicating whether "
|
||||||
|
"the TAP is enabled (1) or not (0).",
|
||||||
|
.usage = "tap_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "tapenable",
|
.name = "tapenable",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
|
.help = "Try to enable the specified TAP using the "
|
||||||
|
"'tap-enable' TAP event.",
|
||||||
|
.usage = "tap_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "tapdisable",
|
.name = "tapdisable",
|
||||||
|
|
|
@ -372,7 +372,7 @@ tap_state_t tap_state_by_name(const char *name)
|
||||||
tap_state_name(a), tap_state_name(b), astr, bstr)
|
tap_state_name(a), tap_state_name(b), astr, bstr)
|
||||||
|
|
||||||
tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf,
|
tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf,
|
||||||
unsigned tap_bits, tap_state_t next_state)
|
unsigned int tap_bits, tap_state_t next_state)
|
||||||
{
|
{
|
||||||
const uint8_t *tms_buffer;
|
const uint8_t *tms_buffer;
|
||||||
const uint8_t *tdi_buffer;
|
const uint8_t *tdi_buffer;
|
||||||
|
|
|
@ -147,6 +147,8 @@ void tap_use_new_tms_table(bool use_new);
|
||||||
/** @returns True if new TMS table is active; false otherwise. */
|
/** @returns True if new TMS table is active; false otherwise. */
|
||||||
bool tap_uses_new_tms_table(void);
|
bool tap_uses_new_tms_table(void);
|
||||||
|
|
||||||
|
tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf,
|
||||||
|
unsigned int tap_len, tap_state_t start_tap_state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prints verbose TAP state transitions for the given TMS/TDI buffers.
|
* @brief Prints verbose TAP state transitions for the given TMS/TDI buffers.
|
||||||
|
@ -159,10 +161,6 @@ bool tap_uses_new_tms_table(void);
|
||||||
static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
|
static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
|
||||||
const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state)
|
const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state)
|
||||||
{
|
{
|
||||||
/* Private declaration */
|
|
||||||
tap_state_t jtag_debug_state_machine_(const void *tms_buf, const void *tdi_buf,
|
|
||||||
unsigned tap_len, tap_state_t start_tap_state);
|
|
||||||
|
|
||||||
if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO))
|
if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO))
|
||||||
return jtag_debug_state_machine_(tms_buf, tdi_buf, tap_len, start_tap_state);
|
return jtag_debug_state_machine_(tms_buf, tdi_buf, tap_len, start_tap_state);
|
||||||
else
|
else
|
||||||
|
@ -364,4 +362,42 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
||||||
unsigned int traceclkin_freq, uint16_t *prescaler);
|
unsigned int traceclkin_freq, uint16_t *prescaler);
|
||||||
int adapter_poll_trace(uint8_t *buf, size_t *size);
|
int adapter_poll_trace(uint8_t *buf, size_t *size);
|
||||||
|
|
||||||
|
extern struct adapter_driver am335xgpio_adapter_driver;
|
||||||
|
extern struct adapter_driver amt_jtagaccel_adapter_driver;
|
||||||
|
extern struct adapter_driver armjtagew_adapter_driver;
|
||||||
|
extern struct adapter_driver at91rm9200_adapter_driver;
|
||||||
|
extern struct adapter_driver bcm2835gpio_adapter_driver;
|
||||||
|
extern struct adapter_driver buspirate_adapter_driver;
|
||||||
|
extern struct adapter_driver cmsis_dap_adapter_driver;
|
||||||
|
extern struct adapter_driver dummy_adapter_driver;
|
||||||
|
extern struct adapter_driver ep93xx_adapter_driver;
|
||||||
|
extern struct adapter_driver esp_usb_adapter_driver;
|
||||||
|
extern struct adapter_driver ft232r_adapter_driver;
|
||||||
|
extern struct adapter_driver ftdi_adapter_driver;
|
||||||
|
extern struct adapter_driver gw16012_adapter_driver;
|
||||||
|
extern struct adapter_driver hl_adapter_driver;
|
||||||
|
extern struct adapter_driver imx_gpio_adapter_driver;
|
||||||
|
extern struct adapter_driver jlink_adapter_driver;
|
||||||
|
extern struct adapter_driver jtag_dpi_adapter_driver;
|
||||||
|
extern struct adapter_driver jtag_vpi_adapter_driver;
|
||||||
|
extern struct adapter_driver kitprog_adapter_driver;
|
||||||
|
extern struct adapter_driver linuxgpiod_adapter_driver;
|
||||||
|
extern struct adapter_driver opendous_adapter_driver;
|
||||||
|
extern struct adapter_driver openjtag_adapter_driver;
|
||||||
|
extern struct adapter_driver osbdm_adapter_driver;
|
||||||
|
extern struct adapter_driver parport_adapter_driver;
|
||||||
|
extern struct adapter_driver presto_adapter_driver;
|
||||||
|
extern struct adapter_driver remote_bitbang_adapter_driver;
|
||||||
|
extern struct adapter_driver rlink_adapter_driver;
|
||||||
|
extern struct adapter_driver rshim_dap_adapter_driver;
|
||||||
|
extern struct adapter_driver stlink_dap_adapter_driver;
|
||||||
|
extern struct adapter_driver sysfsgpio_adapter_driver;
|
||||||
|
extern struct adapter_driver ulink_adapter_driver;
|
||||||
|
extern struct adapter_driver usb_blaster_adapter_driver;
|
||||||
|
extern struct adapter_driver usbprog_adapter_driver;
|
||||||
|
extern struct adapter_driver vdebug_adapter_driver;
|
||||||
|
extern struct adapter_driver vsllink_adapter_driver;
|
||||||
|
extern struct adapter_driver xds110_adapter_driver;
|
||||||
|
extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_INTERFACE_H */
|
#endif /* OPENOCD_JTAG_INTERFACE_H */
|
||||||
|
|
|
@ -24,125 +24,13 @@
|
||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
* This file includes declarations for all built-in jtag interfaces,
|
* This file collects all the built-in JTAG interfaces in the adapter_drivers
|
||||||
* which are then listed in the adapter_drivers array.
|
* array.
|
||||||
*
|
*
|
||||||
* Dynamic loading can be implemented be searching for shared libraries
|
* Dynamic loading can be implemented be searching for shared libraries
|
||||||
* that contain an adapter_driver structure that can added to this list.
|
* that contain an adapter_driver structure that can added to this list.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if BUILD_PARPORT == 1
|
|
||||||
extern struct adapter_driver parport_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_DUMMY == 1
|
|
||||||
extern struct adapter_driver dummy_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_FTDI == 1
|
|
||||||
extern struct adapter_driver ftdi_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1
|
|
||||||
extern struct adapter_driver usb_blaster_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_ESP_USB_JTAG == 1
|
|
||||||
extern struct adapter_driver esp_usb_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_JTAG_VPI == 1
|
|
||||||
extern struct adapter_driver jtag_vpi_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_VDEBUG == 1
|
|
||||||
extern struct adapter_driver vdebug_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_JTAG_DPI == 1
|
|
||||||
extern struct adapter_driver jtag_dpi_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_FT232R == 1
|
|
||||||
extern struct adapter_driver ft232r_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_AMTJTAGACCEL == 1
|
|
||||||
extern struct adapter_driver amt_jtagaccel_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_EP93XX == 1
|
|
||||||
extern struct adapter_driver ep93xx_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_AT91RM9200 == 1
|
|
||||||
extern struct adapter_driver at91rm9200_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_GW16012 == 1
|
|
||||||
extern struct adapter_driver gw16012_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_PRESTO
|
|
||||||
extern struct adapter_driver presto_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_USBPROG == 1
|
|
||||||
extern struct adapter_driver usbprog_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_OPENJTAG == 1
|
|
||||||
extern struct adapter_driver openjtag_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_JLINK == 1
|
|
||||||
extern struct adapter_driver jlink_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_VSLLINK == 1
|
|
||||||
extern struct adapter_driver vsllink_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_RLINK == 1
|
|
||||||
extern struct adapter_driver rlink_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_ULINK == 1
|
|
||||||
extern struct adapter_driver ulink_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_ARMJTAGEW == 1
|
|
||||||
extern struct adapter_driver armjtagew_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_BUSPIRATE == 1
|
|
||||||
extern struct adapter_driver buspirate_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_REMOTE_BITBANG == 1
|
|
||||||
extern struct adapter_driver remote_bitbang_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_HLADAPTER == 1
|
|
||||||
extern struct adapter_driver hl_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_OSBDM == 1
|
|
||||||
extern struct adapter_driver osbdm_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_OPENDOUS == 1
|
|
||||||
extern struct adapter_driver opendous_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_SYSFSGPIO == 1
|
|
||||||
extern struct adapter_driver sysfsgpio_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_LINUXGPIOD == 1
|
|
||||||
extern struct adapter_driver linuxgpiod_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_XLNX_PCIE_XVC == 1
|
|
||||||
extern struct adapter_driver xlnx_pcie_xvc_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_BCM2835GPIO == 1
|
|
||||||
extern struct adapter_driver bcm2835gpio_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1
|
|
||||||
extern struct adapter_driver cmsis_dap_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_KITPROG == 1
|
|
||||||
extern struct adapter_driver kitprog_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_IMX_GPIO == 1
|
|
||||||
extern struct adapter_driver imx_gpio_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_XDS110 == 1
|
|
||||||
extern struct adapter_driver xds110_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#if BUILD_HLADAPTER_STLINK == 1
|
|
||||||
extern struct adapter_driver stlink_dap_adapter_driver;
|
|
||||||
#endif
|
|
||||||
#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
|
* The list of built-in JTAG interfaces, containing entries for those
|
||||||
* drivers that were enabled by the @c configure script.
|
* drivers that were enabled by the @c configure script.
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#define OPENOCD_JTAG_JTAG_H
|
#define OPENOCD_JTAG_JTAG_H
|
||||||
|
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
|
#include <helper/command.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
#include <helper/replacements.h>
|
#include <helper/replacements.h>
|
||||||
|
|
||||||
|
@ -602,6 +603,6 @@ void jtag_poll_unmask(bool saved);
|
||||||
|
|
||||||
#include <jtag/minidriver.h>
|
#include <jtag/minidriver.h>
|
||||||
|
|
||||||
int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
|
__COMMAND_HANDLER(handle_jtag_newtap);
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_JTAG_H */
|
#endif /* OPENOCD_JTAG_JTAG_H */
|
||||||
|
|
373
src/jtag/tcl.c
373
src/jtag/tcl.c
|
@ -31,6 +31,8 @@
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <helper/command.h>
|
||||||
|
#include <helper/nvp.h>
|
||||||
#include <helper/time_support.h>
|
#include <helper/time_support.h>
|
||||||
#include "transport/transport.h"
|
#include "transport/transport.h"
|
||||||
|
|
||||||
|
@ -376,39 +378,6 @@ static int jtag_tap_configure_cmd(struct jim_getopt_info *goi, struct jtag_tap *
|
||||||
return JIM_OK;
|
return JIM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_bad_irval(int ir_length, jim_wide w)
|
|
||||||
{
|
|
||||||
jim_wide v = 1;
|
|
||||||
|
|
||||||
v <<= ir_length;
|
|
||||||
v -= 1;
|
|
||||||
v = ~v;
|
|
||||||
return (w & v) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi,
|
|
||||||
struct jtag_tap *tap)
|
|
||||||
{
|
|
||||||
jim_wide w;
|
|
||||||
int e = jim_getopt_wide(goi, &w);
|
|
||||||
if (e != JIM_OK) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t *p = realloc(tap->expected_ids,
|
|
||||||
(tap->expected_ids_cnt + 1) * sizeof(uint32_t));
|
|
||||||
if (!p) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "no memory");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
tap->expected_ids = p;
|
|
||||||
tap->expected_ids[tap->expected_ids_cnt++] = w;
|
|
||||||
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NTAP_OPT_IRLEN 0
|
#define NTAP_OPT_IRLEN 0
|
||||||
#define NTAP_OPT_IRMASK 1
|
#define NTAP_OPT_IRMASK 1
|
||||||
#define NTAP_OPT_IRCAPTURE 2
|
#define NTAP_OPT_IRCAPTURE 2
|
||||||
|
@ -418,166 +387,155 @@ static int jim_newtap_expected_id(struct jim_nvp *n, struct jim_getopt_info *goi
|
||||||
#define NTAP_OPT_VERSION 6
|
#define NTAP_OPT_VERSION 6
|
||||||
#define NTAP_OPT_BYPASS 7
|
#define NTAP_OPT_BYPASS 7
|
||||||
|
|
||||||
static int jim_newtap_ir_param(struct jim_nvp *n, struct jim_getopt_info *goi,
|
static const struct nvp jtag_newtap_opts[] = {
|
||||||
struct jtag_tap *tap)
|
{ .name = "-irlen", .value = NTAP_OPT_IRLEN },
|
||||||
|
{ .name = "-irmask", .value = NTAP_OPT_IRMASK },
|
||||||
|
{ .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE },
|
||||||
|
{ .name = "-enable", .value = NTAP_OPT_ENABLED },
|
||||||
|
{ .name = "-disable", .value = NTAP_OPT_DISABLED },
|
||||||
|
{ .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID },
|
||||||
|
{ .name = "-ignore-version", .value = NTAP_OPT_VERSION },
|
||||||
|
{ .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS },
|
||||||
|
{ .name = NULL, .value = -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static COMMAND_HELPER(handle_jtag_newtap_args, struct jtag_tap *tap)
|
||||||
{
|
{
|
||||||
jim_wide w;
|
/* we expect CHIP + TAP + OPTIONS */
|
||||||
int e = jim_getopt_wide(goi, &w);
|
if (CMD_ARGC < 2)
|
||||||
if (e != JIM_OK) {
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
Jim_SetResultFormatted(goi->interp,
|
|
||||||
"option: %s bad parameter", n->name);
|
tap->chip = strdup(CMD_ARGV[0]);
|
||||||
return e;
|
tap->tapname = strdup(CMD_ARGV[1]);
|
||||||
|
tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]);
|
||||||
|
if (!tap->chip || !tap->tapname || !tap->dotted_name) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
switch (n->value) {
|
CMD_ARGC -= 2;
|
||||||
case NTAP_OPT_IRLEN:
|
CMD_ARGV += 2;
|
||||||
if (w > (jim_wide) (8 * sizeof(tap->ir_capture_value))) {
|
|
||||||
LOG_WARNING("%s: huge IR length %d",
|
|
||||||
tap->dotted_name, (int) w);
|
|
||||||
}
|
|
||||||
tap->ir_length = w;
|
|
||||||
break;
|
|
||||||
case NTAP_OPT_IRMASK:
|
|
||||||
if (is_bad_irval(tap->ir_length, w)) {
|
|
||||||
LOG_ERROR("%s: IR mask %x too big",
|
|
||||||
tap->dotted_name,
|
|
||||||
(int) w);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
if ((w & 3) != 3)
|
|
||||||
LOG_WARNING("%s: nonstandard IR mask", tap->dotted_name);
|
|
||||||
tap->ir_capture_mask = w;
|
|
||||||
break;
|
|
||||||
case NTAP_OPT_IRCAPTURE:
|
|
||||||
if (is_bad_irval(tap->ir_length, w)) {
|
|
||||||
LOG_ERROR("%s: IR capture %x too big",
|
|
||||||
tap->dotted_name, (int) w);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
if ((w & 3) != 1)
|
|
||||||
LOG_WARNING("%s: nonstandard IR value",
|
|
||||||
tap->dotted_name);
|
|
||||||
tap->ir_capture_value = w;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
return JIM_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jim_newtap_cmd(struct jim_getopt_info *goi)
|
|
||||||
{
|
|
||||||
struct jtag_tap *tap;
|
|
||||||
int x;
|
|
||||||
int e;
|
|
||||||
struct jim_nvp *n;
|
|
||||||
char *cp;
|
|
||||||
const struct jim_nvp opts[] = {
|
|
||||||
{ .name = "-irlen", .value = NTAP_OPT_IRLEN },
|
|
||||||
{ .name = "-irmask", .value = NTAP_OPT_IRMASK },
|
|
||||||
{ .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE },
|
|
||||||
{ .name = "-enable", .value = NTAP_OPT_ENABLED },
|
|
||||||
{ .name = "-disable", .value = NTAP_OPT_DISABLED },
|
|
||||||
{ .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID },
|
|
||||||
{ .name = "-ignore-version", .value = NTAP_OPT_VERSION },
|
|
||||||
{ .name = "-ignore-bypass", .value = NTAP_OPT_BYPASS },
|
|
||||||
{ .name = NULL, .value = -1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
tap = calloc(1, sizeof(struct jtag_tap));
|
|
||||||
if (!tap) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "no memory");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* we expect CHIP + TAP + OPTIONS
|
|
||||||
* */
|
|
||||||
if (goi->argc < 3) {
|
|
||||||
Jim_SetResultFormatted(goi->interp, "Missing CHIP TAP OPTIONS ....");
|
|
||||||
free(tap);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *tmp;
|
|
||||||
jim_getopt_string(goi, &tmp, NULL);
|
|
||||||
tap->chip = strdup(tmp);
|
|
||||||
|
|
||||||
jim_getopt_string(goi, &tmp, NULL);
|
|
||||||
tap->tapname = strdup(tmp);
|
|
||||||
|
|
||||||
/* name + dot + name + null */
|
|
||||||
x = strlen(tap->chip) + 1 + strlen(tap->tapname) + 1;
|
|
||||||
cp = malloc(x);
|
|
||||||
sprintf(cp, "%s.%s", tap->chip, tap->tapname);
|
|
||||||
tap->dotted_name = cp;
|
|
||||||
|
|
||||||
LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
|
LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params",
|
||||||
tap->chip, tap->tapname, tap->dotted_name, goi->argc);
|
tap->chip, tap->tapname, tap->dotted_name, CMD_ARGC);
|
||||||
|
|
||||||
/* IEEE specifies that the two LSBs of an IR scan are 01, so make
|
/*
|
||||||
|
* IEEE specifies that the two LSBs of an IR scan are 01, so make
|
||||||
* that the default. The "-ircapture" and "-irmask" options are only
|
* that the default. The "-ircapture" and "-irmask" options are only
|
||||||
* needed to cope with nonstandard TAPs, or to specify more bits.
|
* needed to cope with nonstandard TAPs, or to specify more bits.
|
||||||
*/
|
*/
|
||||||
tap->ir_capture_mask = 0x03;
|
tap->ir_capture_mask = 0x03;
|
||||||
tap->ir_capture_value = 0x01;
|
tap->ir_capture_value = 0x01;
|
||||||
|
|
||||||
while (goi->argc) {
|
while (CMD_ARGC) {
|
||||||
e = jim_getopt_nvp(goi, opts, &n);
|
const struct nvp *n = nvp_name2value(jtag_newtap_opts, CMD_ARGV[0]);
|
||||||
if (e != JIM_OK) {
|
CMD_ARGC--;
|
||||||
jim_getopt_nvp_unknown(goi, opts, 0);
|
CMD_ARGV++;
|
||||||
free(cp);
|
|
||||||
free(tap);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Processing option: %s", n->name);
|
|
||||||
switch (n->value) {
|
switch (n->value) {
|
||||||
case NTAP_OPT_ENABLED:
|
case NTAP_OPT_ENABLED:
|
||||||
tap->disabled_after_reset = false;
|
tap->disabled_after_reset = false;
|
||||||
break;
|
break;
|
||||||
case NTAP_OPT_DISABLED:
|
|
||||||
tap->disabled_after_reset = true;
|
case NTAP_OPT_DISABLED:
|
||||||
break;
|
tap->disabled_after_reset = true;
|
||||||
case NTAP_OPT_EXPECTED_ID:
|
break;
|
||||||
e = jim_newtap_expected_id(n, goi, tap);
|
|
||||||
if (e != JIM_OK) {
|
case NTAP_OPT_EXPECTED_ID:
|
||||||
free(cp);
|
if (!CMD_ARGC)
|
||||||
free(tap);
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
return e;
|
|
||||||
}
|
tap->expected_ids = realloc(tap->expected_ids,
|
||||||
break;
|
(tap->expected_ids_cnt + 1) * sizeof(uint32_t));
|
||||||
case NTAP_OPT_IRLEN:
|
if (!tap->expected_ids) {
|
||||||
case NTAP_OPT_IRMASK:
|
LOG_ERROR("Out of memory");
|
||||||
case NTAP_OPT_IRCAPTURE:
|
return ERROR_FAIL;
|
||||||
e = jim_newtap_ir_param(n, goi, tap);
|
}
|
||||||
if (e != JIM_OK) {
|
|
||||||
free(cp);
|
uint32_t id;
|
||||||
free(tap);
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], id);
|
||||||
return e;
|
CMD_ARGC--;
|
||||||
}
|
CMD_ARGV++;
|
||||||
break;
|
tap->expected_ids[tap->expected_ids_cnt++] = id;
|
||||||
case NTAP_OPT_VERSION:
|
|
||||||
tap->ignore_version = true;
|
break;
|
||||||
break;
|
|
||||||
case NTAP_OPT_BYPASS:
|
case NTAP_OPT_IRLEN:
|
||||||
tap->ignore_bypass = true;
|
if (!CMD_ARGC)
|
||||||
break;
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
} /* switch (n->value) */
|
|
||||||
} /* while (goi->argc) */
|
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tap->ir_length);
|
||||||
|
CMD_ARGC--;
|
||||||
|
CMD_ARGV++;
|
||||||
|
if (tap->ir_length > (int)(8 * sizeof(tap->ir_capture_value)))
|
||||||
|
LOG_WARNING("%s: huge IR length %d", tap->dotted_name, tap->ir_length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NTAP_OPT_IRMASK:
|
||||||
|
if (!CMD_ARGC)
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_mask);
|
||||||
|
CMD_ARGC--;
|
||||||
|
CMD_ARGV++;
|
||||||
|
if ((tap->ir_capture_mask & 3) != 3)
|
||||||
|
LOG_WARNING("%s: nonstandard IR mask", tap->dotted_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NTAP_OPT_IRCAPTURE:
|
||||||
|
if (!CMD_ARGC)
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], tap->ir_capture_value);
|
||||||
|
CMD_ARGC--;
|
||||||
|
CMD_ARGV++;
|
||||||
|
if ((tap->ir_capture_value & 3) != 1)
|
||||||
|
LOG_WARNING("%s: nonstandard IR value", tap->dotted_name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NTAP_OPT_VERSION:
|
||||||
|
tap->ignore_version = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NTAP_OPT_BYPASS:
|
||||||
|
tap->ignore_bypass = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
nvp_unknown_command_print(CMD, jtag_newtap_opts, NULL, CMD_ARGV[-1]);
|
||||||
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* default is enabled-after-reset */
|
/* default is enabled-after-reset */
|
||||||
tap->enabled = !tap->disabled_after_reset;
|
tap->enabled = !tap->disabled_after_reset;
|
||||||
|
|
||||||
/* Did all the required option bits get cleared? */
|
if (transport_is_jtag() && tap->ir_length == 0) {
|
||||||
if (!transport_is_jtag() || tap->ir_length != 0) {
|
command_print(CMD, "newtap: %s missing IR length", tap->dotted_name);
|
||||||
jtag_tap_init(tap);
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
return JIM_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Jim_SetResultFormatted(goi->interp,
|
return ERROR_OK;
|
||||||
"newtap: %s missing IR length",
|
}
|
||||||
tap->dotted_name);
|
|
||||||
jtag_tap_free(tap);
|
__COMMAND_HANDLER(handle_jtag_newtap)
|
||||||
return JIM_ERR;
|
{
|
||||||
|
struct jtag_tap *tap = calloc(1, sizeof(struct jtag_tap));
|
||||||
|
if (!tap) {
|
||||||
|
LOG_ERROR("Out of memory");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = CALL_COMMAND_HANDLER(handle_jtag_newtap_args, tap);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
free(tap->chip);
|
||||||
|
free(tap->tapname);
|
||||||
|
free(tap->dotted_name);
|
||||||
|
free(tap->expected_ids);
|
||||||
|
free(tap);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
jtag_tap_init(tap);
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e)
|
static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e)
|
||||||
|
@ -643,17 +601,10 @@ COMMAND_HANDLER(handle_jtag_arp_init_reset)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|
||||||
{
|
|
||||||
struct jim_getopt_info goi;
|
|
||||||
jim_getopt_setup(&goi, interp, argc-1, argv + 1);
|
|
||||||
return jim_newtap_cmd(&goi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool jtag_tap_enable(struct jtag_tap *t)
|
static bool jtag_tap_enable(struct jtag_tap *t)
|
||||||
{
|
{
|
||||||
if (t->enabled)
|
if (t->enabled)
|
||||||
return false;
|
return true;
|
||||||
jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE);
|
jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE);
|
||||||
if (!t->enabled)
|
if (!t->enabled)
|
||||||
return false;
|
return false;
|
||||||
|
@ -668,7 +619,7 @@ static bool jtag_tap_enable(struct jtag_tap *t)
|
||||||
static bool jtag_tap_disable(struct jtag_tap *t)
|
static bool jtag_tap_disable(struct jtag_tap *t)
|
||||||
{
|
{
|
||||||
if (!t->enabled)
|
if (!t->enabled)
|
||||||
return false;
|
return true;
|
||||||
jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE);
|
jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE);
|
||||||
if (t->enabled)
|
if (t->enabled)
|
||||||
return false;
|
return false;
|
||||||
|
@ -681,42 +632,36 @@ static bool jtag_tap_disable(struct jtag_tap *t)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
__COMMAND_HANDLER(handle_jtag_tap_enabler)
|
||||||
{
|
{
|
||||||
struct command *c = jim_to_command(interp);
|
if (CMD_ARGC != 1)
|
||||||
const char *cmd_name = c->name;
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
struct jim_getopt_info goi;
|
|
||||||
jim_getopt_setup(&goi, interp, argc-1, argv + 1);
|
struct jtag_tap *t = jtag_tap_by_string(CMD_ARGV[0]);
|
||||||
if (goi.argc != 1) {
|
if (!t) {
|
||||||
Jim_SetResultFormatted(goi.interp, "usage: %s <name>", cmd_name);
|
command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]);
|
||||||
return JIM_ERR;
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct jtag_tap *t;
|
if (strcmp(CMD_NAME, "tapisenabled") == 0) {
|
||||||
|
|
||||||
t = jtag_tap_by_jim_obj(goi.interp, goi.argv[0]);
|
|
||||||
if (!t)
|
|
||||||
return JIM_ERR;
|
|
||||||
|
|
||||||
if (strcasecmp(cmd_name, "tapisenabled") == 0) {
|
|
||||||
/* do nothing, just return the value */
|
/* do nothing, just return the value */
|
||||||
} else if (strcasecmp(cmd_name, "tapenable") == 0) {
|
} else if (strcmp(CMD_NAME, "tapenable") == 0) {
|
||||||
if (!jtag_tap_enable(t)) {
|
if (!jtag_tap_enable(t)) {
|
||||||
LOG_WARNING("failed to enable tap %s", t->dotted_name);
|
command_print(CMD, "failed to enable tap %s", t->dotted_name);
|
||||||
return JIM_ERR;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
} else if (strcasecmp(cmd_name, "tapdisable") == 0) {
|
} else if (strcmp(CMD_NAME, "tapdisable") == 0) {
|
||||||
if (!jtag_tap_disable(t)) {
|
if (!jtag_tap_disable(t)) {
|
||||||
LOG_WARNING("failed to disable tap %s", t->dotted_name);
|
command_print(CMD, "failed to disable tap %s", t->dotted_name);
|
||||||
return JIM_ERR;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("command '%s' unknown", cmd_name);
|
command_print(CMD, "command '%s' unknown", CMD_NAME);
|
||||||
return JIM_ERR;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
bool e = t->enabled;
|
|
||||||
Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, e));
|
command_print(CMD, "%d", t->enabled ? 1 : 0);
|
||||||
return JIM_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||||
|
@ -798,7 +743,7 @@ static const struct command_registration jtag_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "newtap",
|
.name = "newtap",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.help = "Create a new TAP instance named basename.tap_type, "
|
.help = "Create a new TAP instance named basename.tap_type, "
|
||||||
"and appends it to the scan chain.",
|
"and appends it to the scan chain.",
|
||||||
.usage = "basename tap_type '-irlen' count "
|
.usage = "basename tap_type '-irlen' count "
|
||||||
|
@ -812,7 +757,7 @@ static const struct command_registration jtag_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "tapisenabled",
|
.name = "tapisenabled",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
.help = "Returns a Tcl boolean (0/1) indicating whether "
|
.help = "Returns a Tcl boolean (0/1) indicating whether "
|
||||||
"the TAP is enabled (1) or not (0).",
|
"the TAP is enabled (1) or not (0).",
|
||||||
.usage = "tap_name",
|
.usage = "tap_name",
|
||||||
|
@ -820,7 +765,7 @@ static const struct command_registration jtag_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "tapenable",
|
.name = "tapenable",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
.help = "Try to enable the specified TAP using the "
|
.help = "Try to enable the specified TAP using the "
|
||||||
"'tap-enable' TAP event.",
|
"'tap-enable' TAP event.",
|
||||||
.usage = "tap_name",
|
.usage = "tap_name",
|
||||||
|
@ -828,7 +773,7 @@ static const struct command_registration jtag_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "tapdisable",
|
.name = "tapdisable",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
.help = "Try to disable the specified TAP using the "
|
.help = "Try to disable the specified TAP using the "
|
||||||
"'tap-disable' TAP event.",
|
"'tap-disable' TAP event.",
|
||||||
.usage = "tap_name",
|
.usage = "tap_name",
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
#ifndef OPENOCD_JTAG_TCL_H
|
#ifndef OPENOCD_JTAG_TCL_H
|
||||||
#define OPENOCD_JTAG_TCL_H
|
#define OPENOCD_JTAG_TCL_H
|
||||||
|
|
||||||
|
#include <helper/command.h>
|
||||||
|
|
||||||
int jim_jtag_configure(Jim_Interp *interp, int argc,
|
int jim_jtag_configure(Jim_Interp *interp, int argc,
|
||||||
Jim_Obj * const *argv);
|
Jim_Obj * const *argv);
|
||||||
int jim_jtag_tap_enabler(Jim_Interp *interp, int argc,
|
__COMMAND_HANDLER(handle_jtag_tap_enabler);
|
||||||
Jim_Obj * const *argv);
|
|
||||||
|
|
||||||
#endif /* OPENOCD_JTAG_TCL_H */
|
#endif /* OPENOCD_JTAG_TCL_H */
|
||||||
|
|
|
@ -29,7 +29,7 @@ static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
bit_file->part = 0;
|
bit_file->part = NULL;
|
||||||
bit_file->has_id = false;
|
bit_file->has_id = false;
|
||||||
enum read_bit_state state = SEEK_HEADER_START;
|
enum read_bit_state state = SEEK_HEADER_START;
|
||||||
for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) {
|
for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) {
|
||||||
|
|
|
@ -156,8 +156,6 @@ COMMAND_HANDLER(handle_pld_load_command)
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
command_print(CMD, "failed loading file %s to pld device %u",
|
command_print(CMD, "failed loading file %s to pld device %u",
|
||||||
CMD_ARGV[1], dev_id);
|
CMD_ARGV[1], dev_id);
|
||||||
switch (retval) {
|
|
||||||
}
|
|
||||||
return retval;
|
return retval;
|
||||||
} else {
|
} else {
|
||||||
gettimeofday(&end, NULL);
|
gettimeofday(&end, NULL);
|
||||||
|
|
|
@ -241,9 +241,13 @@ COMMAND_HANDLER(virtex2_handle_read_stat_command)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtex2_read_stat(device, &status);
|
int retval = virtex2_read_stat(device, &status);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD, "cannot read virtex2 status register");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
command_print(CMD, "virtex2 status register: 0x%8.8" PRIx32 "", status);
|
command_print(CMD, "virtex2 status register: 0x%8.8" PRIx32, status);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1161,9 +1161,6 @@ static bool ecos_detect_rtos(struct target *target)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int rtos_thread_packet(struct connection *connection,
|
|
||||||
const char *packet, int packet_size);
|
|
||||||
|
|
||||||
/* Since we should never have 0 as a valid eCos thread ID we use $Hg0 as the
|
/* Since we should never have 0 as a valid eCos thread ID we use $Hg0 as the
|
||||||
* indicator of a new session as regards flushing any cached state. */
|
* indicator of a new session as regards flushing any cached state. */
|
||||||
static int ecos_packet_hook(struct connection *connection,
|
static int ecos_packet_hook(struct connection *connection,
|
||||||
|
|
|
@ -35,8 +35,6 @@ struct target *hwthread_swbp_target(struct rtos *rtos, target_addr_t address,
|
||||||
|
|
||||||
#define HW_THREAD_NAME_STR_SIZE (32)
|
#define HW_THREAD_NAME_STR_SIZE (32)
|
||||||
|
|
||||||
extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
|
|
||||||
|
|
||||||
static inline threadid_t threadid_from_target(const struct target *target)
|
static inline threadid_t threadid_from_target(const struct target *target)
|
||||||
{
|
{
|
||||||
return target->coreid + 1;
|
return target->coreid + 1;
|
||||||
|
|
|
@ -37,8 +37,6 @@ static const struct rtos_type *rtos_types[] = {
|
||||||
|
|
||||||
static int rtos_try_next(struct target *target);
|
static int rtos_try_next(struct target *target);
|
||||||
|
|
||||||
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
|
|
||||||
|
|
||||||
int rtos_smp_init(struct target *target)
|
int rtos_smp_init(struct target *target)
|
||||||
{
|
{
|
||||||
if (target->rtos->type->smp_init)
|
if (target->rtos->type->smp_init)
|
||||||
|
|
|
@ -157,6 +157,7 @@ int rtos_generic_stack_write_reg(struct target *target,
|
||||||
target_addr_t stack_ptr,
|
target_addr_t stack_ptr,
|
||||||
uint32_t reg_num, uint8_t *reg_value);
|
uint32_t reg_num, uint8_t *reg_value);
|
||||||
int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size);
|
int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size);
|
||||||
|
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
|
||||||
int rtos_get_gdb_reg(struct connection *connection, int reg_num);
|
int rtos_get_gdb_reg(struct connection *connection, int reg_num);
|
||||||
int rtos_get_gdb_reg_list(struct connection *connection);
|
int rtos_get_gdb_reg_list(struct connection *connection);
|
||||||
int rtos_update_threads(struct target *target);
|
int rtos_update_threads(struct target *target);
|
||||||
|
|
|
@ -29,6 +29,12 @@
|
||||||
struct ucos_iii_params {
|
struct ucos_iii_params {
|
||||||
const char *target_name;
|
const char *target_name;
|
||||||
const unsigned char pointer_width;
|
const unsigned char pointer_width;
|
||||||
|
size_t threadid_start;
|
||||||
|
const struct rtos_register_stacking *stacking_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ucos_iii_private {
|
||||||
|
const struct ucos_iii_params *params;
|
||||||
symbol_address_t thread_stack_offset;
|
symbol_address_t thread_stack_offset;
|
||||||
symbol_address_t thread_name_offset;
|
symbol_address_t thread_name_offset;
|
||||||
symbol_address_t thread_state_offset;
|
symbol_address_t thread_state_offset;
|
||||||
|
@ -36,40 +42,22 @@ struct ucos_iii_params {
|
||||||
symbol_address_t thread_prev_offset;
|
symbol_address_t thread_prev_offset;
|
||||||
symbol_address_t thread_next_offset;
|
symbol_address_t thread_next_offset;
|
||||||
bool thread_offsets_updated;
|
bool thread_offsets_updated;
|
||||||
size_t threadid_start;
|
|
||||||
const struct rtos_register_stacking *stacking_info;
|
|
||||||
size_t num_threads;
|
size_t num_threads;
|
||||||
symbol_address_t threads[];
|
symbol_address_t threads[UCOS_III_MAX_THREADS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct ucos_iii_params ucos_iii_params_list[] = {
|
static const struct ucos_iii_params ucos_iii_params_list[] = {
|
||||||
{
|
{
|
||||||
"cortex_m", /* target_name */
|
.target_name = "cortex_m",
|
||||||
sizeof(uint32_t), /* pointer_width */
|
.pointer_width = sizeof(uint32_t),
|
||||||
0, /* thread_stack_offset */
|
.threadid_start = 1,
|
||||||
0, /* thread_name_offset */
|
.stacking_info = &rtos_ucos_iii_cortex_m_stacking,
|
||||||
0, /* thread_state_offset */
|
|
||||||
0, /* thread_priority_offset */
|
|
||||||
0, /* thread_prev_offset */
|
|
||||||
0, /* thread_next_offset */
|
|
||||||
false, /* thread_offsets_updated */
|
|
||||||
1, /* threadid_start */
|
|
||||||
&rtos_ucos_iii_cortex_m_stacking, /* stacking_info */
|
|
||||||
0, /* num_threads */
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"esirisc", /* target_name */
|
.target_name = "esirisc",
|
||||||
sizeof(uint32_t), /* pointer_width */
|
.pointer_width = sizeof(uint32_t),
|
||||||
0, /* thread_stack_offset */
|
.threadid_start = 1,
|
||||||
0, /* thread_name_offset */
|
.stacking_info = &rtos_ucos_iii_esi_risc_stacking,
|
||||||
0, /* thread_state_offset */
|
|
||||||
0, /* thread_priority_offset */
|
|
||||||
0, /* thread_prev_offset */
|
|
||||||
0, /* thread_next_offset */
|
|
||||||
false, /* thread_offsets_updated */
|
|
||||||
1, /* threadid_start */
|
|
||||||
&rtos_ucos_iii_esi_risc_stacking, /* stacking_info */
|
|
||||||
0, /* num_threads */
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,7 +106,7 @@ static const char * const ucos_iii_thread_state_list[] = {
|
||||||
static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
|
static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t thread_address,
|
||||||
threadid_t *threadid)
|
threadid_t *threadid)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
size_t thread_index;
|
size_t thread_index;
|
||||||
|
|
||||||
for (thread_index = 0; thread_index < params->num_threads; thread_index++)
|
for (thread_index = 0; thread_index < params->num_threads; thread_index++)
|
||||||
|
@ -133,17 +121,17 @@ static int ucos_iii_find_or_create_thread(struct rtos *rtos, symbol_address_t th
|
||||||
params->threads[thread_index] = thread_address;
|
params->threads[thread_index] = thread_address;
|
||||||
params->num_threads++;
|
params->num_threads++;
|
||||||
found:
|
found:
|
||||||
*threadid = thread_index + params->threadid_start;
|
*threadid = thread_index + params->params->threadid_start;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid,
|
static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid,
|
||||||
symbol_address_t *thread_address)
|
symbol_address_t *thread_address)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
size_t thread_index;
|
size_t thread_index;
|
||||||
|
|
||||||
thread_index = threadid - params->threadid_start;
|
thread_index = threadid - params->params->threadid_start;
|
||||||
if (thread_index >= params->num_threads) {
|
if (thread_index >= params->num_threads) {
|
||||||
LOG_ERROR("uCOS-III: failed to find thread address");
|
LOG_ERROR("uCOS-III: failed to find thread address");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -155,7 +143,7 @@ static int ucos_iii_find_thread_address(struct rtos *rtos, threadid_t threadid,
|
||||||
|
|
||||||
static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
|
static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t *thread_address)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* read the thread list head */
|
/* read the thread list head */
|
||||||
|
@ -163,7 +151,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t
|
||||||
|
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
rtos->symbols[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR].address,
|
rtos->symbols[UCOS_III_VAL_OS_TASK_DBG_LIST_PTR].address,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)&thread_list_address);
|
(void *)&thread_list_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -177,7 +165,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t
|
||||||
|
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
thread_list_address + params->thread_next_offset,
|
thread_list_address + params->thread_next_offset,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)&thread_list_address);
|
(void *)&thread_list_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -191,7 +179,7 @@ static int ucos_iii_find_last_thread_address(struct rtos *rtos, symbol_address_t
|
||||||
|
|
||||||
static int ucos_iii_update_thread_offsets(struct rtos *rtos)
|
static int ucos_iii_update_thread_offsets(struct rtos *rtos)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
|
|
||||||
if (params->thread_offsets_updated)
|
if (params->thread_offsets_updated)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -231,7 +219,7 @@ static int ucos_iii_update_thread_offsets(struct rtos *rtos)
|
||||||
|
|
||||||
int retval = target_read_memory(rtos->target,
|
int retval = target_read_memory(rtos->target,
|
||||||
rtos->symbols[thread_offset_map->symbol_value].address,
|
rtos->symbols[thread_offset_map->symbol_value].address,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)thread_offset_map->thread_offset);
|
(void *)thread_offset_map->thread_offset);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -252,7 +240,7 @@ static bool ucos_iii_detect_rtos(struct target *target)
|
||||||
|
|
||||||
static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
|
static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode reset_mode, void *priv)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = target->rtos->rtos_specific_params;
|
struct ucos_iii_private *params = target->rtos->rtos_specific_params;
|
||||||
|
|
||||||
params->thread_offsets_updated = false;
|
params->thread_offsets_updated = false;
|
||||||
params->num_threads = 0;
|
params->num_threads = 0;
|
||||||
|
@ -262,17 +250,17 @@ static int ucos_iii_reset_handler(struct target *target, enum target_reset_mode
|
||||||
|
|
||||||
static int ucos_iii_create(struct target *target)
|
static int ucos_iii_create(struct target *target)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params;
|
struct ucos_iii_private *params;
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_params_list); i++)
|
for (size_t i = 0; i < ARRAY_SIZE(ucos_iii_params_list); i++)
|
||||||
if (strcmp(ucos_iii_params_list[i].target_name, target->type->name) == 0) {
|
if (strcmp(ucos_iii_params_list[i].target_name, target->type->name) == 0) {
|
||||||
params = malloc(sizeof(*params) + (UCOS_III_MAX_THREADS * sizeof(*params->threads)));
|
params = calloc(1, sizeof(*params));
|
||||||
if (!params) {
|
if (!params) {
|
||||||
LOG_ERROR("uCOS-III: out of memory");
|
LOG_ERROR("uCOS-III: out of memory");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(params, &ucos_iii_params_list[i], sizeof(ucos_iii_params_list[i]));
|
params->params = &ucos_iii_params_list[i];
|
||||||
target->rtos->rtos_specific_params = (void *)params;
|
target->rtos->rtos_specific_params = (void *)params;
|
||||||
|
|
||||||
target_register_reset_callback(ucos_iii_reset_handler, NULL);
|
target_register_reset_callback(ucos_iii_reset_handler, NULL);
|
||||||
|
@ -286,7 +274,7 @@ static int ucos_iii_create(struct target *target)
|
||||||
|
|
||||||
static int ucos_iii_update_threads(struct rtos *rtos)
|
static int ucos_iii_update_threads(struct rtos *rtos)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (!rtos->symbols) {
|
if (!rtos->symbols) {
|
||||||
|
@ -340,7 +328,7 @@ static int ucos_iii_update_threads(struct rtos *rtos)
|
||||||
|
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
rtos->symbols[UCOS_III_VAL_OS_TCB_CUR_PTR].address,
|
rtos->symbols[UCOS_III_VAL_OS_TCB_CUR_PTR].address,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)¤t_thread_address);
|
(void *)¤t_thread_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -396,7 +384,7 @@ static int ucos_iii_update_threads(struct rtos *rtos)
|
||||||
|
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
thread_address + params->thread_name_offset,
|
thread_address + params->thread_name_offset,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)&thread_name_address);
|
(void *)&thread_name_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -450,7 +438,7 @@ static int ucos_iii_update_threads(struct rtos *rtos)
|
||||||
/* read previous thread address */
|
/* read previous thread address */
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
thread_address + params->thread_prev_offset,
|
thread_address + params->thread_prev_offset,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)&thread_address);
|
(void *)&thread_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -465,7 +453,7 @@ static int ucos_iii_update_threads(struct rtos *rtos)
|
||||||
static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
|
static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
|
||||||
struct rtos_reg **reg_list, int *num_regs)
|
struct rtos_reg **reg_list, int *num_regs)
|
||||||
{
|
{
|
||||||
struct ucos_iii_params *params = rtos->rtos_specific_params;
|
struct ucos_iii_private *params = rtos->rtos_specific_params;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
/* find thread address for threadid */
|
/* find thread address for threadid */
|
||||||
|
@ -482,7 +470,7 @@ static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
|
||||||
|
|
||||||
retval = target_read_memory(rtos->target,
|
retval = target_read_memory(rtos->target,
|
||||||
thread_address + params->thread_stack_offset,
|
thread_address + params->thread_stack_offset,
|
||||||
params->pointer_width,
|
params->params->pointer_width,
|
||||||
1,
|
1,
|
||||||
(void *)&stack_address);
|
(void *)&stack_address);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
|
@ -491,7 +479,7 @@ static int ucos_iii_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
|
||||||
}
|
}
|
||||||
|
|
||||||
return rtos_generic_stack_read(rtos->target,
|
return rtos_generic_stack_read(rtos->target,
|
||||||
params->stacking_info,
|
params->params->stacking_info,
|
||||||
stack_address,
|
stack_address,
|
||||||
reg_list,
|
reg_list,
|
||||||
num_regs);
|
num_regs);
|
||||||
|
|
|
@ -117,7 +117,7 @@ static void gdb_sig_halted(struct connection *connection);
|
||||||
|
|
||||||
/* number of gdb connections, mainly to suppress gdb related debugging spam
|
/* number of gdb connections, mainly to suppress gdb related debugging spam
|
||||||
* in helper/log.c when no gdb connections are actually active */
|
* in helper/log.c when no gdb connections are actually active */
|
||||||
int gdb_actual_connections;
|
static int gdb_actual_connections;
|
||||||
|
|
||||||
/* set if we are sending a memory map to gdb
|
/* set if we are sending a memory map to gdb
|
||||||
* via qXfer:memory-map:read packet */
|
* via qXfer:memory-map:read packet */
|
||||||
|
@ -186,6 +186,9 @@ static bool gdb_connection_includes_target(struct connection *connection, struct
|
||||||
|
|
||||||
static int gdb_last_signal(struct target *target)
|
static int gdb_last_signal(struct target *target)
|
||||||
{
|
{
|
||||||
|
LOG_TARGET_DEBUG(target, "Debug reason is: %s",
|
||||||
|
target_debug_reason_str(target->debug_reason));
|
||||||
|
|
||||||
switch (target->debug_reason) {
|
switch (target->debug_reason) {
|
||||||
case DBG_REASON_DBGRQ:
|
case DBG_REASON_DBGRQ:
|
||||||
return 0x2; /* SIGINT */
|
return 0x2; /* SIGINT */
|
||||||
|
@ -200,8 +203,9 @@ static int gdb_last_signal(struct target *target)
|
||||||
case DBG_REASON_NOTHALTED:
|
case DBG_REASON_NOTHALTED:
|
||||||
return 0x0; /* no signal... shouldn't happen */
|
return 0x0; /* no signal... shouldn't happen */
|
||||||
default:
|
default:
|
||||||
LOG_USER("undefined debug reason %d - target needs reset",
|
LOG_USER("undefined debug reason %d (%s) - target needs reset",
|
||||||
target->debug_reason);
|
target->debug_reason,
|
||||||
|
target_debug_reason_str(target->debug_reason));
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,39 +276,20 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
errno = WSAGetLastError();
|
bool retry = (WSAGetLastError() == WSAEWOULDBLOCK);
|
||||||
|
|
||||||
switch (errno) {
|
|
||||||
case WSAEWOULDBLOCK:
|
|
||||||
usleep(1000);
|
|
||||||
break;
|
|
||||||
case WSAECONNABORTED:
|
|
||||||
gdb_con->closed = true;
|
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
|
||||||
case WSAECONNRESET:
|
|
||||||
gdb_con->closed = true;
|
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("read: %d", errno);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
switch (errno) {
|
bool retry = (errno == EAGAIN);
|
||||||
case EAGAIN:
|
|
||||||
usleep(1000);
|
|
||||||
break;
|
|
||||||
case ECONNABORTED:
|
|
||||||
gdb_con->closed = true;
|
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
|
||||||
case ECONNRESET:
|
|
||||||
gdb_con->closed = true;
|
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("read: %s", strerror(errno));
|
|
||||||
gdb_con->closed = true;
|
|
||||||
return ERROR_SERVER_REMOTE_CLOSED;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (retry) {
|
||||||
|
// Try again after a delay
|
||||||
|
usleep(1000);
|
||||||
|
} else {
|
||||||
|
// Print error and close the socket
|
||||||
|
log_socket_error("GDB");
|
||||||
|
gdb_con->closed = true;
|
||||||
|
return ERROR_SERVER_REMOTE_CLOSED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _DEBUG_GDB_IO_
|
#ifdef _DEBUG_GDB_IO_
|
||||||
|
@ -844,6 +829,7 @@ static void gdb_signal_reply(struct target *target, struct connection *connectio
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gdb_connection->ctrl_c) {
|
if (gdb_connection->ctrl_c) {
|
||||||
|
LOG_TARGET_DEBUG(target, "Responding with signal 2 (SIGINT) to debugger due to Ctrl-C");
|
||||||
signal_var = 0x2;
|
signal_var = 0x2;
|
||||||
} else
|
} else
|
||||||
signal_var = gdb_last_signal(ct);
|
signal_var = gdb_last_signal(ct);
|
||||||
|
@ -4201,3 +4187,8 @@ void gdb_service_free(void)
|
||||||
free(gdb_port);
|
free(gdb_port);
|
||||||
free(gdb_port_next);
|
free(gdb_port_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gdb_get_actual_connections(void)
|
||||||
|
{
|
||||||
|
return gdb_actual_connections;
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
struct image;
|
struct image;
|
||||||
struct reg;
|
struct reg;
|
||||||
#include <target/target.h>
|
#include <target/target.h>
|
||||||
|
#include <server/server.h>
|
||||||
|
|
||||||
#define GDB_BUFFER_SIZE 16384
|
#define GDB_BUFFER_SIZE 16384
|
||||||
|
|
||||||
|
@ -29,6 +30,8 @@ void gdb_service_free(void);
|
||||||
|
|
||||||
int gdb_put_packet(struct connection *connection, char *buffer, int len);
|
int gdb_put_packet(struct connection *connection, char *buffer, int len);
|
||||||
|
|
||||||
|
int gdb_get_actual_connections(void);
|
||||||
|
|
||||||
static inline struct target *get_target_from_connection(struct connection *connection)
|
static inline struct target *get_target_from_connection(struct connection *connection)
|
||||||
{
|
{
|
||||||
struct gdb_service *gdb_service = connection->service->priv;
|
struct gdb_service *gdb_service = connection->service->priv;
|
||||||
|
|
|
@ -58,8 +58,15 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] =
|
||||||
{
|
{
|
||||||
.name = "newtap",
|
.name = "newtap",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.help = "declare a new TAP"
|
.help = "declare a new TAP",
|
||||||
|
.usage = "basename tap_type '-irlen' count "
|
||||||
|
"['-enable'|'-disable'] "
|
||||||
|
"['-expected_id' number] "
|
||||||
|
"['-ignore-version'] "
|
||||||
|
"['-ignore-bypass'] "
|
||||||
|
"['-ircapture' number] "
|
||||||
|
"['-mask' number]",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "init",
|
.name = "init",
|
||||||
|
@ -82,12 +89,18 @@ static const struct command_registration dapdirect_jtag_subcommand_handlers[] =
|
||||||
{
|
{
|
||||||
.name = "tapisenabled",
|
.name = "tapisenabled",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
|
.help = "Returns a Tcl boolean (0/1) indicating whether "
|
||||||
|
"the TAP is enabled (1) or not (0).",
|
||||||
|
.usage = "tap_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "tapenable",
|
.name = "tapenable",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_jtag_tap_enabler,
|
.handler = handle_jtag_tap_enabler,
|
||||||
|
.help = "Try to enable the specified TAP using the "
|
||||||
|
"'tap-enable' TAP event.",
|
||||||
|
.usage = "tap_name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "tapdisable",
|
.name = "tapdisable",
|
||||||
|
@ -135,8 +148,15 @@ static const struct command_registration dapdirect_swd_subcommand_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "newdap",
|
.name = "newdap",
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.help = "declare a new SWD DAP",
|
.help = "declare a new SWD DAP",
|
||||||
|
.usage = "basename dap_type ['-irlen' count] "
|
||||||
|
"['-enable'|'-disable'] "
|
||||||
|
"['-expected_id' number] "
|
||||||
|
"['-ignore-version'] "
|
||||||
|
"['-ignore-bypass'] "
|
||||||
|
"['-ircapture' number] "
|
||||||
|
"['-mask' number]",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -657,9 +657,16 @@ static const struct command_registration swd_commands[] = {
|
||||||
* REVISIT can we verify "just one SWD DAP" here/early?
|
* REVISIT can we verify "just one SWD DAP" here/early?
|
||||||
*/
|
*/
|
||||||
.name = "newdap",
|
.name = "newdap",
|
||||||
.jim_handler = jim_jtag_newtap,
|
.handler = handle_jtag_newtap,
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.help = "declare a new SWD DAP"
|
.help = "declare a new SWD DAP",
|
||||||
|
.usage = "basename dap_type ['-irlen' count] "
|
||||||
|
"['-enable'|'-disable'] "
|
||||||
|
"['-expected_id' number] "
|
||||||
|
"['-ignore-version'] "
|
||||||
|
"['-ignore-bypass'] "
|
||||||
|
"['-ircapture' number] "
|
||||||
|
"['-mask' number]",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -292,14 +292,14 @@ int armv4_5_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
int armv4_5_run_algorithm_inner(struct target *target,
|
int armv4_5_run_algorithm_inner(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
uint32_t entry_point, uint32_t exit_point,
|
uint32_t entry_point, uint32_t exit_point,
|
||||||
int timeout_ms, void *arch_info,
|
unsigned int timeout_ms, void *arch_info,
|
||||||
int (*run_it)(struct target *target, uint32_t exit_point,
|
int (*run_it)(struct target *target, uint32_t exit_point,
|
||||||
int timeout_ms, void *arch_info));
|
unsigned int timeout_ms, void *arch_info));
|
||||||
|
|
||||||
int arm_checksum_memory(struct target *target,
|
int arm_checksum_memory(struct target *target,
|
||||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
target_addr_t address, uint32_t count, uint32_t *checksum);
|
||||||
|
|
|
@ -2518,7 +2518,7 @@ static const uint8_t *dcc_buffer;
|
||||||
|
|
||||||
static int arm7_9_dcc_completion(struct target *target,
|
static int arm7_9_dcc_completion(struct target *target,
|
||||||
uint32_t exit_point,
|
uint32_t exit_point,
|
||||||
int timeout_ms,
|
unsigned int timeout_ms,
|
||||||
void *arch_info)
|
void *arch_info)
|
||||||
{
|
{
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
|
@ -455,6 +455,9 @@ enum ap_type {
|
||||||
AP_TYPE_AHB5H_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 8), /* AHB5 with enhanced HPROT Memory-AP */
|
AP_TYPE_AHB5H_AP = AP_REG_IDR_VALUE(ARM_ID, AP_REG_IDR_CLASS_MEM_AP, 8), /* AHB5 with enhanced HPROT Memory-AP */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const struct dap_ops jtag_dp_ops;
|
||||||
|
extern const struct dap_ops swd_dap_ops;
|
||||||
|
|
||||||
/* Check the ap->cfg_reg Long Address field (bit 1)
|
/* Check the ap->cfg_reg Long Address field (bit 1)
|
||||||
*
|
*
|
||||||
* 0b0: The AP only supports physical addresses 32 bits or smaller
|
* 0b0: The AP only supports physical addresses 32 bits or smaller
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
static LIST_HEAD(all_dap);
|
static LIST_HEAD(all_dap);
|
||||||
|
|
||||||
extern const struct dap_ops swd_dap_ops;
|
|
||||||
extern const struct dap_ops jtag_dp_ops;
|
|
||||||
extern struct adapter_driver *adapter_driver;
|
extern struct adapter_driver *adapter_driver;
|
||||||
|
|
||||||
/* DAP command support */
|
/* DAP command support */
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ int arm_dpm_setup(struct arm_dpm *dpm)
|
||||||
{
|
{
|
||||||
struct arm *arm = dpm->arm;
|
struct arm *arm = dpm->arm;
|
||||||
struct target *target = arm->target;
|
struct target *target = arm->target;
|
||||||
struct reg_cache *cache = 0;
|
struct reg_cache *cache = NULL;
|
||||||
|
|
||||||
arm->dpm = dpm;
|
arm->dpm = dpm;
|
||||||
|
|
||||||
|
|
|
@ -1252,7 +1252,7 @@ int arm_get_gdb_reg_list(struct target *target,
|
||||||
/* wait for execution to complete and check exit point */
|
/* wait for execution to complete and check exit point */
|
||||||
static int armv4_5_run_algorithm_completion(struct target *target,
|
static int armv4_5_run_algorithm_completion(struct target *target,
|
||||||
uint32_t exit_point,
|
uint32_t exit_point,
|
||||||
int timeout_ms,
|
unsigned int timeout_ms,
|
||||||
void *arch_info)
|
void *arch_info)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -1286,9 +1286,9 @@ int armv4_5_run_algorithm_inner(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
uint32_t entry_point, uint32_t exit_point,
|
uint32_t entry_point, uint32_t exit_point,
|
||||||
int timeout_ms, void *arch_info,
|
unsigned int timeout_ms, void *arch_info,
|
||||||
int (*run_it)(struct target *target, uint32_t exit_point,
|
int (*run_it)(struct target *target, uint32_t exit_point,
|
||||||
int timeout_ms, void *arch_info))
|
unsigned int timeout_ms, void *arch_info))
|
||||||
{
|
{
|
||||||
struct arm *arm = target_to_arm(target);
|
struct arm *arm = target_to_arm(target);
|
||||||
struct arm_algorithm *arm_algorithm_info = arch_info;
|
struct arm_algorithm *arm_algorithm_info = arch_info;
|
||||||
|
@ -1474,7 +1474,7 @@ int armv4_5_run_algorithm(struct target *target,
|
||||||
struct reg_param *reg_params,
|
struct reg_param *reg_params,
|
||||||
target_addr_t entry_point,
|
target_addr_t entry_point,
|
||||||
target_addr_t exit_point,
|
target_addr_t exit_point,
|
||||||
int timeout_ms,
|
unsigned int timeout_ms,
|
||||||
void *arch_info)
|
void *arch_info)
|
||||||
{
|
{
|
||||||
return armv4_5_run_algorithm_inner(target,
|
return armv4_5_run_algorithm_inner(target,
|
||||||
|
@ -1535,7 +1535,7 @@ int arm_checksum_memory(struct target *target,
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||||
|
|
||||||
/* 20 second timeout/megabyte */
|
/* 20 second timeout/megabyte */
|
||||||
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
unsigned int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
||||||
|
|
||||||
/* armv4 must exit using a hardware breakpoint */
|
/* armv4 must exit using a hardware breakpoint */
|
||||||
if (arm->arch == ARM_ARCH_V4)
|
if (arm->arch == ARM_ARCH_V4)
|
||||||
|
|
|
@ -484,7 +484,7 @@ int armv7m_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info)
|
unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ int armv7m_start_algorithm(struct target *target,
|
||||||
int armv7m_wait_algorithm(struct target *target,
|
int armv7m_wait_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t exit_point, int timeout_ms,
|
target_addr_t exit_point, unsigned int timeout_ms,
|
||||||
void *arch_info)
|
void *arch_info)
|
||||||
{
|
{
|
||||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||||
|
@ -909,7 +909,7 @@ int armv7m_checksum_memory(struct target *target,
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||||
|
|
||||||
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
unsigned int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
||||||
|
|
||||||
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
|
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
|
||||||
crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
|
crc_algorithm->address + (sizeof(cortex_m_crc_code) - 6),
|
||||||
|
@ -1016,7 +1016,7 @@ int armv7m_blank_check_memory(struct target *target,
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, erased_word);
|
buf_set_u32(reg_params[1].value, 0, 32, erased_word);
|
||||||
|
|
||||||
/* assume CPU clk at least 1 MHz */
|
/* assume CPU clk at least 1 MHz */
|
||||||
int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
|
unsigned int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
|
||||||
|
|
||||||
retval = target_run_algorithm(target,
|
retval = target_run_algorithm(target,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
|
|
|
@ -314,7 +314,7 @@ int armv7m_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
int armv7m_start_algorithm(struct target *target,
|
int armv7m_start_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
|
@ -325,7 +325,7 @@ int armv7m_start_algorithm(struct target *target,
|
||||||
int armv7m_wait_algorithm(struct target *target,
|
int armv7m_wait_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t exit_point, int timeout_ms,
|
target_addr_t exit_point, unsigned int timeout_ms,
|
||||||
void *arch_info);
|
void *arch_info);
|
||||||
|
|
||||||
int armv7m_invalidate_core_regs(struct target *target);
|
int armv7m_invalidate_core_regs(struct target *target);
|
||||||
|
|
|
@ -1682,7 +1682,7 @@ struct reg_cache *armv8_build_reg_cache(struct target *target)
|
||||||
LOG_ERROR("unable to allocate reg type list");
|
LOG_ERROR("unable to allocate reg type list");
|
||||||
|
|
||||||
if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK)
|
if (i == ARMV8_PAUTH_CMASK || i == ARMV8_PAUTH_DMASK)
|
||||||
reg_list[i].hidden = !armv8->enable_pauth;
|
reg_list[i].exist = armv8->enable_pauth;
|
||||||
}
|
}
|
||||||
|
|
||||||
arm->cpsr = reg_list + ARMV8_XPSR;
|
arm->cpsr = reg_list + ARMV8_XPSR;
|
||||||
|
|
|
@ -801,15 +801,11 @@ static int cortex_m_debug_entry(struct target *target)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
/* examine PE security state */
|
/* examine PE security state */
|
||||||
bool secure_state = false;
|
uint32_t dscsr = 0;
|
||||||
if (armv7m->arm.arch == ARM_ARCH_V8M) {
|
if (armv7m->arm.arch == ARM_ARCH_V8M) {
|
||||||
uint32_t dscsr;
|
|
||||||
|
|
||||||
retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr);
|
retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DSCSR, &dscsr);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load all registers to arm.core_cache */
|
/* Load all registers to arm.core_cache */
|
||||||
|
@ -857,6 +853,7 @@ static int cortex_m_debug_entry(struct target *target)
|
||||||
if (armv7m->exception_number)
|
if (armv7m->exception_number)
|
||||||
cortex_m_examine_exception_reason(target);
|
cortex_m_examine_exception_reason(target);
|
||||||
|
|
||||||
|
bool secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS;
|
||||||
LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32
|
LOG_TARGET_DEBUG(target, "entered debug state in core mode: %s at PC 0x%" PRIx32
|
||||||
", cpu in %s state, target->state: %s",
|
", cpu in %s state, target->state: %s",
|
||||||
arm_mode_name(arm->core_mode),
|
arm_mode_name(arm->core_mode),
|
||||||
|
|
|
@ -1374,7 +1374,7 @@ static int dsp563xx_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info)
|
unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
|
|
|
@ -15,5 +15,8 @@ noinst_LTLIBRARIES += %D%/libespressif.la
|
||||||
%D%/esp32.c \
|
%D%/esp32.c \
|
||||||
%D%/esp32s2.c \
|
%D%/esp32s2.c \
|
||||||
%D%/esp32s3.c \
|
%D%/esp32s3.c \
|
||||||
|
%D%/esp32_sysview.c \
|
||||||
|
%D%/esp32_sysview.h \
|
||||||
|
%D%/segger_sysview.h \
|
||||||
%D%/esp_semihosting.c \
|
%D%/esp_semihosting.c \
|
||||||
%D%/esp_semihosting.h
|
%D%/esp_semihosting.h
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include "esp_xtensa_smp.h"
|
#include "esp_xtensa_smp.h"
|
||||||
#include "esp_xtensa_apptrace.h"
|
#include "esp_xtensa_apptrace.h"
|
||||||
#include "esp32_apptrace.h"
|
#include "esp32_apptrace.h"
|
||||||
|
#include "esp32_sysview.h"
|
||||||
|
#include "segger_sysview.h"
|
||||||
|
|
||||||
#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
|
#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
|
||||||
#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
|
#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
|
||||||
|
@ -82,6 +84,8 @@ static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
|
||||||
static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx);
|
static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx);
|
||||||
static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
|
static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
|
||||||
struct esp32_apptrace_block *block);
|
struct esp32_apptrace_block *block);
|
||||||
|
static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx);
|
||||||
|
static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx);
|
||||||
|
|
||||||
static const bool s_time_stats_enable = true;
|
static const bool s_time_stats_enable = true;
|
||||||
|
|
||||||
|
@ -1118,10 +1122,7 @@ static int esp32_apptrace_poll(void *priv)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res =
|
res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
|
||||||
ctx->hw->data_read(ctx->cpus[fired_target_num],
|
|
||||||
target_state[fired_target_num].data_len,
|
|
||||||
block->data,
|
|
||||||
target_state[fired_target_num].block_id,
|
target_state[fired_target_num].block_id,
|
||||||
/* do not ack target data in sync mode,
|
/* do not ack target data in sync mode,
|
||||||
esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
|
esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
|
||||||
|
@ -1215,6 +1216,11 @@ static int esp32_apptrace_poll(void *priv)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_sysview_mode(int mode)
|
||||||
|
{
|
||||||
|
return mode == ESP_APPTRACE_CMD_MODE_SYSVIEW || mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE;
|
||||||
|
}
|
||||||
|
|
||||||
static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
|
static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (duration_measure(&ctx->read_time) != 0)
|
if (duration_measure(&ctx->read_time) != 0)
|
||||||
|
@ -1222,7 +1228,12 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
|
||||||
int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
|
int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
|
||||||
if (res != ERROR_OK)
|
if (res != ERROR_OK)
|
||||||
LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
|
LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
|
||||||
|
if (is_sysview_mode(ctx->mode)) {
|
||||||
|
/* stop tracing */
|
||||||
|
res = esp32_sysview_stop(ctx);
|
||||||
|
if (res != ERROR_OK)
|
||||||
|
LOG_ERROR("sysview: Failed to stop tracing!");
|
||||||
|
}
|
||||||
/* data processor is alive, so wait for all received blocks to be processed */
|
/* data processor is alive, so wait for all received blocks to be processed */
|
||||||
res = esp32_apptrace_wait_tracing_finished(ctx);
|
res = esp32_apptrace_wait_tracing_finished(ctx);
|
||||||
if (res != ERROR_OK)
|
if (res != ERROR_OK)
|
||||||
|
@ -1236,7 +1247,191 @@ static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
|
||||||
LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res);
|
LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc)
|
/* this function must be called after connecting to targets */
|
||||||
|
static int esp32_sysview_start(struct esp32_apptrace_cmd_ctx *ctx)
|
||||||
|
{
|
||||||
|
uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_START };
|
||||||
|
uint32_t fired_target_num = 0;
|
||||||
|
struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM] = {0};
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
|
||||||
|
|
||||||
|
/* get current block id */
|
||||||
|
int res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to read target data info!");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (fired_target_num == UINT32_MAX) {
|
||||||
|
/* it can happen that there is no pending target data, but block was switched
|
||||||
|
* in this case block_ids on both CPUs are equal, so select the first one */
|
||||||
|
fired_target_num = 0;
|
||||||
|
}
|
||||||
|
/* start tracing */
|
||||||
|
res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
|
||||||
|
cmds, sizeof(cmds));
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to start tracing!");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
cmd_data->sv_trace_running = 1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx)
|
||||||
|
{
|
||||||
|
uint32_t old_block_id, fired_target_num = 0, empty_target_num = 0;
|
||||||
|
struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
|
||||||
|
uint8_t cmds[] = { SEGGER_SYSVIEW_COMMAND_ID_STOP };
|
||||||
|
struct duration wait_time;
|
||||||
|
|
||||||
|
struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
|
||||||
|
if (!block) {
|
||||||
|
LOG_ERROR("Failed to get free block for data on (%s)!", target_name(ctx->cpus[fired_target_num]));
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* halt all CPUs (not only one), otherwise it can happen that there is no target data and
|
||||||
|
* while we are queueing commands another CPU switches tracing block */
|
||||||
|
int res = esp32_apptrace_safe_halt_targets(ctx, target_state);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to halt targets (%d)!", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/* it can happen that there is no pending target data
|
||||||
|
* in this case block_ids on both CPUs are equal, so the first one will be selected */
|
||||||
|
for (unsigned int k = 0; k < ctx->cores_num; k++) {
|
||||||
|
if (target_state[k].data_len) {
|
||||||
|
fired_target_num = k;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target_state[fired_target_num].data_len) {
|
||||||
|
/* read pending data without ack, they will be acked when stop command is queued */
|
||||||
|
res = ctx->hw->data_read(ctx->cpus[fired_target_num], target_state[fired_target_num].data_len, block->data,
|
||||||
|
target_state[fired_target_num].block_id,
|
||||||
|
false /*no ack target data*/);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to read data on (%s)!", target_name(ctx->cpus[fired_target_num]));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/* process data */
|
||||||
|
block->data_len = target_state[fired_target_num].data_len;
|
||||||
|
res = esp32_apptrace_handle_trace_block(ctx, block);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* stop tracing and ack target data */
|
||||||
|
res = esp_apptrace_usr_block_write(ctx->hw, ctx->cpus[fired_target_num], target_state[fired_target_num].block_id,
|
||||||
|
cmds,
|
||||||
|
sizeof(cmds));
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to stop tracing!");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (ctx->cores_num > 1) {
|
||||||
|
empty_target_num = fired_target_num ? 0 : 1;
|
||||||
|
/* ack target data on another CPU */
|
||||||
|
res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num], target_state[fired_target_num].block_id,
|
||||||
|
0 /*target data ack*/,
|
||||||
|
true /*host connected*/,
|
||||||
|
false /*no host data*/);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
|
||||||
|
target_name(ctx->cpus[empty_target_num]), res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* resume targets to allow command processing */
|
||||||
|
LOG_INFO("Resume targets");
|
||||||
|
bool smp_resumed = false;
|
||||||
|
for (unsigned int k = 0; k < ctx->cores_num; k++) {
|
||||||
|
if (smp_resumed && ctx->cpus[k]->smp) {
|
||||||
|
/* in SMP mode we need to call target_resume for one core only */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (ctx->cpus[k]->smp)
|
||||||
|
smp_resumed = true;
|
||||||
|
}
|
||||||
|
/* wait for block switch (command sent), so we can disconnect from targets */
|
||||||
|
old_block_id = target_state[fired_target_num].block_id;
|
||||||
|
if (duration_start(&wait_time) != 0) {
|
||||||
|
LOG_ERROR("Failed to start trace stop timeout measurement!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
/* we are waiting for the last data from tracing block and also there can be data in the pended
|
||||||
|
* data buffer */
|
||||||
|
/* so we are expecting two TRX block switches at most or stopping due to timeout */
|
||||||
|
while (cmd_data->sv_trace_running) {
|
||||||
|
res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to read targets data info!");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (fired_target_num == UINT32_MAX) {
|
||||||
|
/* it can happen that there is no pending (last) target data, but block was
|
||||||
|
* switched */
|
||||||
|
/* in this case block_ids on both CPUs are equal, so select the first one */
|
||||||
|
fired_target_num = 0;
|
||||||
|
}
|
||||||
|
if (target_state[fired_target_num].block_id != old_block_id) {
|
||||||
|
if (target_state[fired_target_num].data_len) {
|
||||||
|
/* read last data and ack them */
|
||||||
|
res = ctx->hw->data_read(ctx->cpus[fired_target_num],
|
||||||
|
target_state[fired_target_num].data_len,
|
||||||
|
block->data,
|
||||||
|
target_state[fired_target_num].block_id,
|
||||||
|
true /*ack target data*/);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to read last data on (%s)!", target_name(ctx->cpus[fired_target_num]));
|
||||||
|
} else {
|
||||||
|
if (ctx->cores_num > 1) {
|
||||||
|
/* ack target data on another CPU */
|
||||||
|
empty_target_num = fired_target_num ? 0 : 1;
|
||||||
|
res = ctx->hw->ctrl_reg_write(ctx->cpus[empty_target_num],
|
||||||
|
target_state[fired_target_num].block_id,
|
||||||
|
0 /*all read*/,
|
||||||
|
true /*host connected*/,
|
||||||
|
false /*no host data*/);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to ack data on target '%s' (%d)!",
|
||||||
|
target_name(ctx->cpus[empty_target_num]), res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* process data */
|
||||||
|
block->data_len = target_state[fired_target_num].data_len;
|
||||||
|
res = esp32_apptrace_handle_trace_block(ctx, block);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to process trace block %" PRId32 " bytes!",
|
||||||
|
block->data_len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
old_block_id = target_state[fired_target_num].block_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duration_measure(&wait_time) != 0) {
|
||||||
|
LOG_ERROR("Failed to start trace stop timeout measurement!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
const float stop_tmo = LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 30.0 : 0.5;
|
||||||
|
if (duration_elapsed(&wait_time) >= stop_tmo) {
|
||||||
|
LOG_INFO("Stop waiting for the last data due to timeout.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc)
|
||||||
{
|
{
|
||||||
static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
|
static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
|
||||||
struct esp32_apptrace_cmd_data *cmd_data;
|
struct esp32_apptrace_cmd_data *cmd_data;
|
||||||
|
@ -1264,17 +1459,39 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
|
||||||
old_state = target->state;
|
old_state = target->state;
|
||||||
|
|
||||||
if (strcmp(argv[0], "start") == 0) {
|
if (strcmp(argv[0], "start") == 0) {
|
||||||
res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
|
if (is_sysview_mode(mode)) {
|
||||||
cmd,
|
/* init cmd context */
|
||||||
mode,
|
res = esp32_sysview_cmd_init(&s_at_cmd_ctx,
|
||||||
&argv[1],
|
cmd,
|
||||||
argc - 1);
|
mode,
|
||||||
if (res != ERROR_OK) {
|
mode == ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE,
|
||||||
command_print(cmd, "Failed to init cmd ctx (%d)!", res);
|
&argv[1],
|
||||||
return res;
|
argc - 1);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
command_print(cmd, "Failed to init cmd ctx (%d)!", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
cmd_data = s_at_cmd_ctx.cmd_priv;
|
||||||
|
if (cmd_data->skip_len != 0) {
|
||||||
|
s_at_cmd_ctx.running = 0;
|
||||||
|
esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
|
||||||
|
command_print(cmd, "Data skipping not supported!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
s_at_cmd_ctx.process_data = esp32_sysview_process_data;
|
||||||
|
} else {
|
||||||
|
res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
|
||||||
|
cmd,
|
||||||
|
mode,
|
||||||
|
&argv[1],
|
||||||
|
argc - 1);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
command_print(cmd, "Failed to init cmd ctx (%d)!", res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
cmd_data = s_at_cmd_ctx.cmd_priv;
|
||||||
|
s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
|
||||||
}
|
}
|
||||||
cmd_data = s_at_cmd_ctx.cmd_priv;
|
|
||||||
s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
|
|
||||||
s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
|
s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
|
||||||
if (cmd_data->wait4halt) {
|
if (cmd_data->wait4halt) {
|
||||||
res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
|
res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
|
||||||
|
@ -1288,6 +1505,17 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
|
||||||
command_print(cmd, "Failed to connect to targets (%d)!", res);
|
command_print(cmd, "Failed to connect to targets (%d)!", res);
|
||||||
goto _on_start_error;
|
goto _on_start_error;
|
||||||
}
|
}
|
||||||
|
if (is_sysview_mode(mode)) {
|
||||||
|
/* start tracing */
|
||||||
|
res = esp32_sysview_start(&s_at_cmd_ctx);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
esp32_apptrace_connect_targets(&s_at_cmd_ctx, false, old_state == TARGET_RUNNING);
|
||||||
|
s_at_cmd_ctx.running = 0;
|
||||||
|
esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
|
||||||
|
command_print(cmd, "sysview: Failed to start tracing!");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
res = target_register_timer_callback(esp32_apptrace_poll,
|
res = target_register_timer_callback(esp32_apptrace_poll,
|
||||||
cmd_data->poll_period,
|
cmd_data->poll_period,
|
||||||
TARGET_TIMER_TYPE_PERIODIC,
|
TARGET_TIMER_TYPE_PERIODIC,
|
||||||
|
@ -1309,6 +1537,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
|
||||||
esp32_apptrace_print_stats(&s_at_cmd_ctx);
|
esp32_apptrace_print_stats(&s_at_cmd_ctx);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
} else if (strcmp(argv[0], "dump") == 0) {
|
} else if (strcmp(argv[0], "dump") == 0) {
|
||||||
|
if (is_sysview_mode(mode)) {
|
||||||
|
command_print(cmd, "Not supported!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
/* [dump outfile] - post-mortem dump without connection to targets */
|
/* [dump outfile] - post-mortem dump without connection to targets */
|
||||||
res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
|
res = esp32_apptrace_cmd_init(&s_at_cmd_ctx,
|
||||||
cmd,
|
cmd,
|
||||||
|
@ -1349,7 +1581,10 @@ int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const c
|
||||||
|
|
||||||
_on_start_error:
|
_on_start_error:
|
||||||
s_at_cmd_ctx.running = 0;
|
s_at_cmd_ctx.running = 0;
|
||||||
esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
|
if (is_sysview_mode(mode))
|
||||||
|
esp32_sysview_cmd_cleanup(&s_at_cmd_ctx);
|
||||||
|
else
|
||||||
|
esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1358,6 +1593,16 @@ COMMAND_HANDLER(esp32_cmd_apptrace)
|
||||||
return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
|
return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(esp32_cmd_sysview)
|
||||||
|
{
|
||||||
|
return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW, CMD_ARGV, CMD_ARGC);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(esp32_cmd_sysview_mcore)
|
||||||
|
{
|
||||||
|
return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE, CMD_ARGV, CMD_ARGC);
|
||||||
|
}
|
||||||
|
|
||||||
const struct command_registration esp32_apptrace_command_handlers[] = {
|
const struct command_registration esp32_apptrace_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "apptrace",
|
.name = "apptrace",
|
||||||
|
@ -1366,7 +1611,25 @@ const struct command_registration esp32_apptrace_command_handlers[] = {
|
||||||
.help =
|
.help =
|
||||||
"App Tracing: application level trace control. Starts, stops or queries tracing process status.",
|
"App Tracing: application level trace control. Starts, stops or queries tracing process status.",
|
||||||
.usage =
|
.usage =
|
||||||
"[start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
|
"(start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status) | (dump <destination>)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "sysview",
|
||||||
|
.handler = esp32_cmd_sysview,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help =
|
||||||
|
"App Tracing: SEGGER SystemView compatible trace control. Starts, stops or queries tracing process status.",
|
||||||
|
.usage =
|
||||||
|
"(start file://<outfile1> [file://<outfile2>] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "sysview_mcore",
|
||||||
|
.handler = esp32_cmd_sysview_mcore,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help =
|
||||||
|
"App Tracing: Espressif multi-core SystemView trace control. Starts, stops or queries tracing process status.",
|
||||||
|
.usage =
|
||||||
|
"(start file://<outfile> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]) | (stop) | (status)",
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,554 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* ESP32 sysview tracing module *
|
||||||
|
* Copyright (C) 2020 Espressif Systems Ltd. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <helper/log.h>
|
||||||
|
#include "esp32_apptrace.h"
|
||||||
|
#include "esp32_sysview.h"
|
||||||
|
#include "segger_sysview.h"
|
||||||
|
|
||||||
|
/* in SystemView mode core ID is passed in event ID field */
|
||||||
|
#define ESP32_SYSVIEW_USER_BLOCK_CORE(_v_) (0) /* not used */
|
||||||
|
#define ESP32_SYSVIEW_USER_BLOCK_LEN(_v_) (_v_)
|
||||||
|
#define ESP32_SYSVIEW_USER_BLOCK_HDR_SZ 2
|
||||||
|
|
||||||
|
struct esp_sysview_target2host_hdr {
|
||||||
|
uint8_t block_sz;
|
||||||
|
uint8_t wr_sz;
|
||||||
|
};
|
||||||
|
#define SYSVIEW_BLOCK_SIZE_OFFSET 0
|
||||||
|
#define SYSVIEW_WR_SIZE_OFFSET 1
|
||||||
|
|
||||||
|
static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format);
|
||||||
|
static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf);
|
||||||
|
static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len);
|
||||||
|
|
||||||
|
int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
|
||||||
|
struct command_invocation *cmd,
|
||||||
|
int mode,
|
||||||
|
bool mcore_format,
|
||||||
|
const char **argv,
|
||||||
|
int argc)
|
||||||
|
{
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
command_print(cmd, "Not enough args! Need trace data destination!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode);
|
||||||
|
if (res != ERROR_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
int core_num = cmd_ctx->cores_num;
|
||||||
|
|
||||||
|
if (!mcore_format && argc < core_num) {
|
||||||
|
command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
|
||||||
|
res = ERROR_FAIL;
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_data = calloc(1, sizeof(*cmd_data));
|
||||||
|
if (!cmd_data) {
|
||||||
|
command_print(cmd, "No memory for command data!");
|
||||||
|
res = ERROR_FAIL;
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
cmd_ctx->cmd_priv = cmd_data;
|
||||||
|
cmd_data->mcore_format = mcore_format;
|
||||||
|
|
||||||
|
/*outfile1 [outfile2] [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
|
||||||
|
int dests_num = esp32_apptrace_dest_init(cmd_data->data_dests, argv, !mcore_format ? core_num : 1);
|
||||||
|
if (!mcore_format && dests_num < core_num) {
|
||||||
|
command_print(cmd, "Not enough args! Need %d trace data destinations!", core_num);
|
||||||
|
free(cmd_data);
|
||||||
|
res = ERROR_FAIL;
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
cmd_data->apptrace.max_len = UINT32_MAX;
|
||||||
|
cmd_data->apptrace.poll_period = 0 /*ms*/;
|
||||||
|
cmd_ctx->stop_tmo = -1.0; /* infinite */
|
||||||
|
if (argc > dests_num) {
|
||||||
|
/* parse remaining args */
|
||||||
|
esp32_apptrace_cmd_args_parse(cmd_ctx,
|
||||||
|
&cmd_data->apptrace,
|
||||||
|
&argv[dests_num],
|
||||||
|
argc - dests_num);
|
||||||
|
}
|
||||||
|
LOG_USER("App trace params: from %d cores, size %u bytes, stop_tmo %g s, "
|
||||||
|
"poll period %u ms, wait_rst %d, skip %u bytes",
|
||||||
|
cmd_ctx->cores_num,
|
||||||
|
cmd_data->apptrace.max_len,
|
||||||
|
cmd_ctx->stop_tmo,
|
||||||
|
cmd_data->apptrace.poll_period,
|
||||||
|
cmd_data->apptrace.wait4halt,
|
||||||
|
cmd_data->apptrace.skip_len);
|
||||||
|
|
||||||
|
cmd_ctx->trace_format.hdr_sz = ESP32_SYSVIEW_USER_BLOCK_HDR_SZ;
|
||||||
|
cmd_ctx->trace_format.core_id_get = esp32_sysview_core_id_get;
|
||||||
|
cmd_ctx->trace_format.usr_block_len_get = esp32_sysview_usr_block_len_get;
|
||||||
|
|
||||||
|
res = esp_sysview_trace_header_write(cmd_ctx, mcore_format);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
command_print(cmd, "Failed to write trace header (%d)!", res);
|
||||||
|
esp32_apptrace_dest_cleanup(cmd_data->data_dests, core_num);
|
||||||
|
free(cmd_data);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
on_error:
|
||||||
|
cmd_ctx->running = 0;
|
||||||
|
esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
|
||||||
|
{
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = cmd_ctx->cmd_priv;
|
||||||
|
|
||||||
|
esp32_apptrace_dest_cleanup(cmd_data->data_dests, cmd_ctx->cores_num);
|
||||||
|
free(cmd_data);
|
||||||
|
cmd_ctx->cmd_priv = NULL;
|
||||||
|
esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp32_sysview_core_id_get(struct target *target, uint8_t *hdr_buf)
|
||||||
|
{
|
||||||
|
/* for sysview compressed apptrace header is used, so core id is encoded in sysview packet */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t esp32_sysview_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len)
|
||||||
|
{
|
||||||
|
*wr_len = ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_WR_SIZE_OFFSET]);
|
||||||
|
return ESP32_SYSVIEW_USER_BLOCK_LEN(hdr_buf[SYSVIEW_BLOCK_SIZE_OFFSET]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp_sysview_trace_header_write(struct esp32_apptrace_cmd_ctx *ctx, bool mcore_format)
|
||||||
|
{
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
|
||||||
|
char *hdr_str;
|
||||||
|
int dests_num;
|
||||||
|
|
||||||
|
if (!mcore_format) {
|
||||||
|
hdr_str = ";\n"
|
||||||
|
"; Version " SYSVIEW_MIN_VER_STRING "\n"
|
||||||
|
"; Author Espressif Inc\n"
|
||||||
|
";\n";
|
||||||
|
dests_num = ctx->cores_num;
|
||||||
|
} else {
|
||||||
|
hdr_str = ";\n"
|
||||||
|
"; Version " SYSVIEW_MIN_VER_STRING "\n"
|
||||||
|
"; Author Espressif Inc\n"
|
||||||
|
"; ESP_Extension\n"
|
||||||
|
";\n";
|
||||||
|
dests_num = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hdr_len = strlen(hdr_str);
|
||||||
|
for (int i = 0; i < dests_num; i++) {
|
||||||
|
int res = cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
|
||||||
|
(uint8_t *)hdr_str,
|
||||||
|
hdr_len);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", hdr_len, i);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sysview_encode_u32(uint8_t **dest, uint32_t val)
|
||||||
|
{
|
||||||
|
uint8_t *sv_ptr = *dest;
|
||||||
|
while (val > 0x7F) {
|
||||||
|
*sv_ptr++ = (uint8_t)(val | 0x80);
|
||||||
|
val >>= 7;
|
||||||
|
}
|
||||||
|
*sv_ptr++ = (uint8_t)val;
|
||||||
|
*dest = sv_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t esp_sysview_decode_u32(uint8_t **ptr)
|
||||||
|
{
|
||||||
|
uint32_t val = 0;
|
||||||
|
for (int k = 0;; k++, (*ptr)++) {
|
||||||
|
if (**ptr & 0x80) {
|
||||||
|
val |= (uint32_t)(**ptr & ~0x80) << 7 * k;
|
||||||
|
} else {
|
||||||
|
val |= (uint32_t)**ptr << 7 * k;
|
||||||
|
(*ptr)++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t esp_sysview_decode_plen(uint8_t **ptr)
|
||||||
|
{
|
||||||
|
uint16_t payload_len = 0;
|
||||||
|
uint8_t *p = *ptr;
|
||||||
|
/* here pkt points to encoded payload length */
|
||||||
|
if (*p & 0x80) {
|
||||||
|
payload_len = *(p + 1); /* higher part */
|
||||||
|
payload_len = (payload_len << 7) | (*p & ~0x80);/* lower 7 bits */
|
||||||
|
p += 2; /* payload len (2 bytes) */
|
||||||
|
} else {
|
||||||
|
payload_len = *p;
|
||||||
|
p++; /* payload len (1 byte) */
|
||||||
|
}
|
||||||
|
*ptr = p;
|
||||||
|
|
||||||
|
return payload_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t esp_sysview_get_predef_payload_len(uint16_t id, uint8_t *pkt)
|
||||||
|
{
|
||||||
|
uint16_t len;
|
||||||
|
uint8_t *ptr = pkt;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case SYSVIEW_EVTID_OVERFLOW:
|
||||||
|
case SYSVIEW_EVTID_ISR_ENTER:
|
||||||
|
case SYSVIEW_EVTID_TASK_START_EXEC:
|
||||||
|
case SYSVIEW_EVTID_TASK_START_READY:
|
||||||
|
case SYSVIEW_EVTID_TASK_CREATE:
|
||||||
|
case SYSVIEW_EVTID_SYSTIME_CYCLES:
|
||||||
|
case SYSVIEW_EVTID_USER_START:
|
||||||
|
case SYSVIEW_EVTID_USER_STOP:
|
||||||
|
case SYSVIEW_EVTID_TIMER_ENTER:
|
||||||
|
/*ENCODE_U32 */
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
len = ptr - pkt;
|
||||||
|
break;
|
||||||
|
case SYSVIEW_EVTID_TASK_STOP_READY:
|
||||||
|
case SYSVIEW_EVTID_SYSTIME_US:
|
||||||
|
/*2*ENCODE_U32 */
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
len = ptr - pkt;
|
||||||
|
break;
|
||||||
|
case SYSVIEW_EVTID_SYSDESC:
|
||||||
|
/*str(128 + 1) */
|
||||||
|
len = *ptr + 1;
|
||||||
|
break;
|
||||||
|
case SYSVIEW_EVTID_TASK_INFO:
|
||||||
|
case SYSVIEW_EVTID_MODULEDESC:
|
||||||
|
/*2*ENCODE_U32 + str */
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
/* TODO: add support for strings longer then 255 bytes */
|
||||||
|
len = ptr - pkt + *ptr + 1;
|
||||||
|
break;
|
||||||
|
case SYSVIEW_EVTID_STACK_INFO:
|
||||||
|
/*4*ENCODE_U32 */
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
esp_sysview_decode_u32(&ptr);
|
||||||
|
len = ptr - pkt;
|
||||||
|
break;
|
||||||
|
case SYSVIEW_EVTID_ISR_EXIT:
|
||||||
|
case SYSVIEW_EVTID_TASK_STOP_EXEC:
|
||||||
|
case SYSVIEW_EVTID_TRACE_START:
|
||||||
|
case SYSVIEW_EVTID_TRACE_STOP:
|
||||||
|
case SYSVIEW_EVTID_IDLE:
|
||||||
|
case SYSVIEW_EVTID_ISR_TO_SCHEDULER:
|
||||||
|
case SYSVIEW_EVTID_TIMER_EXIT:
|
||||||
|
len = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*case SYSVIEW_EVTID_NOP: */
|
||||||
|
default:
|
||||||
|
LOG_ERROR("sysview: Unsupported predef event %d!", id);
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t esp_sysview_parse_packet(uint8_t *pkt_buf,
|
||||||
|
uint32_t *pkt_len,
|
||||||
|
unsigned int *pkt_core_id,
|
||||||
|
uint32_t *delta,
|
||||||
|
uint32_t *delta_len,
|
||||||
|
bool clear_core_bit)
|
||||||
|
{
|
||||||
|
uint8_t *pkt = pkt_buf;
|
||||||
|
uint16_t event_id = 0, payload_len = 0;
|
||||||
|
|
||||||
|
*pkt_core_id = 0;
|
||||||
|
*pkt_len = 0;
|
||||||
|
/* 1-2 byte of message type, 0-2 byte of payload length, payload, 1-5 bytes of timestamp. */
|
||||||
|
if (*pkt & 0x80) {
|
||||||
|
if (*(pkt + 1) & (1 << 6)) {
|
||||||
|
if (clear_core_bit)
|
||||||
|
*(pkt + 1) &= ~(1 << 6); /* clear core_id bit */
|
||||||
|
*pkt_core_id = 1;
|
||||||
|
}
|
||||||
|
event_id = *(pkt + 1) & ~(1 << 6); /* higher part */
|
||||||
|
event_id = (event_id << 7) | (*pkt & ~0x80); /* lower 7 bits */
|
||||||
|
pkt += 2; /* event_id (2 bytes) */
|
||||||
|
/* here pkt points to encoded payload length */
|
||||||
|
payload_len = esp_sysview_decode_plen(&pkt);
|
||||||
|
} else {
|
||||||
|
if (*pkt & (1 << 6)) {
|
||||||
|
if (clear_core_bit)
|
||||||
|
*pkt &= ~(1 << 6); /* clear core_id bit */
|
||||||
|
*pkt_core_id = 1;
|
||||||
|
}
|
||||||
|
/* event_id (1 byte) */
|
||||||
|
event_id = *pkt & ~(1 << 6);
|
||||||
|
pkt++;
|
||||||
|
if (event_id < 24)
|
||||||
|
payload_len = esp_sysview_get_predef_payload_len(event_id, pkt);
|
||||||
|
else
|
||||||
|
payload_len = esp_sysview_decode_plen(&pkt);
|
||||||
|
}
|
||||||
|
pkt += payload_len;
|
||||||
|
uint8_t *delta_start = pkt;
|
||||||
|
*delta = esp_sysview_decode_u32(&pkt);
|
||||||
|
*delta_len = pkt - delta_start;
|
||||||
|
*pkt_len = pkt - pkt_buf;
|
||||||
|
LOG_DEBUG("sysview: evt %d len %d plen %d dlen %d",
|
||||||
|
event_id,
|
||||||
|
*pkt_len,
|
||||||
|
payload_len,
|
||||||
|
*delta_len);
|
||||||
|
return event_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp32_sysview_write_packet(struct esp32_sysview_cmd_data *cmd_data,
|
||||||
|
int pkt_core_id, uint32_t pkt_len, uint8_t *pkt_buf, uint32_t delta_len, uint8_t *delta_buf)
|
||||||
|
{
|
||||||
|
if (!cmd_data->data_dests[pkt_core_id].write)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
int res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, pkt_buf, pkt_len);
|
||||||
|
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, pkt_core_id);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (delta_len) {
|
||||||
|
/* write packet with modified delta */
|
||||||
|
res = cmd_data->data_dests[pkt_core_id].write(cmd_data->data_dests[pkt_core_id].priv, delta_buf, delta_len);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u bytes of delta to dest %d!", delta_len, pkt_core_id);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp32_sysview_process_packet(struct esp32_apptrace_cmd_ctx *ctx,
|
||||||
|
unsigned int pkt_core_id, uint16_t event_id, uint32_t delta, uint32_t delta_len,
|
||||||
|
uint32_t pkt_len, uint8_t *pkt_buf)
|
||||||
|
{
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
|
||||||
|
int pkt_core_changed = 0;
|
||||||
|
uint32_t new_delta_len = 0;
|
||||||
|
uint8_t new_delta_buf[10];
|
||||||
|
uint32_t wr_len = pkt_len;
|
||||||
|
|
||||||
|
if (ctx->cores_num > 1) {
|
||||||
|
if (cmd_data->sv_last_core_id == pkt_core_id) {
|
||||||
|
/* if this packet is for the same core as the prev one acc delta and write packet unmodified */
|
||||||
|
cmd_data->sv_acc_time_delta += delta;
|
||||||
|
} else {
|
||||||
|
/* if this packet is for another core then prev one set acc delta to the packet's delta */
|
||||||
|
uint8_t *delta_ptr = new_delta_buf;
|
||||||
|
sysview_encode_u32(&delta_ptr, delta + cmd_data->sv_acc_time_delta);
|
||||||
|
cmd_data->sv_acc_time_delta = delta;
|
||||||
|
wr_len -= delta_len;
|
||||||
|
new_delta_len = delta_ptr - new_delta_buf;
|
||||||
|
pkt_core_changed = 1;
|
||||||
|
}
|
||||||
|
cmd_data->sv_last_core_id = pkt_core_id;
|
||||||
|
}
|
||||||
|
if (pkt_core_id >= ctx->cores_num) {
|
||||||
|
LOG_WARNING("sysview: invalid core ID in packet %d, must be less then %d! Event id %d",
|
||||||
|
pkt_core_id,
|
||||||
|
ctx->cores_num,
|
||||||
|
event_id);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
int res = esp32_sysview_write_packet(cmd_data,
|
||||||
|
pkt_core_id,
|
||||||
|
wr_len,
|
||||||
|
pkt_buf,
|
||||||
|
new_delta_len,
|
||||||
|
new_delta_buf);
|
||||||
|
if (res != ERROR_OK)
|
||||||
|
return res;
|
||||||
|
for (unsigned int i = 0; i < ctx->cores_num; i++) {
|
||||||
|
if (pkt_core_id == i)
|
||||||
|
continue;
|
||||||
|
switch (event_id) {
|
||||||
|
/* messages below should be sent to trace destinations for all cores */
|
||||||
|
case SYSVIEW_EVTID_TRACE_START:
|
||||||
|
case SYSVIEW_EVTID_TRACE_STOP:
|
||||||
|
case SYSVIEW_EVTID_SYSTIME_CYCLES:
|
||||||
|
case SYSVIEW_EVTID_SYSTIME_US:
|
||||||
|
case SYSVIEW_EVTID_SYSDESC:
|
||||||
|
case SYSVIEW_EVTID_TASK_INFO:
|
||||||
|
case SYSVIEW_EVTID_STACK_INFO:
|
||||||
|
case SYSVIEW_EVTID_MODULEDESC:
|
||||||
|
case SYSVIEW_EVTID_INIT:
|
||||||
|
case SYSVIEW_EVTID_NUMMODULES:
|
||||||
|
case SYSVIEW_EVTID_OVERFLOW:
|
||||||
|
case SYSVIEW_EVTID_TASK_START_READY:
|
||||||
|
/* if packet's source core has changed */
|
||||||
|
wr_len = pkt_len;
|
||||||
|
if (pkt_core_changed) {
|
||||||
|
/* clone packet with unmodified delta */
|
||||||
|
new_delta_len = 0;
|
||||||
|
} else {
|
||||||
|
/* clone packet with modified delta */
|
||||||
|
uint8_t *delta_ptr = new_delta_buf;
|
||||||
|
sysview_encode_u32(&delta_ptr, cmd_data->sv_acc_time_delta /*delta has been accumulated above*/);
|
||||||
|
wr_len -= delta_len;
|
||||||
|
new_delta_len = delta_ptr - new_delta_buf;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("sysview: Redirect %d bytes of event %d to dest %d", wr_len, event_id, i);
|
||||||
|
res = esp32_sysview_write_packet(cmd_data,
|
||||||
|
i,
|
||||||
|
wr_len,
|
||||||
|
pkt_buf,
|
||||||
|
new_delta_len,
|
||||||
|
new_delta_buf);
|
||||||
|
if (res != ERROR_OK)
|
||||||
|
return res;
|
||||||
|
/* messages above are cloned to trace files for both cores,
|
||||||
|
* so reset acc time delta, both files have actual delta
|
||||||
|
* info */
|
||||||
|
cmd_data->sv_acc_time_delta = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
|
||||||
|
unsigned int core_id,
|
||||||
|
uint8_t *data,
|
||||||
|
uint32_t data_len)
|
||||||
|
{
|
||||||
|
struct esp32_sysview_cmd_data *cmd_data = ctx->cmd_priv;
|
||||||
|
|
||||||
|
LOG_DEBUG("sysview: Read from target %d bytes [%x %x %x %x]",
|
||||||
|
data_len,
|
||||||
|
data[0],
|
||||||
|
data[1],
|
||||||
|
data[2],
|
||||||
|
data[3]);
|
||||||
|
int res;
|
||||||
|
uint32_t processed = 0;
|
||||||
|
if (core_id >= ctx->cores_num) {
|
||||||
|
LOG_ERROR("sysview: Invalid core id %d in user block!", core_id);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (cmd_data->mcore_format)
|
||||||
|
core_id = 0;
|
||||||
|
if (ctx->tot_len == 0) {
|
||||||
|
/* handle sync seq */
|
||||||
|
if (data_len < SYSVIEW_SYNC_LEN) {
|
||||||
|
LOG_ERROR("sysview: Invalid init seq len %d!", data_len);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("sysview: Process %d sync bytes", SYSVIEW_SYNC_LEN);
|
||||||
|
uint8_t sync_seq[SYSVIEW_SYNC_LEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||||
|
if (memcmp(data, sync_seq, SYSVIEW_SYNC_LEN) != 0) {
|
||||||
|
LOG_ERROR("sysview: Invalid init seq [%x %x %x %x %x %x %x %x %x %x]",
|
||||||
|
data[0], data[1], data[2], data[3], data[4], data[5], data[6],
|
||||||
|
data[7], data[8], data[9]);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
res = cmd_data->data_dests[core_id].write(cmd_data->data_dests[core_id].priv,
|
||||||
|
data,
|
||||||
|
SYSVIEW_SYNC_LEN);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!",
|
||||||
|
SYSVIEW_SYNC_LEN,
|
||||||
|
core_id);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (!cmd_data->mcore_format) {
|
||||||
|
for (unsigned int i = 0; i < ctx->cores_num; i++) {
|
||||||
|
if (core_id == i)
|
||||||
|
continue;
|
||||||
|
res =
|
||||||
|
cmd_data->data_dests[i].write(cmd_data->data_dests[i].priv,
|
||||||
|
data,
|
||||||
|
SYSVIEW_SYNC_LEN);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u sync bytes to dest %d!", SYSVIEW_SYNC_LEN, core_id ? 0 : 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->tot_len += SYSVIEW_SYNC_LEN;
|
||||||
|
processed += SYSVIEW_SYNC_LEN;
|
||||||
|
}
|
||||||
|
while (processed < data_len) {
|
||||||
|
unsigned int pkt_core_id;
|
||||||
|
uint32_t delta_len = 0;
|
||||||
|
uint32_t pkt_len = 0, delta = 0;
|
||||||
|
uint16_t event_id = esp_sysview_parse_packet(data + processed,
|
||||||
|
&pkt_len,
|
||||||
|
&pkt_core_id,
|
||||||
|
&delta,
|
||||||
|
&delta_len,
|
||||||
|
!cmd_data->mcore_format);
|
||||||
|
LOG_DEBUG("sysview: Process packet: core %d, %d id, %d bytes [%x %x %x %x]",
|
||||||
|
pkt_core_id,
|
||||||
|
event_id,
|
||||||
|
pkt_len,
|
||||||
|
data[processed + 0],
|
||||||
|
data[processed + 1],
|
||||||
|
data[processed + 2],
|
||||||
|
data[processed + 3]);
|
||||||
|
if (!cmd_data->mcore_format) {
|
||||||
|
res = esp32_sysview_process_packet(ctx,
|
||||||
|
pkt_core_id,
|
||||||
|
event_id,
|
||||||
|
delta,
|
||||||
|
delta_len,
|
||||||
|
pkt_len,
|
||||||
|
data + processed);
|
||||||
|
if (res != ERROR_OK)
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
res = cmd_data->data_dests[0].write(cmd_data->data_dests[0].priv, data + processed, pkt_len);
|
||||||
|
if (res != ERROR_OK) {
|
||||||
|
LOG_ERROR("sysview: Failed to write %u bytes to dest %d!", pkt_len, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (event_id == SYSVIEW_EVTID_TRACE_STOP)
|
||||||
|
cmd_data->sv_trace_running = 0;
|
||||||
|
ctx->tot_len += pkt_len;
|
||||||
|
processed += pkt_len;
|
||||||
|
}
|
||||||
|
LOG_USER("%u ", ctx->tot_len);
|
||||||
|
/* check for stop condition */
|
||||||
|
if (ctx->tot_len > cmd_data->apptrace.skip_len &&
|
||||||
|
(ctx->tot_len - cmd_data->apptrace.skip_len >= cmd_data->apptrace.max_len)) {
|
||||||
|
ctx->running = 0;
|
||||||
|
if (duration_measure(&ctx->read_time) != 0) {
|
||||||
|
LOG_ERROR("Failed to stop trace read time measure!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* ESP32 sysview tracing module *
|
||||||
|
* Copyright (C) 2020 Espressif Systems Ltd. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef OPENOCD_TARGET_ESP32_SYSVIEW_H
|
||||||
|
#define OPENOCD_TARGET_ESP32_SYSVIEW_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "esp32_apptrace.h"
|
||||||
|
|
||||||
|
struct esp32_sysview_cmd_data {
|
||||||
|
/* Should be the first field. Generic apptrace command handling code accesses it */
|
||||||
|
struct esp32_apptrace_cmd_data apptrace;
|
||||||
|
struct esp32_apptrace_dest data_dests[ESP32_APPTRACE_MAX_CORES_NUM];
|
||||||
|
bool mcore_format;
|
||||||
|
uint32_t sv_acc_time_delta;
|
||||||
|
unsigned int sv_last_core_id;
|
||||||
|
int sv_trace_running;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct esp32_apptrace_cmd_ctx;
|
||||||
|
|
||||||
|
int esp32_sysview_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
|
||||||
|
struct command_invocation *cmd,
|
||||||
|
int mode,
|
||||||
|
bool mcore_format,
|
||||||
|
const char **argv,
|
||||||
|
int argc);
|
||||||
|
int esp32_sysview_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx);
|
||||||
|
int esp32_sysview_process_data(struct esp32_apptrace_cmd_ctx *ctx,
|
||||||
|
unsigned int core_id,
|
||||||
|
uint8_t *data,
|
||||||
|
uint32_t data_len);
|
||||||
|
|
||||||
|
#endif /* OPENOCD_TARGET_ESP32_SYSVIEW_H */
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* SPDX-License-Identifier: BSD-1-Clause */
|
||||||
|
/* SPDX-FileCopyrightText: (c) 1995-2021 SEGGER Microcontroller GmbH. All rights reserved. */
|
||||||
|
/* SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The contend below is extracted from files SEGGER_SYSVIEW.h and SEGGER_SYSVIEW_Int.h in:
|
||||||
|
* https://www.segger.com/downloads/systemview/systemview_target_src
|
||||||
|
* SystemView version: 3.42
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPENOCD_TARGET_SEGGER_SYSVIEW_H
|
||||||
|
#define OPENOCD_TARGET_SEGGER_SYSVIEW_H
|
||||||
|
|
||||||
|
#define SYSVIEW_EVTID_NOP 0 /* Dummy packet. */
|
||||||
|
#define SYSVIEW_EVTID_OVERFLOW 1
|
||||||
|
#define SYSVIEW_EVTID_ISR_ENTER 2
|
||||||
|
#define SYSVIEW_EVTID_ISR_EXIT 3
|
||||||
|
#define SYSVIEW_EVTID_TASK_START_EXEC 4
|
||||||
|
#define SYSVIEW_EVTID_TASK_STOP_EXEC 5
|
||||||
|
#define SYSVIEW_EVTID_TASK_START_READY 6
|
||||||
|
#define SYSVIEW_EVTID_TASK_STOP_READY 7
|
||||||
|
#define SYSVIEW_EVTID_TASK_CREATE 8
|
||||||
|
#define SYSVIEW_EVTID_TASK_INFO 9
|
||||||
|
#define SYSVIEW_EVTID_TRACE_START 10
|
||||||
|
#define SYSVIEW_EVTID_TRACE_STOP 11
|
||||||
|
#define SYSVIEW_EVTID_SYSTIME_CYCLES 12
|
||||||
|
#define SYSVIEW_EVTID_SYSTIME_US 13
|
||||||
|
#define SYSVIEW_EVTID_SYSDESC 14
|
||||||
|
#define SYSVIEW_EVTID_USER_START 15
|
||||||
|
#define SYSVIEW_EVTID_USER_STOP 16
|
||||||
|
#define SYSVIEW_EVTID_IDLE 17
|
||||||
|
#define SYSVIEW_EVTID_ISR_TO_SCHEDULER 18
|
||||||
|
#define SYSVIEW_EVTID_TIMER_ENTER 19
|
||||||
|
#define SYSVIEW_EVTID_TIMER_EXIT 20
|
||||||
|
#define SYSVIEW_EVTID_STACK_INFO 21
|
||||||
|
#define SYSVIEW_EVTID_MODULEDESC 22
|
||||||
|
|
||||||
|
#define SYSVIEW_EVTID_INIT 24
|
||||||
|
#define SYSVIEW_EVTID_NAME_RESOURCE 25
|
||||||
|
#define SYSVIEW_EVTID_PRINT_FORMATTED 26
|
||||||
|
#define SYSVIEW_EVTID_NUMMODULES 27
|
||||||
|
#define SYSVIEW_EVTID_END_CALL 28
|
||||||
|
#define SYSVIEW_EVTID_TASK_TERMINATE 29
|
||||||
|
|
||||||
|
#define SYSVIEW_EVTID_EX 31
|
||||||
|
//
|
||||||
|
// SystemView extended events. Sent with ID 31.
|
||||||
|
//
|
||||||
|
#define SYSVIEW_EVTID_EX_MARK 0
|
||||||
|
#define SYSVIEW_EVTID_EX_NAME_MARKER 1
|
||||||
|
#define SYSVIEW_EVTID_EX_HEAP_DEFINE 2
|
||||||
|
#define SYSVIEW_EVTID_EX_HEAP_ALLOC 3
|
||||||
|
#define SYSVIEW_EVTID_EX_HEAP_ALLOC_EX 4
|
||||||
|
#define SYSVIEW_EVTID_EX_HEAP_FREE 5
|
||||||
|
|
||||||
|
#define SYSVIEW_SYNC_LEN 10
|
||||||
|
|
||||||
|
#define SYSVIEW_EVENT_ID_MAX (200)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Commands that Host can send to target
|
||||||
|
//
|
||||||
|
enum {
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_START = 1,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_STOP,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_SYSTIME,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_TASKLIST,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_SYSDESC,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_NUMMODULES,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_MODULEDESC,
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_HEARTBEAT = 127,
|
||||||
|
// Extended commands: Commands >= 128 have a second parameter
|
||||||
|
SEGGER_SYSVIEW_COMMAND_ID_GET_MODULE = 128
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Minimum compatible SEGGER SystemView tool version */
|
||||||
|
#define SYSVIEW_MIN_VER_STRING "SEGGER SystemViewer V2.42"
|
||||||
|
|
||||||
|
#endif
|
|
@ -407,10 +407,12 @@ static int image_elf32_read_headers(struct image *image)
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count useful segments (loadable) */
|
/* count useful segments (loadable), ignore BSS section */
|
||||||
image->num_sections = 0;
|
image->num_sections = 0;
|
||||||
for (i = 0; i < elf->segment_count; i++)
|
for (i = 0; i < elf->segment_count; i++)
|
||||||
if (field32(elf, elf->segments32[i].p_type) == PT_LOAD)
|
if ((field32(elf,
|
||||||
|
elf->segments32[i].p_type) == PT_LOAD) &&
|
||||||
|
(field32(elf, elf->segments32[i].p_filesz) != 0))
|
||||||
image->num_sections++;
|
image->num_sections++;
|
||||||
|
|
||||||
if (image->num_sections == 0) {
|
if (image->num_sections == 0) {
|
||||||
|
@ -447,8 +449,10 @@ static int image_elf32_read_headers(struct image *image)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
||||||
if (field32(elf, elf->segments32[i].p_type) == PT_LOAD) {
|
if ((field32(elf,
|
||||||
image->sections[j].size = field32(elf, elf->segments32[i].p_memsz);
|
elf->segments32[i].p_type) == PT_LOAD) &&
|
||||||
|
(field32(elf, elf->segments32[i].p_filesz) != 0)) {
|
||||||
|
image->sections[j].size = field32(elf, elf->segments32[i].p_filesz);
|
||||||
if (load_to_vaddr)
|
if (load_to_vaddr)
|
||||||
image->sections[j].base_address = field32(elf,
|
image->sections[j].base_address = field32(elf,
|
||||||
elf->segments32[i].p_vaddr);
|
elf->segments32[i].p_vaddr);
|
||||||
|
@ -528,10 +532,12 @@ static int image_elf64_read_headers(struct image *image)
|
||||||
return ERROR_FILEIO_OPERATION_FAILED;
|
return ERROR_FILEIO_OPERATION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* count useful segments (loadable) */
|
/* count useful segments (loadable), ignore BSS section */
|
||||||
image->num_sections = 0;
|
image->num_sections = 0;
|
||||||
for (i = 0; i < elf->segment_count; i++)
|
for (i = 0; i < elf->segment_count; i++)
|
||||||
if (field32(elf, elf->segments64[i].p_type) == PT_LOAD)
|
if ((field32(elf,
|
||||||
|
elf->segments64[i].p_type) == PT_LOAD) &&
|
||||||
|
(field64(elf, elf->segments64[i].p_filesz) != 0))
|
||||||
image->num_sections++;
|
image->num_sections++;
|
||||||
|
|
||||||
if (image->num_sections == 0) {
|
if (image->num_sections == 0) {
|
||||||
|
@ -568,8 +574,10 @@ static int image_elf64_read_headers(struct image *image)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
for (i = 0, j = 0; i < elf->segment_count; i++) {
|
||||||
if (field32(elf, elf->segments64[i].p_type) == PT_LOAD) {
|
if ((field32(elf,
|
||||||
image->sections[j].size = field64(elf, elf->segments64[i].p_memsz);
|
elf->segments64[i].p_type) == PT_LOAD) &&
|
||||||
|
(field64(elf, elf->segments64[i].p_filesz) != 0)) {
|
||||||
|
image->sections[j].size = field64(elf, elf->segments64[i].p_filesz);
|
||||||
if (load_to_vaddr)
|
if (load_to_vaddr)
|
||||||
image->sections[j].base_address = field64(elf,
|
image->sections[j].base_address = field64(elf,
|
||||||
elf->segments64[i].p_vaddr);
|
elf->segments64[i].p_vaddr);
|
||||||
|
@ -643,8 +651,6 @@ static int image_elf32_read_section(struct image *image,
|
||||||
{
|
{
|
||||||
struct image_elf *elf = image->type_private;
|
struct image_elf *elf = image->type_private;
|
||||||
Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private;
|
Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private;
|
||||||
uint32_t filesz = field32(elf, segment->p_filesz);
|
|
||||||
uint32_t memsz = field32(elf, segment->p_memsz);
|
|
||||||
size_t read_size, really_read;
|
size_t read_size, really_read;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -653,9 +659,9 @@ static int image_elf32_read_section(struct image *image,
|
||||||
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
||||||
|
|
||||||
/* read initialized data in current segment if any */
|
/* read initialized data in current segment if any */
|
||||||
if (offset < filesz) {
|
if (offset < field32(elf, segment->p_filesz)) {
|
||||||
/* maximal size present in file for the current segment */
|
/* maximal size present in file for the current segment */
|
||||||
read_size = MIN(size, filesz - offset);
|
read_size = MIN(size, field32(elf, segment->p_filesz) - offset);
|
||||||
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
||||||
field32(elf, segment->p_offset) + offset);
|
field32(elf, segment->p_offset) + offset);
|
||||||
/* read initialized area of the segment */
|
/* read initialized area of the segment */
|
||||||
|
@ -669,8 +675,6 @@ static int image_elf32_read_section(struct image *image,
|
||||||
LOG_ERROR("cannot read ELF segment content, read failed");
|
LOG_ERROR("cannot read ELF segment content, read failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
buffer += read_size;
|
|
||||||
offset += read_size;
|
|
||||||
size -= read_size;
|
size -= read_size;
|
||||||
*size_read += read_size;
|
*size_read += read_size;
|
||||||
/* need more data ? */
|
/* need more data ? */
|
||||||
|
@ -678,13 +682,6 @@ static int image_elf32_read_section(struct image *image,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear bss in current segment if any */
|
|
||||||
if (offset >= filesz) {
|
|
||||||
uint32_t memset_size = MIN(size, memsz - filesz);
|
|
||||||
memset(buffer, 0, memset_size);
|
|
||||||
*size_read += memset_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,8 +694,6 @@ static int image_elf64_read_section(struct image *image,
|
||||||
{
|
{
|
||||||
struct image_elf *elf = image->type_private;
|
struct image_elf *elf = image->type_private;
|
||||||
Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private;
|
Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private;
|
||||||
uint64_t filesz = field64(elf, segment->p_filesz);
|
|
||||||
uint64_t memsz = field64(elf, segment->p_memsz);
|
|
||||||
size_t read_size, really_read;
|
size_t read_size, really_read;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -707,9 +702,9 @@ static int image_elf64_read_section(struct image *image,
|
||||||
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
|
||||||
|
|
||||||
/* read initialized data in current segment if any */
|
/* read initialized data in current segment if any */
|
||||||
if (offset < filesz) {
|
if (offset < field64(elf, segment->p_filesz)) {
|
||||||
/* maximal size present in file for the current segment */
|
/* maximal size present in file for the current segment */
|
||||||
read_size = MIN(size, filesz - offset);
|
read_size = MIN(size, field64(elf, segment->p_filesz) - offset);
|
||||||
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
|
||||||
field64(elf, segment->p_offset) + offset);
|
field64(elf, segment->p_offset) + offset);
|
||||||
/* read initialized area of the segment */
|
/* read initialized area of the segment */
|
||||||
|
@ -723,8 +718,6 @@ static int image_elf64_read_section(struct image *image,
|
||||||
LOG_ERROR("cannot read ELF segment content, read failed");
|
LOG_ERROR("cannot read ELF segment content, read failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
buffer += read_size;
|
|
||||||
offset += read_size;
|
|
||||||
size -= read_size;
|
size -= read_size;
|
||||||
*size_read += read_size;
|
*size_read += read_size;
|
||||||
/* need more data ? */
|
/* need more data ? */
|
||||||
|
@ -732,13 +725,6 @@ static int image_elf64_read_section(struct image *image,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear bss in current segment if any */
|
|
||||||
if (offset >= filesz) {
|
|
||||||
uint64_t memset_size = MIN(size, memsz - filesz);
|
|
||||||
memset(buffer, 0, memset_size);
|
|
||||||
*size_read += memset_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,7 @@ int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, s
|
||||||
|
|
||||||
/* run to exit point. return error if exit point was not reached. */
|
/* run to exit point. return error if exit point was not reached. */
|
||||||
static int mips32_run_and_wait(struct target *target, target_addr_t entry_point,
|
static int mips32_run_and_wait(struct target *target, target_addr_t entry_point,
|
||||||
int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32)
|
unsigned int timeout_ms, target_addr_t exit_point, struct mips32_common *mips32)
|
||||||
{
|
{
|
||||||
uint32_t pc;
|
uint32_t pc;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -418,7 +418,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point,
|
||||||
int mips32_run_algorithm(struct target *target, int num_mem_params,
|
int mips32_run_algorithm(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_params, target_addr_t entry_point,
|
struct reg_param *reg_params, target_addr_t entry_point,
|
||||||
target_addr_t exit_point, int timeout_ms, void *arch_info)
|
target_addr_t exit_point, unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
struct mips32_common *mips32 = target_to_mips32(target);
|
struct mips32_common *mips32 = target_to_mips32(target);
|
||||||
struct mips32_algorithm *mips32_algorithm_info = arch_info;
|
struct mips32_algorithm *mips32_algorithm_info = arch_info;
|
||||||
|
@ -803,7 +803,7 @@ int mips32_checksum_memory(struct target *target, target_addr_t address,
|
||||||
init_reg_param(®_params[1], "r5", 32, PARAM_OUT);
|
init_reg_param(®_params[1], "r5", 32, PARAM_OUT);
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
buf_set_u32(reg_params[1].value, 0, 32, count);
|
||||||
|
|
||||||
int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
unsigned int timeout = 20000 * (1 + (count / (1024 * 1024)));
|
||||||
|
|
||||||
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
|
retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
|
||||||
crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info);
|
crc_algorithm->address + (sizeof(mips_crc_code) - 4), timeout, &mips32_info);
|
||||||
|
|
|
@ -400,7 +400,7 @@ int mips32_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
int mips32_configure_break_unit(struct target *target);
|
int mips32_configure_break_unit(struct target *target);
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ int mips64_init_arch_info(struct target *target, struct mips64_common *mips64,
|
||||||
int mips64_run_algorithm(struct target *target, int num_mem_params,
|
int mips64_run_algorithm(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_params, target_addr_t entry_point,
|
struct reg_param *reg_params, target_addr_t entry_point,
|
||||||
target_addr_t exit_point, int timeout_ms, void *arch_info)
|
target_addr_t exit_point, unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
|
@ -213,7 +213,7 @@ int mips64_build_reg_cache(struct target *target);
|
||||||
int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params,
|
int mips64_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
int mips64_configure_break_unit(struct target *target);
|
int mips64_configure_break_unit(struct target *target);
|
||||||
int mips64_enable_interrupts(struct target *target, bool enable);
|
int mips64_enable_interrupts(struct target *target, bool enable);
|
||||||
int mips64_examine(struct target *target);
|
int mips64_examine(struct target *target);
|
||||||
|
|
|
@ -2573,7 +2573,7 @@ static int riscv_arch_state(struct target *target)
|
||||||
static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
static int riscv_run_algorithm(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_params, target_addr_t entry_point,
|
struct reg_param *reg_params, target_addr_t entry_point,
|
||||||
target_addr_t exit_point, int timeout_ms, void *arch_info)
|
target_addr_t exit_point, unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
RISCV_INFO(info);
|
RISCV_INFO(info);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
#include <helper/log.h>
|
#include <helper/log.h>
|
||||||
|
#include <server/gdb_server.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,9 +93,6 @@ static int semihosting_common_fileio_info(struct target *target,
|
||||||
static int semihosting_common_fileio_end(struct target *target, int result,
|
static int semihosting_common_fileio_end(struct target *target, int result,
|
||||||
int fileio_errno, bool ctrl_c);
|
int fileio_errno, bool ctrl_c);
|
||||||
|
|
||||||
/* Attempts to include gdb_server.h failed. */
|
|
||||||
extern int gdb_actual_connections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize common semihosting support.
|
* Initialize common semihosting support.
|
||||||
*
|
*
|
||||||
|
@ -493,7 +491,7 @@ int semihosting_common(struct target *target)
|
||||||
int code = semihosting_get_field(target, 1, fields);
|
int code = semihosting_get_field(target, 1, fields);
|
||||||
|
|
||||||
if (type == ADP_STOPPED_APPLICATION_EXIT) {
|
if (type == ADP_STOPPED_APPLICATION_EXIT) {
|
||||||
if (!gdb_actual_connections)
|
if (!gdb_get_actual_connections())
|
||||||
exit(code);
|
exit(code);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -508,7 +506,7 @@ int semihosting_common(struct target *target)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
|
if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) {
|
||||||
if (!gdb_actual_connections)
|
if (!gdb_get_actual_connections())
|
||||||
exit(0);
|
exit(0);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -517,14 +515,14 @@ int semihosting_common(struct target *target)
|
||||||
} else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
|
} else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) {
|
||||||
/* Chosen more or less arbitrarily to have a nicer message,
|
/* Chosen more or less arbitrarily to have a nicer message,
|
||||||
* otherwise all other return the same exit code 1. */
|
* otherwise all other return the same exit code 1. */
|
||||||
if (!gdb_actual_connections)
|
if (!gdb_get_actual_connections())
|
||||||
exit(1);
|
exit(1);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"semihosting: *** application exited with error ***\n");
|
"semihosting: *** application exited with error ***\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!gdb_actual_connections)
|
if (!gdb_get_actual_connections())
|
||||||
exit(1);
|
exit(1);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -584,7 +582,7 @@ int semihosting_common(struct target *target)
|
||||||
int code = semihosting_get_field(target, 1, fields);
|
int code = semihosting_get_field(target, 1, fields);
|
||||||
|
|
||||||
if (type == ADP_STOPPED_APPLICATION_EXIT) {
|
if (type == ADP_STOPPED_APPLICATION_EXIT) {
|
||||||
if (!gdb_actual_connections)
|
if (!gdb_get_actual_connections())
|
||||||
exit(code);
|
exit(code);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -781,7 +779,8 @@ int semihosting_common(struct target *target)
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
int fd = semihosting_get_field(target, 0, fields);
|
int fd = semihosting_get_field(target, 0, fields);
|
||||||
semihosting->result = isatty(fd);
|
// isatty() on Windows may return any non-zero value if fd is a terminal
|
||||||
|
semihosting->result = isatty(fd) ? 1 : 0;
|
||||||
semihosting->sys_errno = errno;
|
semihosting->sys_errno = errno;
|
||||||
LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
|
LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1784,7 +1784,7 @@ static int stm8_checksum_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
/* run to exit point. return error if exit point was not reached. */
|
/* run to exit point. return error if exit point was not reached. */
|
||||||
static int stm8_run_and_wait(struct target *target, uint32_t entry_point,
|
static int stm8_run_and_wait(struct target *target, uint32_t entry_point,
|
||||||
int timeout_ms, uint32_t exit_point, struct stm8_common *stm8)
|
unsigned int timeout_ms, uint32_t exit_point, struct stm8_common *stm8)
|
||||||
{
|
{
|
||||||
uint32_t pc;
|
uint32_t pc;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -1819,7 +1819,7 @@ static int stm8_run_and_wait(struct target *target, uint32_t entry_point,
|
||||||
static int stm8_run_algorithm(struct target *target, int num_mem_params,
|
static int stm8_run_algorithm(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_params, target_addr_t entry_point,
|
struct reg_param *reg_params, target_addr_t entry_point,
|
||||||
target_addr_t exit_point, int timeout_ms, void *arch_info)
|
target_addr_t exit_point, unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
struct stm8_common *stm8 = target_to_stm8(target);
|
struct stm8_common *stm8 = target_to_stm8(target);
|
||||||
|
|
||||||
|
|
|
@ -210,7 +210,7 @@ static const struct jim_nvp nvp_target_event[] = {
|
||||||
{ .name = NULL, .value = -1 }
|
{ .name = NULL, .value = -1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct jim_nvp nvp_target_state[] = {
|
static const struct nvp nvp_target_state[] = {
|
||||||
{ .name = "unknown", .value = TARGET_UNKNOWN },
|
{ .name = "unknown", .value = TARGET_UNKNOWN },
|
||||||
{ .name = "running", .value = TARGET_RUNNING },
|
{ .name = "running", .value = TARGET_RUNNING },
|
||||||
{ .name = "halted", .value = TARGET_HALTED },
|
{ .name = "halted", .value = TARGET_HALTED },
|
||||||
|
@ -265,7 +265,7 @@ const char *debug_reason_name(struct target *t)
|
||||||
const char *target_state_name(struct target *t)
|
const char *target_state_name(struct target *t)
|
||||||
{
|
{
|
||||||
const char *cp;
|
const char *cp;
|
||||||
cp = jim_nvp_value2name_simple(nvp_target_state, t->state)->name;
|
cp = nvp_value2name(nvp_target_state, t->state)->name;
|
||||||
if (!cp) {
|
if (!cp) {
|
||||||
LOG_ERROR("Invalid target state: %d", (int)(t->state));
|
LOG_ERROR("Invalid target state: %d", (int)(t->state));
|
||||||
cp = "(*BUG*unknown*BUG*)";
|
cp = "(*BUG*unknown*BUG*)";
|
||||||
|
@ -819,7 +819,7 @@ int target_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_param,
|
int num_reg_params, struct reg_param *reg_param,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info)
|
unsigned int timeout_ms, void *arch_info)
|
||||||
{
|
{
|
||||||
int retval = ERROR_FAIL;
|
int retval = ERROR_FAIL;
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ done:
|
||||||
int target_wait_algorithm(struct target *target,
|
int target_wait_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t exit_point, int timeout_ms,
|
target_addr_t exit_point, unsigned int timeout_ms,
|
||||||
void *arch_info)
|
void *arch_info)
|
||||||
{
|
{
|
||||||
int retval = ERROR_FAIL;
|
int retval = ERROR_FAIL;
|
||||||
|
@ -3230,7 +3230,7 @@ COMMAND_HANDLER(handle_wait_halt_command)
|
||||||
*
|
*
|
||||||
* After 500ms, keep_alive() is invoked
|
* After 500ms, keep_alive() is invoked
|
||||||
*/
|
*/
|
||||||
int target_wait_state(struct target *target, enum target_state state, int ms)
|
int target_wait_state(struct target *target, enum target_state state, unsigned int ms)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
int64_t then = 0, cur;
|
int64_t then = 0, cur;
|
||||||
|
@ -3247,7 +3247,7 @@ int target_wait_state(struct target *target, enum target_state state, int ms)
|
||||||
once = false;
|
once = false;
|
||||||
then = timeval_ms();
|
then = timeval_ms();
|
||||||
LOG_DEBUG("waiting for target %s...",
|
LOG_DEBUG("waiting for target %s...",
|
||||||
jim_nvp_value2name_simple(nvp_target_state, state)->name);
|
nvp_value2name(nvp_target_state, state)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur-then > 500)
|
if (cur-then > 500)
|
||||||
|
@ -3255,7 +3255,7 @@ int target_wait_state(struct target *target, enum target_state state, int ms)
|
||||||
|
|
||||||
if ((cur-then) > ms) {
|
if ((cur-then) > ms) {
|
||||||
LOG_ERROR("timed out while waiting for target %s",
|
LOG_ERROR("timed out while waiting for target %s",
|
||||||
jim_nvp_value2name_simple(nvp_target_state, state)->name);
|
nvp_value2name(nvp_target_state, state)->name);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5635,55 +5635,40 @@ static int jim_target_array2mem(Jim_Interp *interp,
|
||||||
return target_array2mem(interp, target, argc - 1, argv + 1);
|
return target_array2mem(interp, target, argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_target_tap_disabled(Jim_Interp *interp)
|
COMMAND_HANDLER(handle_target_examine)
|
||||||
{
|
|
||||||
Jim_SetResultFormatted(interp, "[TAP is disabled]");
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|
||||||
{
|
{
|
||||||
bool allow_defer = false;
|
bool allow_defer = false;
|
||||||
|
|
||||||
struct jim_getopt_info goi;
|
if (CMD_ARGC > 1)
|
||||||
jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
if (goi.argc > 1) {
|
|
||||||
const char *cmd_name = Jim_GetString(argv[0], NULL);
|
if (CMD_ARGC == 1) {
|
||||||
Jim_SetResultFormatted(goi.interp,
|
if (strcmp(CMD_ARGV[0], "allow-defer"))
|
||||||
"usage: %s ['allow-defer']", cmd_name);
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
return JIM_ERR;
|
|
||||||
}
|
|
||||||
if (goi.argc > 0 &&
|
|
||||||
strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) {
|
|
||||||
/* consume it */
|
|
||||||
Jim_Obj *obj;
|
|
||||||
int e = jim_getopt_obj(&goi, &obj);
|
|
||||||
if (e != JIM_OK)
|
|
||||||
return e;
|
|
||||||
allow_defer = true;
|
allow_defer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct command_context *cmd_ctx = current_command_context(interp);
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
assert(cmd_ctx);
|
if (!target->tap->enabled) {
|
||||||
struct target *target = get_current_target(cmd_ctx);
|
command_print(CMD, "[TAP is disabled]");
|
||||||
if (!target->tap->enabled)
|
return ERROR_FAIL;
|
||||||
return jim_target_tap_disabled(interp);
|
}
|
||||||
|
|
||||||
if (allow_defer && target->defer_examine) {
|
if (allow_defer && target->defer_examine) {
|
||||||
LOG_INFO("Deferring arp_examine of %s", target_name(target));
|
LOG_INFO("Deferring arp_examine of %s", target_name(target));
|
||||||
LOG_INFO("Use arp_examine command to examine it manually!");
|
LOG_INFO("Use arp_examine command to examine it manually!");
|
||||||
return JIM_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int e = target->type->examine(target);
|
int retval = target->type->examine(target);
|
||||||
if (e != ERROR_OK) {
|
if (retval != ERROR_OK) {
|
||||||
target_reset_examined(target);
|
target_reset_examined(target);
|
||||||
return JIM_ERR;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
target_set_examined(target);
|
target_set_examined(target);
|
||||||
|
|
||||||
return JIM_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND_HANDLER(handle_target_was_examined)
|
COMMAND_HANDLER(handle_target_was_examined)
|
||||||
|
@ -5791,45 +5776,35 @@ COMMAND_HANDLER(handle_target_halt)
|
||||||
return target->type->halt(target);
|
return target->type->halt(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
COMMAND_HANDLER(handle_target_wait_state)
|
||||||
{
|
{
|
||||||
struct jim_getopt_info goi;
|
if (CMD_ARGC != 2)
|
||||||
jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
/* params: <name> statename timeoutmsecs */
|
const struct nvp *n = nvp_name2value(nvp_target_state, CMD_ARGV[0]);
|
||||||
if (goi.argc != 2) {
|
if (!n->name) {
|
||||||
const char *cmd_name = Jim_GetString(argv[0], NULL);
|
nvp_unknown_command_print(CMD, nvp_target_state, NULL, CMD_ARGV[0]);
|
||||||
Jim_SetResultFormatted(goi.interp,
|
return ERROR_COMMAND_ARGUMENT_INVALID;
|
||||||
"%s <state_name> <timeout_in_msec>", cmd_name);
|
|
||||||
return JIM_ERR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct jim_nvp *n;
|
unsigned int a;
|
||||||
int e = jim_getopt_nvp(&goi, nvp_target_state, &n);
|
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], a);
|
||||||
if (e != JIM_OK) {
|
|
||||||
jim_getopt_nvp_unknown(&goi, nvp_target_state, 1);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
jim_wide a;
|
|
||||||
e = jim_getopt_wide(&goi, &a);
|
|
||||||
if (e != JIM_OK)
|
|
||||||
return e;
|
|
||||||
struct command_context *cmd_ctx = current_command_context(interp);
|
|
||||||
assert(cmd_ctx);
|
|
||||||
struct target *target = get_current_target(cmd_ctx);
|
|
||||||
if (!target->tap->enabled)
|
|
||||||
return jim_target_tap_disabled(interp);
|
|
||||||
|
|
||||||
e = target_wait_state(target, n->value, a);
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
if (e != ERROR_OK) {
|
if (!target->tap->enabled) {
|
||||||
Jim_Obj *obj = Jim_NewIntObj(interp, e);
|
command_print(CMD, "[TAP is disabled]");
|
||||||
Jim_SetResultFormatted(goi.interp,
|
return ERROR_FAIL;
|
||||||
"target: %s wait %s fails (%#s) %s",
|
}
|
||||||
|
|
||||||
|
int retval = target_wait_state(target, n->value, a);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD,
|
||||||
|
"target: %s wait %s fails (%d) %s",
|
||||||
target_name(target), n->name,
|
target_name(target), n->name,
|
||||||
obj, target_strerror_safe(e));
|
retval, target_strerror_safe(retval));
|
||||||
return JIM_ERR;
|
return retval;
|
||||||
}
|
}
|
||||||
return JIM_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
/* List for human, Events defined for this target.
|
/* List for human, Events defined for this target.
|
||||||
* scripts/programs should use 'name cget -event NAME'
|
* scripts/programs should use 'name cget -event NAME'
|
||||||
|
@ -6021,7 +5996,7 @@ static const struct command_registration target_instance_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "arp_examine",
|
.name = "arp_examine",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_target_examine,
|
.handler = handle_target_examine,
|
||||||
.help = "used internally for reset processing",
|
.help = "used internally for reset processing",
|
||||||
.usage = "['allow-defer']",
|
.usage = "['allow-defer']",
|
||||||
},
|
},
|
||||||
|
@ -6070,8 +6045,9 @@ static const struct command_registration target_instance_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "arp_waitstate",
|
.name = "arp_waitstate",
|
||||||
.mode = COMMAND_EXEC,
|
.mode = COMMAND_EXEC,
|
||||||
.jim_handler = jim_target_wait_state,
|
.handler = handle_target_wait_state,
|
||||||
.help = "used internally for reset processing",
|
.help = "used internally for reset processing",
|
||||||
|
.usage = "statename timeoutmsecs",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "invoke-event",
|
.name = "invoke-event",
|
||||||
|
@ -7173,3 +7149,29 @@ static int target_register_user_commands(struct command_context *cmd_ctx)
|
||||||
|
|
||||||
return register_commands(cmd_ctx, NULL, target_exec_command_handlers);
|
return register_commands(cmd_ctx, NULL, target_exec_command_handlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *target_debug_reason_str(enum target_debug_reason reason)
|
||||||
|
{
|
||||||
|
switch (reason) {
|
||||||
|
case DBG_REASON_DBGRQ:
|
||||||
|
return "DBGRQ";
|
||||||
|
case DBG_REASON_BREAKPOINT:
|
||||||
|
return "BREAKPOINT";
|
||||||
|
case DBG_REASON_WATCHPOINT:
|
||||||
|
return "WATCHPOINT";
|
||||||
|
case DBG_REASON_WPTANDBKPT:
|
||||||
|
return "WPTANDBKPT";
|
||||||
|
case DBG_REASON_SINGLESTEP:
|
||||||
|
return "SINGLESTEP";
|
||||||
|
case DBG_REASON_NOTHALTED:
|
||||||
|
return "NOTHALTED";
|
||||||
|
case DBG_REASON_EXIT:
|
||||||
|
return "EXIT";
|
||||||
|
case DBG_REASON_EXC_CATCH:
|
||||||
|
return "EXC_CATCH";
|
||||||
|
case DBG_REASON_UNDEFINED:
|
||||||
|
return "UNDEFINED";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -553,7 +553,7 @@ int target_run_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_param,
|
int num_reg_params, struct reg_param *reg_param,
|
||||||
target_addr_t entry_point, target_addr_t exit_point,
|
target_addr_t entry_point, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an algorithm in the background on the @a target given.
|
* Starts an algorithm in the background on the @a target given.
|
||||||
|
@ -574,7 +574,7 @@ int target_start_algorithm(struct target *target,
|
||||||
int target_wait_algorithm(struct target *target,
|
int target_wait_algorithm(struct target *target,
|
||||||
int num_mem_params, struct mem_param *mem_params,
|
int num_mem_params, struct mem_param *mem_params,
|
||||||
int num_reg_params, struct reg_param *reg_params,
|
int num_reg_params, struct reg_param *reg_params,
|
||||||
target_addr_t exit_point, int timeout_ms,
|
target_addr_t exit_point, unsigned int timeout_ms,
|
||||||
void *arch_info);
|
void *arch_info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -666,7 +666,7 @@ int target_checksum_memory(struct target *target,
|
||||||
int target_blank_check_memory(struct target *target,
|
int target_blank_check_memory(struct target *target,
|
||||||
struct target_memory_check_block *blocks, int num_blocks,
|
struct target_memory_check_block *blocks, int num_blocks,
|
||||||
uint8_t erased_value);
|
uint8_t erased_value);
|
||||||
int target_wait_state(struct target *target, enum target_state state, int ms);
|
int target_wait_state(struct target *target, enum target_state state, unsigned int ms);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain file-I/O information from target for GDB to do syscall.
|
* Obtain file-I/O information from target for GDB to do syscall.
|
||||||
|
@ -809,4 +809,6 @@ extern bool get_target_reset_nag(void);
|
||||||
|
|
||||||
#define TARGET_DEFAULT_POLLING_INTERVAL 100
|
#define TARGET_DEFAULT_POLLING_INTERVAL 100
|
||||||
|
|
||||||
|
const char *target_debug_reason_str(enum target_debug_reason reason);
|
||||||
|
|
||||||
#endif /* OPENOCD_TARGET_TARGET_H */
|
#endif /* OPENOCD_TARGET_TARGET_H */
|
||||||
|
|
|
@ -181,7 +181,7 @@ struct target_type {
|
||||||
int (*run_algorithm)(struct target *target, int num_mem_params,
|
int (*run_algorithm)(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_param, target_addr_t entry_point,
|
struct reg_param *reg_param, target_addr_t entry_point,
|
||||||
target_addr_t exit_point, int timeout_ms, void *arch_info);
|
target_addr_t exit_point, unsigned int timeout_ms, void *arch_info);
|
||||||
int (*start_algorithm)(struct target *target, int num_mem_params,
|
int (*start_algorithm)(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_param, target_addr_t entry_point,
|
struct reg_param *reg_param, target_addr_t entry_point,
|
||||||
|
@ -189,7 +189,7 @@ struct target_type {
|
||||||
int (*wait_algorithm)(struct target *target, int num_mem_params,
|
int (*wait_algorithm)(struct target *target, int num_mem_params,
|
||||||
struct mem_param *mem_params, int num_reg_params,
|
struct mem_param *mem_params, int num_reg_params,
|
||||||
struct reg_param *reg_param, target_addr_t exit_point,
|
struct reg_param *reg_param, target_addr_t exit_point,
|
||||||
int timeout_ms, void *arch_info);
|
unsigned int timeout_ms, void *arch_info);
|
||||||
|
|
||||||
const struct command_registration *commands;
|
const struct command_registration *commands;
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,6 @@ noinst_LTLIBRARIES += %D%/libxtensa.la
|
||||||
%D%/xtensa_chip.h \
|
%D%/xtensa_chip.h \
|
||||||
%D%/xtensa_debug_module.c \
|
%D%/xtensa_debug_module.c \
|
||||||
%D%/xtensa_debug_module.h \
|
%D%/xtensa_debug_module.h \
|
||||||
|
%D%/xtensa_fileio.c \
|
||||||
|
%D%/xtensa_fileio.h \
|
||||||
%D%/xtensa_regs.h
|
%D%/xtensa_regs.h
|
||||||
|
|
|
@ -1544,6 +1544,7 @@ int xtensa_prepare_resume(struct target *target,
|
||||||
LOG_TARGET_WARNING(target, "target not halted");
|
LOG_TARGET_WARNING(target, "target not halted");
|
||||||
return ERROR_TARGET_NOT_HALTED;
|
return ERROR_TARGET_NOT_HALTED;
|
||||||
}
|
}
|
||||||
|
xtensa->halt_request = false;
|
||||||
|
|
||||||
if (address && !current) {
|
if (address && !current) {
|
||||||
xtensa_reg_set(target, XT_REG_IDX_PC, address);
|
xtensa_reg_set(target, XT_REG_IDX_PC, address);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <target/arm_adi_v5.h>
|
#include <target/arm_adi_v5.h>
|
||||||
#include <rtos/rtos.h>
|
#include <rtos/rtos.h>
|
||||||
#include "xtensa_chip.h"
|
#include "xtensa_chip.h"
|
||||||
|
#include "xtensa_fileio.h"
|
||||||
|
|
||||||
int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
|
int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
|
||||||
struct xtensa_debug_module_config *dm_cfg)
|
struct xtensa_debug_module_config *dm_cfg)
|
||||||
|
@ -30,7 +31,10 @@ int xtensa_chip_init_arch_info(struct target *target, void *arch_info,
|
||||||
|
|
||||||
int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target)
|
int xtensa_chip_target_init(struct command_context *cmd_ctx, struct target *target)
|
||||||
{
|
{
|
||||||
return xtensa_target_init(cmd_ctx, target);
|
int ret = xtensa_target_init(cmd_ctx, target);
|
||||||
|
if (ret != ERROR_OK)
|
||||||
|
return ret;
|
||||||
|
return xtensa_fileio_init(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
int xtensa_chip_arch_state(struct target *target)
|
int xtensa_chip_arch_state(struct target *target)
|
||||||
|
@ -45,10 +49,12 @@ static int xtensa_chip_poll(struct target *target)
|
||||||
|
|
||||||
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
|
if (old_state != TARGET_HALTED && target->state == TARGET_HALTED) {
|
||||||
/*Call any event callbacks that are applicable */
|
/*Call any event callbacks that are applicable */
|
||||||
if (old_state == TARGET_DEBUG_RUNNING)
|
if (old_state == TARGET_DEBUG_RUNNING) {
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
|
||||||
else
|
} else {
|
||||||
|
xtensa_fileio_detect_proc(target);
|
||||||
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -193,4 +199,7 @@ struct target_type xtensa_chip_target = {
|
||||||
.gdb_query_custom = xtensa_gdb_query_custom,
|
.gdb_query_custom = xtensa_gdb_query_custom,
|
||||||
|
|
||||||
.commands = xtensa_command_handlers,
|
.commands = xtensa_command_handlers,
|
||||||
|
|
||||||
|
.get_gdb_fileio_info = xtensa_get_gdb_fileio_info,
|
||||||
|
.gdb_fileio_end = xtensa_gdb_fileio_end,
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Xtensa Target File-I/O Support for OpenOCD *
|
||||||
|
* Copyright (C) 2020-2023 Cadence Design Systems, Inc. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xtensa_chip.h"
|
||||||
|
#include "xtensa_fileio.h"
|
||||||
|
#include "xtensa.h"
|
||||||
|
|
||||||
|
#define XTENSA_SYSCALL(x) XT_INS_BREAK(x, 1, 14)
|
||||||
|
#define XTENSA_SYSCALL_SZ 3
|
||||||
|
#define XTENSA_SYSCALL_LEN_MAX 255
|
||||||
|
|
||||||
|
|
||||||
|
int xtensa_fileio_init(struct target *target)
|
||||||
|
{
|
||||||
|
char *idmem = malloc(XTENSA_SYSCALL_LEN_MAX + 1);
|
||||||
|
target->fileio_info = malloc(sizeof(struct gdb_fileio_info));
|
||||||
|
if (!idmem || !target->fileio_info) {
|
||||||
|
LOG_TARGET_ERROR(target, "Out of memory!");
|
||||||
|
free(idmem);
|
||||||
|
free(target->fileio_info);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
target->fileio_info->identifier = idmem;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for and processes an Xtensa File-IO request.
|
||||||
|
*
|
||||||
|
* Return ERROR_OK if request was found and handled; or
|
||||||
|
* return ERROR_FAIL if no request was detected.
|
||||||
|
*/
|
||||||
|
int xtensa_fileio_detect_proc(struct target *target)
|
||||||
|
{
|
||||||
|
struct xtensa *xtensa = target_to_xtensa(target);
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
xtensa_reg_val_t dbg_cause = xtensa_cause_get(target);
|
||||||
|
if ((dbg_cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)) == 0 || xtensa->halt_request)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
uint8_t brk_insn_buf[sizeof(uint32_t)] = {0};
|
||||||
|
xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
|
||||||
|
retval = target_read_memory(target,
|
||||||
|
pc,
|
||||||
|
XTENSA_SYSCALL_SZ,
|
||||||
|
1,
|
||||||
|
(uint8_t *)brk_insn_buf);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to read break instruction!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (buf_get_u32(brk_insn_buf, 0, 32) != XTENSA_SYSCALL(xtensa))
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(target, "File-I/O: syscall breakpoint found at 0x%x", pc);
|
||||||
|
xtensa->proc_syscall = true;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
|
||||||
|
{
|
||||||
|
/* fill syscall parameters to file-I/O info */
|
||||||
|
if (!fileio_info) {
|
||||||
|
LOG_ERROR("File-I/O data structure uninitialized");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xtensa *xtensa = target_to_xtensa(target);
|
||||||
|
if (!xtensa->proc_syscall)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
xtensa_reg_val_t syscall = xtensa_reg_get(target, XTENSA_SYSCALL_OP_REG);
|
||||||
|
xtensa_reg_val_t arg0 = xtensa_reg_get(target, XT_REG_IDX_A6);
|
||||||
|
xtensa_reg_val_t arg1 = xtensa_reg_get(target, XT_REG_IDX_A3);
|
||||||
|
xtensa_reg_val_t arg2 = xtensa_reg_get(target, XT_REG_IDX_A4);
|
||||||
|
xtensa_reg_val_t arg3 = xtensa_reg_get(target, XT_REG_IDX_A5);
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(target, "File-I/O: syscall 0x%x 0x%x 0x%x 0x%x 0x%x",
|
||||||
|
syscall, arg0, arg1, arg2, arg3);
|
||||||
|
|
||||||
|
switch (syscall) {
|
||||||
|
case XTENSA_SYSCALL_OPEN:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "open");
|
||||||
|
fileio_info->param_1 = arg0; // pathp
|
||||||
|
fileio_info->param_2 = arg3; // len
|
||||||
|
fileio_info->param_3 = arg1; // flags
|
||||||
|
fileio_info->param_4 = arg2; // mode
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_CLOSE:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "close");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_READ:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "read");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
fileio_info->param_2 = arg1; // bufp
|
||||||
|
fileio_info->param_3 = arg2; // count
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_WRITE:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "write");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
fileio_info->param_2 = arg1; // bufp
|
||||||
|
fileio_info->param_3 = arg2; // count
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_LSEEK:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "lseek");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
fileio_info->param_2 = arg1; // offset
|
||||||
|
fileio_info->param_3 = arg2; // flags
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_RENAME:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "rename");
|
||||||
|
fileio_info->param_1 = arg0; // old pathp
|
||||||
|
fileio_info->param_2 = arg3; // old len
|
||||||
|
fileio_info->param_3 = arg1; // new pathp
|
||||||
|
fileio_info->param_4 = arg2; // new len
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_UNLINK:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unlink");
|
||||||
|
fileio_info->param_1 = arg0; // pathnamep
|
||||||
|
fileio_info->param_2 = arg1; // len
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_STAT:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "stat");
|
||||||
|
fileio_info->param_1 = arg0; // pathnamep
|
||||||
|
fileio_info->param_2 = arg2; // len
|
||||||
|
fileio_info->param_3 = arg1; // bufp
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_FSTAT:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "fstat");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
fileio_info->param_2 = arg1; // bufp
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_GETTIMEOFDAY:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "gettimeofday");
|
||||||
|
fileio_info->param_1 = arg0; // tvp
|
||||||
|
fileio_info->param_2 = arg1; // tzp
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_ISATTY:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "isatty");
|
||||||
|
fileio_info->param_1 = arg0; // fd
|
||||||
|
break;
|
||||||
|
case XTENSA_SYSCALL_SYSTEM:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "system");
|
||||||
|
fileio_info->param_1 = arg0; // cmdp
|
||||||
|
fileio_info->param_2 = arg1; // len
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(fileio_info->identifier, XTENSA_SYSCALL_LEN_MAX, "unknown");
|
||||||
|
LOG_TARGET_DEBUG(target, "File-I/O: syscall unknown (%d), pc=0x%08X",
|
||||||
|
syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
|
||||||
|
LOG_INFO("File-I/O: syscall unknown (%d), pc=0x%08X",
|
||||||
|
syscall, xtensa_reg_get(target, XT_REG_IDX_PC));
|
||||||
|
retval = ERROR_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c)
|
||||||
|
{
|
||||||
|
struct xtensa *xtensa = target_to_xtensa(target);
|
||||||
|
if (!xtensa->proc_syscall)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
LOG_TARGET_DEBUG(target, "File-I/O: syscall return code: 0x%x, errno: 0x%x , ctrl_c: %s",
|
||||||
|
retcode, fileio_errno, ctrl_c ? "true" : "false");
|
||||||
|
|
||||||
|
/* If interrupt was requested before FIO completion (ERRNO==4), halt and repeat
|
||||||
|
* syscall. Otherwise, set File-I/O Ax and underlying ARx registers, increment PC.
|
||||||
|
* NOTE: sporadic cases of ((ERRNO==4) && !ctrl_c) were observed; most have ctrl_c.
|
||||||
|
*/
|
||||||
|
if (fileio_errno != 4) {
|
||||||
|
xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_RETVAL_REG, retcode);
|
||||||
|
xtensa_reg_set_deep_relgen(target, XTENSA_SYSCALL_ERRNO_REG, fileio_errno);
|
||||||
|
|
||||||
|
xtensa_reg_val_t pc = xtensa_reg_get(target, XT_REG_IDX_PC);
|
||||||
|
xtensa_reg_set(target, XT_REG_IDX_PC, pc + XTENSA_SYSCALL_SZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
xtensa->proc_syscall = false;
|
||||||
|
xtensa->halt_request = true;
|
||||||
|
return ctrl_c ? ERROR_FAIL : ERROR_OK;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Xtensa Target File-I/O Support for OpenOCD *
|
||||||
|
* Copyright (C) 2020-2023 Cadence Design Systems, Inc. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef OPENOCD_TARGET_XTENSA_FILEIO_H
|
||||||
|
#define OPENOCD_TARGET_XTENSA_FILEIO_H
|
||||||
|
|
||||||
|
#include <target/target.h>
|
||||||
|
#include <helper/command.h>
|
||||||
|
#include "xtensa.h"
|
||||||
|
|
||||||
|
#define XTENSA_SYSCALL_OP_REG XT_REG_IDX_A2
|
||||||
|
#define XTENSA_SYSCALL_RETVAL_REG XT_REG_IDX_A2
|
||||||
|
#define XTENSA_SYSCALL_ERRNO_REG XT_REG_IDX_A3
|
||||||
|
|
||||||
|
#define XTENSA_SYSCALL_OPEN (-2)
|
||||||
|
#define XTENSA_SYSCALL_CLOSE (-3)
|
||||||
|
#define XTENSA_SYSCALL_READ (-4)
|
||||||
|
#define XTENSA_SYSCALL_WRITE (-5)
|
||||||
|
#define XTENSA_SYSCALL_LSEEK (-6)
|
||||||
|
#define XTENSA_SYSCALL_RENAME (-7)
|
||||||
|
#define XTENSA_SYSCALL_UNLINK (-8)
|
||||||
|
#define XTENSA_SYSCALL_STAT (-9)
|
||||||
|
#define XTENSA_SYSCALL_FSTAT (-10)
|
||||||
|
#define XTENSA_SYSCALL_GETTIMEOFDAY (-11)
|
||||||
|
#define XTENSA_SYSCALL_ISATTY (-12)
|
||||||
|
#define XTENSA_SYSCALL_SYSTEM (-13)
|
||||||
|
|
||||||
|
int xtensa_fileio_init(struct target *target);
|
||||||
|
int xtensa_fileio_detect_proc(struct target *target);
|
||||||
|
int xtensa_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info);
|
||||||
|
int xtensa_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c);
|
||||||
|
|
||||||
|
#endif /* OPENOCD_TARGET_XTENSA_FILEIO_H */
|
|
@ -1,6 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
# CALAO Systems USB-A9G20-C01
|
# CALAO Systems USB-A9G20-C01
|
||||||
|
# Authors: Gregory Hermant, Jean-Christophe PLAGNIOL-VILLARD, Wolfram Sang
|
||||||
|
|
||||||
adapter driver ftdi
|
adapter driver ftdi
|
||||||
ftdi device_desc "USB-A9G20"
|
ftdi device_desc "USB-A9G20"
|
||||||
|
@ -12,3 +13,160 @@ ftdi layout_signal nSRST -data 0x0200 -noe 0x0800
|
||||||
transport select jtag
|
transport select jtag
|
||||||
|
|
||||||
source [find target/at91sam9g20.cfg]
|
source [find target/at91sam9g20.cfg]
|
||||||
|
source [find mem_helper.tcl]
|
||||||
|
|
||||||
|
proc at91sam9g20_reset_start { } {
|
||||||
|
|
||||||
|
# Make sure that the jtag is running slow, since there are a number of different ways the board
|
||||||
|
# can be configured coming into this state that can cause communication problems with the jtag
|
||||||
|
# adapter. Also since this call can be made following a "reset init" where fast memory accesses
|
||||||
|
# are enabled, Need to temporarily shut this down so that the RSTC_MR register can be written at slower
|
||||||
|
# jtag speed without causing GDB keep alive problem.
|
||||||
|
|
||||||
|
arm7_9 fast_memory_access disable
|
||||||
|
adapter speed 2 ;# Slow-speed oscillator enabled at reset, so run jtag speed slow.
|
||||||
|
halt 0 ;# Make sure processor is halted, or error will result in following steps.
|
||||||
|
wait_halt 10000
|
||||||
|
# RSTC_MR : enable user reset, MMU may be enabled... use physical address
|
||||||
|
mww phys 0xfffffd08 0xa5000501
|
||||||
|
}
|
||||||
|
|
||||||
|
proc at91sam9g20_reset_init { } {
|
||||||
|
|
||||||
|
# At reset AT91SAM9G20 chip runs on slow clock (32.768 kHz). To shift over to a normal clock requires
|
||||||
|
# a number of steps that must be carefully performed. The process outline below follows the
|
||||||
|
# recommended procedure outlined in the AT91SAM9G20 technical manual.
|
||||||
|
#
|
||||||
|
# Several key and very important things to keep in mind:
|
||||||
|
# The SDRAM parts used currently on the Atmel evaluation board are -75 grade parts. This
|
||||||
|
# means the master clock (MCLK) must be at or below 133 MHz or timing errors will occur. The processor
|
||||||
|
# core can operate up to 400 MHz and therefore PCLK must be at or below this to function properly.
|
||||||
|
|
||||||
|
mww 0xfffffd44 0x00008000 ;# WDT_MR : disable watchdog.
|
||||||
|
|
||||||
|
# Set oscillator bypass bit (12.00 MHz external oscillator) in CKGR_MOR register.
|
||||||
|
|
||||||
|
mww 0xfffffc20 0x00000002
|
||||||
|
|
||||||
|
# Set PLLA Register for 798.000 MHz (divider: bypass, multiplier: 132).
|
||||||
|
# Wait for LOCKA signal in PMC_SR to assert indicating PLLA is stable.
|
||||||
|
|
||||||
|
mww 0xfffffc28 0x20843F02
|
||||||
|
while { [expr { [mrw 0xfffffc68] & 0x02 } ] != 2 } { sleep 1 }
|
||||||
|
|
||||||
|
# Set master system clock prescaler divide by 6 and processor clock divide by 2 in PMC_MCKR.
|
||||||
|
# Wait for MCKRDY signal from PMC_SR to assert.
|
||||||
|
|
||||||
|
mww 0xfffffc30 0x00001300
|
||||||
|
while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 }
|
||||||
|
|
||||||
|
# Now change PMC_MCKR register to select PLLA.
|
||||||
|
# Wait for MCKRDY signal from PMC_SR to assert.
|
||||||
|
|
||||||
|
mww 0xfffffc30 0x00001302
|
||||||
|
while { [expr { [mrw 0xfffffc68] & 0x08 } ] != 8 } { sleep 1 }
|
||||||
|
|
||||||
|
# Processor and master clocks are now operating and stable at maximum frequency possible:
|
||||||
|
# -> MCLK = 133.000 MHz
|
||||||
|
# -> PCLK = 400.000 MHz
|
||||||
|
|
||||||
|
# Switch to fast JTAG speed
|
||||||
|
|
||||||
|
adapter speed 9500
|
||||||
|
|
||||||
|
# Enable faster DCC downloads.
|
||||||
|
|
||||||
|
arm7_9 dcc_downloads enable
|
||||||
|
arm7_9 fast_memory_access enable
|
||||||
|
|
||||||
|
# To be able to use external SDRAM, several peripheral configuration registers must
|
||||||
|
# be modified. The first change is made to PIO_ASR to select peripheral functions
|
||||||
|
# for D15 through D31. The second change is made to the PIO_PDR register to disable
|
||||||
|
# this for D15 through D31.
|
||||||
|
|
||||||
|
mww 0xfffff870 0xffff0000
|
||||||
|
mww 0xfffff804 0xffff0000
|
||||||
|
|
||||||
|
# The EBI chip select register EBI_CS must be specifically configured to enable the internal SDRAM controller
|
||||||
|
# using CS1. Additionally we want CS3 assigned to NandFlash. Also VDDIO is connected physically on
|
||||||
|
# the board to the 1.8V VDC power supply so set the appropriate register bit to notify the micrcontroller.
|
||||||
|
|
||||||
|
mww 0xffffef1c 0x000000a
|
||||||
|
|
||||||
|
# The USB-A9G20 Embedded computer has built-in NandFlash. The exact physical timing characteristics
|
||||||
|
# for the memory type used on the current board (MT29F2G08AACWP) can be established by setting
|
||||||
|
# four registers in order: SMC_SETUP3, SMC_PULSE3, SMC_CYCLE3, and SMC_MODE3.
|
||||||
|
|
||||||
|
mww 0xffffec30 0x00020002
|
||||||
|
mww 0xffffec34 0x04040404
|
||||||
|
mww 0xffffec38 0x00070007
|
||||||
|
mww 0xffffec3c 0x00030003
|
||||||
|
|
||||||
|
# Now setup SDRAM. This is tricky and configuration is very important for reliability! The current calculations
|
||||||
|
# are based on 2 x Micron LPSDRAM MT48H16M16LFBF-75 memory (4 M x 16 bit x 4 banks). If you use this file as a reference
|
||||||
|
# for a new board that uses different SDRAM devices or clock rates, you need to recalculate the value inserted
|
||||||
|
# into the SDRAM_CR register. Using the memory datasheet for the -75 grade part and assuming a master clock
|
||||||
|
# of 133.000 MHz then the SDCLK period is equal to 7.6 ns. This means the device requires:
|
||||||
|
#
|
||||||
|
# CAS latency = 3 cycles
|
||||||
|
# TXSR = 10 cycles
|
||||||
|
# TRAS = 6 cycles
|
||||||
|
# TRCD = 3 cycles
|
||||||
|
# TRP = 3 cycles
|
||||||
|
# TRC = 9 cycles
|
||||||
|
# TWR = 2 cycles
|
||||||
|
# 9 column, 13 row, 4 banks
|
||||||
|
# refresh equal to or less then 7.8 us for commercial/industrial rated devices
|
||||||
|
#
|
||||||
|
# Thus SDRAM_CR = 0xa6339279
|
||||||
|
|
||||||
|
mww 0xffffea08 0xa6339279
|
||||||
|
|
||||||
|
# Memory Device Type: SDRAM (low-power would be 0x1)
|
||||||
|
mww 0xffffea24 0x00000000
|
||||||
|
|
||||||
|
# Next issue a 'NOP' command through the SDRAMC_MR register followed by writing a zero value into
|
||||||
|
# the starting memory location for the SDRAM.
|
||||||
|
|
||||||
|
mww 0xffffea00 0x00000001
|
||||||
|
mww 0x20000000 0
|
||||||
|
|
||||||
|
# Issue an 'All Banks Precharge' command through the SDRAMC_MR register followed by writing a zero
|
||||||
|
# value into the starting memory location for the SDRAM.
|
||||||
|
|
||||||
|
mww 0xffffea00 0x00000002
|
||||||
|
mww 0x20000000 0
|
||||||
|
|
||||||
|
# Now issue an 'Auto-Refresh' command through the SDRAMC_MR register. Follow this operation by writing
|
||||||
|
# zero values eight times into the starting memory location for the SDRAM.
|
||||||
|
|
||||||
|
mww 0xffffea00 0x4
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
mww 0x20000000 0
|
||||||
|
|
||||||
|
# Almost done, so next issue a 'Load Mode Register' command followed by a zero value write to the
|
||||||
|
# the starting memory location for the SDRAM.
|
||||||
|
|
||||||
|
mww 0xffffea00 0x3
|
||||||
|
mww 0x20000000 0
|
||||||
|
|
||||||
|
# Signal normal mode using the SDRAMC_MR register and follow with a zero value write the starting
|
||||||
|
# memory location for the SDRAM.
|
||||||
|
|
||||||
|
mww 0xffffea00 0x0
|
||||||
|
mww 0x20000000 0
|
||||||
|
|
||||||
|
# Finally set the refresh rate to about every 7 us (7.5 ns x 924 cycles).
|
||||||
|
|
||||||
|
mww 0xffffea04 0x0000039c
|
||||||
|
}
|
||||||
|
|
||||||
|
$_TARGETNAME configure -event gdb-attach { reset init }
|
||||||
|
$_TARGETNAME configure -event reset-start {at91sam9g20_reset_start}
|
||||||
|
$_TARGETNAME configure -event reset-init {at91sam9g20_reset_init}
|
||||||
|
|
|
@ -7,6 +7,6 @@ source [find interface/stlink-dap.cfg]
|
||||||
|
|
||||||
transport select swim
|
transport select swim
|
||||||
|
|
||||||
source [find target/stm8l152.cfg]
|
source [find target/stm8l15xx8.cfg]
|
||||||
|
|
||||||
reset_config srst_only
|
reset_config srst_only
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# Cadence virtual debug interface
|
||||||
|
# Xtensa xt8 through JTAG
|
||||||
|
|
||||||
|
source [find interface/vdebug.cfg]
|
||||||
|
|
||||||
|
set CHIPNAME xt8
|
||||||
|
set CPUTAPID 0x120034e5
|
||||||
|
|
||||||
|
# vdebug select transport
|
||||||
|
transport select jtag
|
||||||
|
|
||||||
|
# JTAG reset config, frequency and reset delay
|
||||||
|
reset_config trst_and_srst
|
||||||
|
adapter speed 50000
|
||||||
|
adapter srst delay 5
|
||||||
|
|
||||||
|
# BFM hierarchical path and input clk period
|
||||||
|
vdebug bfm_path Testbench.u_vd_jtag_bfm 10ns
|
||||||
|
|
||||||
|
# DMA Memories to access backdoor, the values come from generated xtensa-core-xt8.cfg
|
||||||
|
#vdebug mem_path Testbench.Xtsubsystem.Core0.iram0.iram0.mem.dataArray 0x40000000 0x100000
|
||||||
|
#vdebug mem_path Testbench.Xtsubsystem.Core0.dram0.dram0.mem.dataArray 0x3ff00000 0x40000
|
||||||
|
|
||||||
|
# Create Xtensa target first
|
||||||
|
source [find target/xtensa.cfg]
|
||||||
|
# Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config"
|
||||||
|
source [find target/xtensa-core-xt8.cfg]
|
|
@ -23,11 +23,21 @@ if { [info exists FLASHNAME] } {
|
||||||
target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
|
target create $_TARGETNAME testee -chain-position $_CHIPNAME.tap
|
||||||
flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
|
flash bank $_FLASHNAME jtagspi 0 0 0 0 $_TARGETNAME $_JTAGSPI_IR
|
||||||
|
|
||||||
proc jtagspi_init {chain_id proxy_bit} {
|
# initialize jtagspi flash
|
||||||
|
# chain_id: identifier of pld (you can get a list with 'pld devices')
|
||||||
|
# proxy_bit: file with bitstream connecting JTAG and SPI interface in the PLD.
|
||||||
|
# release_from_pwr_down_cmd: optional, command sent to spi flash before probing.
|
||||||
|
# ex: 0xAB to release from power-dowm.
|
||||||
|
# Just omit it to not send a command.
|
||||||
|
|
||||||
|
proc jtagspi_init {chain_id proxy_bit {release_from_pwr_down_cmd -1}} {
|
||||||
# load proxy bitstream $proxy_bit and probe spi flash
|
# load proxy bitstream $proxy_bit and probe spi flash
|
||||||
global _FLASHNAME
|
global _FLASHNAME
|
||||||
pld load $chain_id $proxy_bit
|
pld load $chain_id $proxy_bit
|
||||||
reset halt
|
reset halt
|
||||||
|
if {$release_from_pwr_down_cmd != -1} {
|
||||||
|
jtagspi cmd $_FLASHNAME 0 $release_from_pwr_down_cmd
|
||||||
|
}
|
||||||
flash probe $_FLASHNAME
|
flash probe $_FLASHNAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# NXP QN908x Cortex-M4F with 128 KiB SRAM
|
||||||
|
|
||||||
|
source [find target/swj-dp.tcl]
|
||||||
|
|
||||||
|
set CHIPNAME qn908x
|
||||||
|
set CHIPSERIES qn9080
|
||||||
|
if { ![info exists WORKAREASIZE] } {
|
||||||
|
set WORKAREASIZE 0x20000
|
||||||
|
}
|
||||||
|
|
||||||
|
# SWD IDCODE (Cortex M4).
|
||||||
|
set CPUTAPID 0x2ba01477
|
||||||
|
|
||||||
|
swj_newdap $CHIPNAME cpu -irlen 4 -expected-id $CPUTAPID
|
||||||
|
dap create $CHIPNAME.dap -chain-position $CHIPNAME.cpu
|
||||||
|
|
||||||
|
set TARGETNAME $CHIPNAME.cpu
|
||||||
|
target create $TARGETNAME cortex_m -dap $CHIPNAME.dap
|
||||||
|
|
||||||
|
# SRAM is mapped at 0x04000000.
|
||||||
|
$TARGETNAME configure -work-area-phys 0x04000000 -work-area-size $WORKAREASIZE
|
||||||
|
|
||||||
|
# flash bank <name> qn908x <base> <size> 0 0 <target#> [calc_checksum]
|
||||||
|
# The base must be set as 0x01000000, and the size parameter is unused.
|
||||||
|
set FLASHNAME $CHIPNAME.flash
|
||||||
|
flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum
|
||||||
|
|
||||||
|
# We write directly to flash memory over this adapter interface. For debugging
|
||||||
|
# this could in theory be faster (the Core clock on reset is normally at 32MHz),
|
||||||
|
# but for flashing 1MHz is more reliable.
|
||||||
|
adapter speed 1000
|
||||||
|
|
||||||
|
# Delay on reset line.
|
||||||
|
adapter srst delay 200
|
||||||
|
|
||||||
|
cortex_m reset_config sysresetreq
|
|
@ -0,0 +1,74 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# script for stm32c0x family
|
||||||
|
#
|
||||||
|
# stm32c0 devices support SWD transports only.
|
||||||
|
#
|
||||||
|
|
||||||
|
source [find target/swj-dp.tcl]
|
||||||
|
source [find mem_helper.tcl]
|
||||||
|
|
||||||
|
if { [info exists CHIPNAME] } {
|
||||||
|
set _CHIPNAME $CHIPNAME
|
||||||
|
} else {
|
||||||
|
set _CHIPNAME stm32c0x
|
||||||
|
}
|
||||||
|
|
||||||
|
set _ENDIAN little
|
||||||
|
|
||||||
|
# Work-area is a space in RAM used for flash programming
|
||||||
|
# By default use 6kB
|
||||||
|
if { [info exists WORKAREASIZE] } {
|
||||||
|
set _WORKAREASIZE $WORKAREASIZE
|
||||||
|
} else {
|
||||||
|
set _WORKAREASIZE 0x1800
|
||||||
|
}
|
||||||
|
|
||||||
|
#jtag scan chain
|
||||||
|
if { [info exists CPUTAPID] } {
|
||||||
|
set _CPUTAPID $CPUTAPID
|
||||||
|
} else {
|
||||||
|
# SWD IDCODE (single drop, arm)
|
||||||
|
set _CPUTAPID 0x0bc11477
|
||||||
|
}
|
||||||
|
|
||||||
|
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||||
|
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||||
|
|
||||||
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
|
target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
|
||||||
|
|
||||||
|
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||||
|
|
||||||
|
flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
|
||||||
|
flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
|
||||||
|
|
||||||
|
# reasonable default
|
||||||
|
adapter speed 2000
|
||||||
|
|
||||||
|
adapter srst delay 100
|
||||||
|
if {[using_jtag]} {
|
||||||
|
jtag_ntrst_delay 100
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_config srst_nogate
|
||||||
|
|
||||||
|
if {![using_hla]} {
|
||||||
|
# if srst is not fitted use SYSRESETREQ to
|
||||||
|
# perform a soft reset
|
||||||
|
cortex_m reset_config sysresetreq
|
||||||
|
}
|
||||||
|
|
||||||
|
$_TARGETNAME configure -event examine-end {
|
||||||
|
# Enable DBGMCU clock
|
||||||
|
# RCC_APB1ENR |= DBGMCUEN
|
||||||
|
mmw 0x4002103C 0x08000000 0
|
||||||
|
|
||||||
|
# Enable debug during low power modes (uses more power)
|
||||||
|
# DBGMCU_CR |= DBG_STANDBY | DBG_STOP
|
||||||
|
mmw 0x40015804 0x00000006 0
|
||||||
|
|
||||||
|
# Stop watchdog counters during halt
|
||||||
|
# DBGMCU_APB1_FZ |= DBG_WDGLS_STOP | DBG_WWDG_STOP
|
||||||
|
mmw 0x40015808 0x00001800 0
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Config script for STM8L151x2
|
||||||
|
# Supported Devices:
|
||||||
|
# STM8L151C2
|
||||||
|
# STM8L151F2
|
||||||
|
# STM8L151G2
|
||||||
|
# STM8L151K2
|
||||||
|
|
||||||
|
# 1kB RAM
|
||||||
|
# Start 0x0000
|
||||||
|
# End 0x03ff
|
||||||
|
set WORKAREASIZE 1024
|
||||||
|
|
||||||
|
# 4kB Flash
|
||||||
|
set FLASHSTART 0x8000
|
||||||
|
set FLASHEND 0x8fff
|
||||||
|
|
||||||
|
# 256B EEPROM
|
||||||
|
set EEPROMSTART 0x1000
|
||||||
|
set EEPROMEND 0x10ff
|
||||||
|
|
||||||
|
set OPTIONSTART 0x4800
|
||||||
|
set OPTIONEND 0x487f
|
||||||
|
|
||||||
|
proc stm8_reset_rop {} {
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
reset halt
|
||||||
|
}
|
||||||
|
|
||||||
|
source [find target/stm8l.cfg]
|
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Config script for STM8L151x3
|
||||||
|
# Supported Devices:
|
||||||
|
# STM8L151C3
|
||||||
|
# STM8L151F3
|
||||||
|
# STM8L151G3
|
||||||
|
# STM8L151K3
|
||||||
|
|
||||||
|
# 1kB RAM
|
||||||
|
# Start 0x0000
|
||||||
|
# End 0x03ff
|
||||||
|
set WORKAREASIZE 1024
|
||||||
|
|
||||||
|
# 8kB Flash
|
||||||
|
set FLASHSTART 0x8000
|
||||||
|
set FLASHEND 0x9fff
|
||||||
|
|
||||||
|
# 256B EEPROM
|
||||||
|
set EEPROMSTART 0x1000
|
||||||
|
set EEPROMEND 0x10ff
|
||||||
|
|
||||||
|
set OPTIONSTART 0x4800
|
||||||
|
set OPTIONEND 0x487f
|
||||||
|
|
||||||
|
proc stm8_reset_rop {} {
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
reset halt
|
||||||
|
}
|
||||||
|
|
||||||
|
source [find target/stm8l.cfg]
|
|
@ -1,6 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#config script for STM8L152
|
echo 'DEPRECATED: choose between stm8l15xx4.cfg, stm8l15xx6.cfg and stm8l15xx8.cfg instead of stm8l152.cfg'
|
||||||
|
echo ' using stm8l152.cfg for backwards compatability'
|
||||||
|
|
||||||
set EEPROMSTART 0x1000
|
set EEPROMSTART 0x1000
|
||||||
set EEPROMEND 0x13ff
|
set EEPROMEND 0x13ff
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Config script for STM8L151x4/STM8L152x4
|
||||||
|
# Supported Devices:
|
||||||
|
# STM8L151C4
|
||||||
|
# STM8L151G4
|
||||||
|
# STM8L151K4
|
||||||
|
# STM8L152C4
|
||||||
|
# STM8L152K4
|
||||||
|
|
||||||
|
# 2kB RAM
|
||||||
|
# Start 0x0000
|
||||||
|
# End 0x07ff
|
||||||
|
set WORKAREASIZE 2048
|
||||||
|
|
||||||
|
# 16kB Flash
|
||||||
|
set FLASHSTART 0x8000
|
||||||
|
set FLASHEND 0xbfff
|
||||||
|
|
||||||
|
# 1kB EEPROM
|
||||||
|
set EEPROMSTART 0x1000
|
||||||
|
set EEPROMEND 0x13ff
|
||||||
|
|
||||||
|
set OPTIONSTART 0x4800
|
||||||
|
set OPTIONEND 0x48ff
|
||||||
|
|
||||||
|
proc stm8_reset_rop {} {
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
reset halt
|
||||||
|
}
|
||||||
|
|
||||||
|
source [find target/stm8l.cfg]
|
|
@ -0,0 +1,35 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Config script for STM8L151x6/STM8L152x6
|
||||||
|
# Supported Devices:
|
||||||
|
# STM8L151C6
|
||||||
|
# STM8L151G6
|
||||||
|
# STM8L151K6
|
||||||
|
# STM8L151R6
|
||||||
|
# STM8L152C6
|
||||||
|
# STM8L152K6
|
||||||
|
# STM8L152R6
|
||||||
|
|
||||||
|
# 2kB RAM
|
||||||
|
# Start 0x0000
|
||||||
|
# End 0x07ff
|
||||||
|
set WORKAREASIZE 2048
|
||||||
|
|
||||||
|
# 32kB Flash
|
||||||
|
set FLASHSTART 0x8000
|
||||||
|
set FLASHEND 0xffff
|
||||||
|
|
||||||
|
# 1kB EEPROM
|
||||||
|
set EEPROMSTART 0x1000
|
||||||
|
set EEPROMEND 0x13ff
|
||||||
|
|
||||||
|
set OPTIONSTART 0x4800
|
||||||
|
set OPTIONEND 0x48ff
|
||||||
|
|
||||||
|
proc stm8_reset_rop {} {
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
reset halt
|
||||||
|
}
|
||||||
|
|
||||||
|
source [find target/stm8l.cfg]
|
|
@ -0,0 +1,35 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# Config script for STM8L151x8/STM8L152x8
|
||||||
|
# Supported Devices:
|
||||||
|
# STM8L151C8
|
||||||
|
# STM8L151M8
|
||||||
|
# STM8L151R8
|
||||||
|
# STM8L152C8
|
||||||
|
# STM8L152K8
|
||||||
|
# STM8L152M8
|
||||||
|
# STM8L152R8
|
||||||
|
|
||||||
|
# 4kB RAM
|
||||||
|
# Start 0x0000
|
||||||
|
# End 0x0fff
|
||||||
|
set WORKAREASIZE 4096
|
||||||
|
|
||||||
|
# 64kB Flash
|
||||||
|
set FLASHSTART 0x08000
|
||||||
|
set FLASHEND 0x17fff
|
||||||
|
|
||||||
|
# 2kB EEPROM
|
||||||
|
set EEPROMSTART 0x1000
|
||||||
|
set EEPROMEND 0x17ff
|
||||||
|
|
||||||
|
set OPTIONSTART 0x4800
|
||||||
|
set OPTIONEND 0x48ff
|
||||||
|
|
||||||
|
proc stm8_reset_rop {} {
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
mwb 0x4800 0xaa
|
||||||
|
reset halt
|
||||||
|
}
|
||||||
|
|
||||||
|
source [find target/stm8l.cfg]
|
|
@ -22,7 +22,7 @@ source [find target/icepick.cfg]
|
||||||
if { [info exists DAP_TAPID] } {
|
if { [info exists DAP_TAPID] } {
|
||||||
set _DAP_TAPID $DAP_TAPID
|
set _DAP_TAPID $DAP_TAPID
|
||||||
}
|
}
|
||||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable
|
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable -ignore-version
|
||||||
jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
|
jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
|
||||||
|
|
||||||
# ICEpick-C (JTAG route controller)
|
# ICEpick-C (JTAG route controller)
|
||||||
|
@ -35,10 +35,7 @@ set _JRC_TAPID2 0x0B7B302F
|
||||||
set _JRC_TAPID3 0x0B95502F
|
set _JRC_TAPID3 0x0B95502F
|
||||||
set _JRC_TAPID4 0x0B97102F
|
set _JRC_TAPID4 0x0B97102F
|
||||||
set _JRC_TAPID5 0x0D8A002F
|
set _JRC_TAPID5 0x0D8A002F
|
||||||
set _JRC_TAPID6 0x2B8A002F
|
set _JRC_TAPID6 0x0B8A002F
|
||||||
set _JRC_TAPID7 0x2D8A002F
|
|
||||||
set _JRC_TAPID8 0x3B8A002F
|
|
||||||
set _JRC_TAPID9 0x3D8A002F
|
|
||||||
|
|
||||||
|
|
||||||
jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \
|
jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \
|
||||||
|
@ -48,9 +45,6 @@ jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f \
|
||||||
-expected-id $_JRC_TAPID4 \
|
-expected-id $_JRC_TAPID4 \
|
||||||
-expected-id $_JRC_TAPID5 \
|
-expected-id $_JRC_TAPID5 \
|
||||||
-expected-id $_JRC_TAPID6 \
|
-expected-id $_JRC_TAPID6 \
|
||||||
-expected-id $_JRC_TAPID7 \
|
|
||||||
-expected-id $_JRC_TAPID8 \
|
|
||||||
-expected-id $_JRC_TAPID9 \
|
|
||||||
-ignore-version
|
-ignore-version
|
||||||
jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu"
|
jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu"
|
||||||
jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100"
|
jtag configure $_CHIPNAME.jrc -event post-reset "runtest 100"
|
||||||
|
@ -60,7 +54,7 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||||
# Cortex-R4 target
|
# Cortex-R4 target
|
||||||
set _TARGETNAME $_CHIPNAME.cpu
|
set _TARGETNAME $_CHIPNAME.cpu
|
||||||
target create $_TARGETNAME cortex_r4 -endian $_ENDIAN \
|
target create $_TARGETNAME cortex_r4 -endian $_ENDIAN \
|
||||||
-dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x00001003
|
-dap $_CHIPNAME.dap -coreid 0 -dbgbase 0x80001000
|
||||||
|
|
||||||
# TMS570 uses quirky BE-32 mode
|
# TMS570 uses quirky BE-32 mode
|
||||||
$_CHIPNAME.dap ti_be_32_quirks 1
|
$_CHIPNAME.dap ti_be_32_quirks 1
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
set DAP_TAPID 0x0B95A02F
|
||||||
|
set JRC_TAPID 0x0B95A02F
|
||||||
|
|
||||||
|
source [find target/ti_tms570.cfg]
|
|
@ -1,27 +0,0 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
# Cadence virtual debug interface
|
|
||||||
# for Palladium emulation systems
|
|
||||||
#
|
|
||||||
|
|
||||||
# TODO: Enable backdoor memory access
|
|
||||||
# set _MEMSTART 0x00000000
|
|
||||||
# set _MEMSIZE 0x100000
|
|
||||||
|
|
||||||
# BFM hierarchical path and input clk period
|
|
||||||
vdebug bfm_path dut_top.JTAG 10ns
|
|
||||||
# DMA Memories to access backdoor (up to 4)
|
|
||||||
# vdebug mem_path tbench.u_mcu.u_sys.u_itcm_ram.Mem $_MEMSTART $_MEMSIZE
|
|
||||||
|
|
||||||
# Create Xtensa target first
|
|
||||||
source [find target/xtensa.cfg]
|
|
||||||
|
|
||||||
# Configure Xtensa core parameters next
|
|
||||||
# Generate [xtensa-core-XXX.cfg] via "xt-gdb --dump-oocd-config"
|
|
||||||
|
|
||||||
# register target
|
|
||||||
proc vdebug_examine_end {} {
|
|
||||||
# vdebug register_target
|
|
||||||
}
|
|
||||||
|
|
||||||
# Default hooks
|
|
||||||
$_TARGETNAME configure -event examine-end { vdebug_examine_end }
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
# OpenOCD configuration file for Xtensa xt8 target
|
||||||
|
|
||||||
|
# Core definition and ABI
|
||||||
|
xtensa xtdef LX
|
||||||
|
xtensa xtopt arnum 32
|
||||||
|
xtensa xtopt windowed 1
|
||||||
|
|
||||||
|
|
||||||
|
# Exception/Interrupt Options
|
||||||
|
xtensa xtopt exceptions 1
|
||||||
|
xtensa xtopt hipriints 1
|
||||||
|
xtensa xtopt intlevels 3
|
||||||
|
xtensa xtopt excmlevel 1
|
||||||
|
|
||||||
|
|
||||||
|
# Cache Options
|
||||||
|
xtensa xtmem icache 16 1024 1
|
||||||
|
xtensa xtmem dcache 16 1024 1 1
|
||||||
|
|
||||||
|
|
||||||
|
# Memory Options
|
||||||
|
xtensa xtmem iram 0x40000000 1048576
|
||||||
|
xtensa xtmem dram 0x3ff00000 262144
|
||||||
|
xtensa xtmem srom 0x50000000 131072
|
||||||
|
xtensa xtmem sram 0x60000000 4194304
|
||||||
|
|
||||||
|
|
||||||
|
# Memory Protection/Translation Options
|
||||||
|
|
||||||
|
|
||||||
|
# Debug Options
|
||||||
|
xtensa xtopt debuglevel 3
|
||||||
|
xtensa xtopt ibreaknum 2
|
||||||
|
xtensa xtopt dbreaknum 2
|
||||||
|
|
||||||
|
|
||||||
|
# Core Registers
|
||||||
|
xtensa xtregs 127
|
||||||
|
xtensa xtreg a0 0x0000
|
||||||
|
xtensa xtreg a1 0x0001
|
||||||
|
xtensa xtreg a2 0x0002
|
||||||
|
xtensa xtreg a3 0x0003
|
||||||
|
xtensa xtreg a4 0x0004
|
||||||
|
xtensa xtreg a5 0x0005
|
||||||
|
xtensa xtreg a6 0x0006
|
||||||
|
xtensa xtreg a7 0x0007
|
||||||
|
xtensa xtreg a8 0x0008
|
||||||
|
xtensa xtreg a9 0x0009
|
||||||
|
xtensa xtreg a10 0x000a
|
||||||
|
xtensa xtreg a11 0x000b
|
||||||
|
xtensa xtreg a12 0x000c
|
||||||
|
xtensa xtreg a13 0x000d
|
||||||
|
xtensa xtreg a14 0x000e
|
||||||
|
xtensa xtreg a15 0x000f
|
||||||
|
xtensa xtreg pc 0x0020
|
||||||
|
xtensa xtreg ar0 0x0100
|
||||||
|
xtensa xtreg ar1 0x0101
|
||||||
|
xtensa xtreg ar2 0x0102
|
||||||
|
xtensa xtreg ar3 0x0103
|
||||||
|
xtensa xtreg ar4 0x0104
|
||||||
|
xtensa xtreg ar5 0x0105
|
||||||
|
xtensa xtreg ar6 0x0106
|
||||||
|
xtensa xtreg ar7 0x0107
|
||||||
|
xtensa xtreg ar8 0x0108
|
||||||
|
xtensa xtreg ar9 0x0109
|
||||||
|
xtensa xtreg ar10 0x010a
|
||||||
|
xtensa xtreg ar11 0x010b
|
||||||
|
xtensa xtreg ar12 0x010c
|
||||||
|
xtensa xtreg ar13 0x010d
|
||||||
|
xtensa xtreg ar14 0x010e
|
||||||
|
xtensa xtreg ar15 0x010f
|
||||||
|
xtensa xtreg ar16 0x0110
|
||||||
|
xtensa xtreg ar17 0x0111
|
||||||
|
xtensa xtreg ar18 0x0112
|
||||||
|
xtensa xtreg ar19 0x0113
|
||||||
|
xtensa xtreg ar20 0x0114
|
||||||
|
xtensa xtreg ar21 0x0115
|
||||||
|
xtensa xtreg ar22 0x0116
|
||||||
|
xtensa xtreg ar23 0x0117
|
||||||
|
xtensa xtreg ar24 0x0118
|
||||||
|
xtensa xtreg ar25 0x0119
|
||||||
|
xtensa xtreg ar26 0x011a
|
||||||
|
xtensa xtreg ar27 0x011b
|
||||||
|
xtensa xtreg ar28 0x011c
|
||||||
|
xtensa xtreg ar29 0x011d
|
||||||
|
xtensa xtreg ar30 0x011e
|
||||||
|
xtensa xtreg ar31 0x011f
|
||||||
|
xtensa xtreg lbeg 0x0200
|
||||||
|
xtensa xtreg lend 0x0201
|
||||||
|
xtensa xtreg lcount 0x0202
|
||||||
|
xtensa xtreg sar 0x0203
|
||||||
|
xtensa xtreg windowbase 0x0248
|
||||||
|
xtensa xtreg windowstart 0x0249
|
||||||
|
xtensa xtreg configid0 0x02b0
|
||||||
|
xtensa xtreg configid1 0x02d0
|
||||||
|
xtensa xtreg ps 0x02e6
|
||||||
|
xtensa xtreg expstate 0x03e6
|
||||||
|
xtensa xtreg mmid 0x0259
|
||||||
|
xtensa xtreg ibreakenable 0x0260
|
||||||
|
xtensa xtreg ddr 0x0268
|
||||||
|
xtensa xtreg ibreaka0 0x0280
|
||||||
|
xtensa xtreg ibreaka1 0x0281
|
||||||
|
xtensa xtreg dbreaka0 0x0290
|
||||||
|
xtensa xtreg dbreaka1 0x0291
|
||||||
|
xtensa xtreg dbreakc0 0x02a0
|
||||||
|
xtensa xtreg dbreakc1 0x02a1
|
||||||
|
xtensa xtreg epc1 0x02b1
|
||||||
|
xtensa xtreg epc2 0x02b2
|
||||||
|
xtensa xtreg epc3 0x02b3
|
||||||
|
xtensa xtreg depc 0x02c0
|
||||||
|
xtensa xtreg eps2 0x02c2
|
||||||
|
xtensa xtreg eps3 0x02c3
|
||||||
|
xtensa xtreg excsave1 0x02d1
|
||||||
|
xtensa xtreg excsave2 0x02d2
|
||||||
|
xtensa xtreg excsave3 0x02d3
|
||||||
|
xtensa xtreg interrupt 0x02e2
|
||||||
|
xtensa xtreg intset 0x02e2
|
||||||
|
xtensa xtreg intclear 0x02e3
|
||||||
|
xtensa xtreg intenable 0x02e4
|
||||||
|
xtensa xtreg exccause 0x02e8
|
||||||
|
xtensa xtreg debugcause 0x02e9
|
||||||
|
xtensa xtreg ccount 0x02ea
|
||||||
|
xtensa xtreg icount 0x02ec
|
||||||
|
xtensa xtreg icountlevel 0x02ed
|
||||||
|
xtensa xtreg excvaddr 0x02ee
|
||||||
|
xtensa xtreg ccompare0 0x02f0
|
||||||
|
xtensa xtreg ccompare1 0x02f1
|
||||||
|
xtensa xtreg pwrctl 0x200f
|
||||||
|
xtensa xtreg pwrstat 0x2010
|
||||||
|
xtensa xtreg eristat 0x2011
|
||||||
|
xtensa xtreg cs_itctrl 0x2012
|
||||||
|
xtensa xtreg cs_claimset 0x2013
|
||||||
|
xtensa xtreg cs_claimclr 0x2014
|
||||||
|
xtensa xtreg cs_lockaccess 0x2015
|
||||||
|
xtensa xtreg cs_lockstatus 0x2016
|
||||||
|
xtensa xtreg cs_authstatus 0x2017
|
||||||
|
xtensa xtreg fault_info 0x2026
|
||||||
|
xtensa xtreg trax_id 0x2027
|
||||||
|
xtensa xtreg trax_control 0x2028
|
||||||
|
xtensa xtreg trax_status 0x2029
|
||||||
|
xtensa xtreg trax_data 0x202a
|
||||||
|
xtensa xtreg trax_address 0x202b
|
||||||
|
xtensa xtreg trax_pctrigger 0x202c
|
||||||
|
xtensa xtreg trax_pcmatch 0x202d
|
||||||
|
xtensa xtreg trax_delay 0x202e
|
||||||
|
xtensa xtreg trax_memstart 0x202f
|
||||||
|
xtensa xtreg trax_memend 0x2030
|
||||||
|
xtensa xtreg pmg 0x203e
|
||||||
|
xtensa xtreg pmpc 0x203f
|
||||||
|
xtensa xtreg pm0 0x2040
|
||||||
|
xtensa xtreg pm1 0x2041
|
||||||
|
xtensa xtreg pmctrl0 0x2042
|
||||||
|
xtensa xtreg pmctrl1 0x2043
|
||||||
|
xtensa xtreg pmstat0 0x2044
|
||||||
|
xtensa xtreg pmstat1 0x2045
|
||||||
|
xtensa xtreg ocdid 0x2046
|
||||||
|
xtensa xtreg ocd_dcrclr 0x2047
|
||||||
|
xtensa xtreg ocd_dcrset 0x2048
|
||||||
|
xtensa xtreg ocd_dsr 0x2049
|
||||||
|
xtensa xtreg psintlevel 0x2003
|
||||||
|
xtensa xtreg psum 0x2004
|
||||||
|
xtensa xtreg pswoe 0x2005
|
||||||
|
xtensa xtreg psexcm 0x2006
|
||||||
|
xtensa xtreg pscallinc 0x2007
|
||||||
|
xtensa xtreg psowb 0x2008
|
Loading…
Reference in New Issue