aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2023-10-23 12:29:21 -0700
committerTim Newsome <tim@sifive.com>2023-10-23 12:29:21 -0700
commitaf08d582b55f8c8e326b422a46c63909bca6009c (patch)
tree86e13b5da9ce8b8c02e1ceec6ec066a9b9da27f0
parent132e3faf1d47f4a2ca7d01aa0191c59f5e1816c5 (diff)
parente17fe4db0f256ee4fb97dcfd6b9f7f55c966b190 (diff)
downloadriscv-openocd-af08d582b55f8c8e326b422a46c63909bca6009c.zip
riscv-openocd-af08d582b55f8c8e326b422a46c63909bca6009c.tar.gz
riscv-openocd-af08d582b55f8c8e326b422a46c63909bca6009c.tar.bz2
Merge commit 'e17fe4db0f256ee4fb97dcfd6b9f7f55c966b190' into from_upstream
Conflicts: src/flash/nor/drivers.c src/target/riscv/riscv.c Change-Id: Ide3eded7e0d5b0b446bfd0873a32c00cc9f128bd
-rw-r--r--contrib/loaders/flash/rsl10/rom_launcher.S2
-rw-r--r--doc/openocd.texi119
-rw-r--r--src/flash/nand/driver.c20
-rw-r--r--src/flash/nand/driver.h15
-rw-r--r--src/flash/nand/lpc32xx.c2
-rw-r--r--src/flash/nor/at91sam3.c2
-rw-r--r--src/flash/nor/at91sam4.c2
-rw-r--r--src/flash/nor/at91samd.c20
-rw-r--r--src/flash/nor/atsame5.c2
-rw-r--r--src/flash/nor/atsamv.c2
-rw-r--r--src/flash/nor/driver.h71
-rw-r--r--src/flash/nor/drivers.c72
-rw-r--r--src/flash/nor/msp432.c2
-rw-r--r--src/flash/nor/numicro.c4
-rw-r--r--src/flash/nor/rp2040.c2
-rw-r--r--src/flash/nor/rsl10.c2
-rw-r--r--src/flash/nor/stellaris.c2
-rw-r--r--src/flash/nor/stmqspi.c2
-rw-r--r--src/flash/nor/swm050.c2
-rw-r--r--src/helper/command.c2
-rw-r--r--src/helper/jep106.c2
-rw-r--r--src/helper/options.c12
-rw-r--r--src/helper/util.c1
-rw-r--r--src/jtag/drivers/arm-jtag-ew.c2
-rw-r--r--src/jtag/drivers/at91rm9200.c8
-rw-r--r--src/jtag/drivers/bcm2835gpio.c2
-rw-r--r--src/jtag/drivers/ep93xx.c4
-rw-r--r--src/jtag/drivers/ft232r.c12
-rw-r--r--src/jtag/drivers/ftdi.c11
-rw-r--r--src/jtag/drivers/mpsse.c14
-rw-r--r--src/jtag/drivers/opendous.c2
-rw-r--r--src/jtag/drivers/parport.c6
-rw-r--r--src/jtag/drivers/rlink.c2
-rw-r--r--src/jtag/drivers/stlink_usb.c2
-rw-r--r--src/jtag/drivers/sysfsgpio.c2
-rw-r--r--src/jtag/drivers/ti_icdi_usb.c6
-rw-r--r--src/jtag/drivers/usbprog.c2
-rw-r--r--src/jtag/drivers/vdebug.c4
-rw-r--r--src/jtag/drivers/xds110.c10
-rw-r--r--src/jtag/tcl.c227
-rw-r--r--src/pld/Makefile.am17
-rw-r--r--src/pld/certus.c233
-rw-r--r--src/pld/certus.h18
-rw-r--r--src/pld/ecp2_3.c251
-rw-r--r--src/pld/ecp2_3.h19
-rw-r--r--src/pld/ecp5.c207
-rw-r--r--src/pld/ecp5.h18
-rw-r--r--src/pld/efinix.c218
-rw-r--r--src/pld/gatemate.c243
-rw-r--r--src/pld/gowin.c581
-rw-r--r--src/pld/intel.c474
-rw-r--r--src/pld/lattice.c529
-rw-r--r--src/pld/lattice.h36
-rw-r--r--src/pld/lattice_bit.c105
-rw-r--r--src/pld/lattice_bit.h33
-rw-r--r--src/pld/lattice_cmd.h19
-rw-r--r--src/pld/pld.c26
-rw-r--r--src/pld/pld.h7
-rw-r--r--src/pld/raw_bit.c55
-rw-r--r--src/pld/raw_bit.h21
-rw-r--r--src/pld/virtex2.c121
-rw-r--r--src/pld/xilinx_bit.c17
-rw-r--r--src/rtos/chibios.c8
-rw-r--r--src/rtos/linux.c2
-rw-r--r--src/rtos/rtos.c16
-rw-r--r--src/rtos/rtos.h15
-rw-r--r--src/server/gdb_server.c1
-rw-r--r--src/server/ipdbg.c23
-rw-r--r--src/target/aarch64.c107
-rw-r--r--src/target/arm9tdmi.c2
-rw-r--r--src/target/armv8.c13
-rw-r--r--src/target/armv8.h1
-rw-r--r--src/target/armv8_dpm.c7
-rw-r--r--src/target/cortex_a.c17
-rw-r--r--src/target/cortex_m.c9
-rw-r--r--src/target/dsp563xx_once.c10
-rw-r--r--src/target/espressif/Makefile.am4
-rw-r--r--src/target/espressif/esp32.c5
-rw-r--r--src/target/espressif/esp32_apptrace.c1372
-rw-r--r--src/target/espressif/esp32_apptrace.h126
-rw-r--r--src/target/espressif/esp32s2.c5
-rw-r--r--src/target/espressif/esp32s3.c5
-rw-r--r--src/target/espressif/esp_xtensa.c2
-rw-r--r--src/target/espressif/esp_xtensa.h2
-rw-r--r--src/target/espressif/esp_xtensa_apptrace.c499
-rw-r--r--src/target/espressif/esp_xtensa_apptrace.h37
-rw-r--r--src/target/etm.c2
-rw-r--r--src/target/lakemont.c174
-rw-r--r--src/target/mips64_pracc.h2
-rw-r--r--src/target/rtt.c1
-rw-r--r--src/target/stm8.c4
-rw-r--r--src/target/target.c177
-rw-r--r--src/target/target.h5
-rw-r--r--src/target/target_type.h39
-rw-r--r--src/target/xtensa/xtensa.c4
-rw-r--r--tcl/board/bemicro_cycloneiii.cfg20
-rw-r--r--tcl/board/certuspro_evaluation.cfg14
-rw-r--r--tcl/board/ecp5_evaluation.cfg19
-rw-r--r--tcl/board/gatemate_eval.cfg16
-rw-r--r--tcl/board/gowin_runber.cfg19
-rw-r--r--tcl/board/trion_t20_bga256.cfg24
-rw-r--r--tcl/cpld/altera-5m570z-cpld.cfg13
-rw-r--r--tcl/cpld/altera-epm240.cfg24
-rw-r--r--tcl/cpld/altera-max10.cfg30
-rw-r--r--tcl/cpld/altera-maxii.cfg21
-rw-r--r--tcl/cpld/altera-maxv.cfg19
-rw-r--r--tcl/fpga/altera-10m50.cfg27
-rw-r--r--tcl/fpga/altera-arriaii.cfg31
-rw-r--r--tcl/fpga/altera-cyclone10.cfg34
-rw-r--r--tcl/fpga/altera-cycloneiii.cfg35
-rw-r--r--tcl/fpga/altera-cycloneiv.cfg41
-rw-r--r--tcl/fpga/altera-cyclonev.cfg47
-rw-r--r--tcl/fpga/altera-ep3c10.cfg11
-rw-r--r--tcl/fpga/efinix_titanium.cfg23
-rw-r--r--tcl/fpga/efinix_trion.cfg17
-rw-r--r--tcl/fpga/gatemate.cfg16
-rw-r--r--tcl/fpga/gowin_gw1n.cfg29
-rw-r--r--tcl/fpga/lattice_certus.cfg18
-rw-r--r--tcl/fpga/lattice_certuspro.cfg18
-rw-r--r--tcl/fpga/lattice_ecp2.cfg31
-rw-r--r--tcl/fpga/lattice_ecp3.cfg22
-rw-r--r--tcl/fpga/lattice_ecp5.cfg2
-rw-r--r--tcl/target/renesas_rcar_gen3.cfg21
123 files changed, 6575 insertions, 689 deletions
diff --git a/contrib/loaders/flash/rsl10/rom_launcher.S b/contrib/loaders/flash/rsl10/rom_launcher.S
index 70f000e..aafedfb 100644
--- a/contrib/loaders/flash/rsl10/rom_launcher.S
+++ b/contrib/loaders/flash/rsl10/rom_launcher.S
@@ -21,7 +21,7 @@
.global _start
_start:
launch_program_in_rom:
- // variables are already set, addres to jump is in r3
+ // variables are already set, address to jump is in r3
blx r3
exit:
// Wait for OpenOCD
diff --git a/doc/openocd.texi b/doc/openocd.texi
index eb9f92f..7e9eb20 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8519,13 +8519,90 @@ openocd -f board/digilent_zedboard.cfg -c "init" \
@end example
-
@deffn {Command} {virtex2 read_stat} num
Reads and displays the Virtex-II status register (STAT)
for FPGA @var{num}.
@end deffn
@end deffn
+
+
+@deffn {FPGA Driver} {lattice} [family]
+The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro by Lattice are supported.
+This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register.
+
+The option @option{family} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices).
+
+@deffn {Command} {lattice read_status} num
+Reads and displays the status register
+for FPGA @var{num}.
+@end deffn
+
+@deffn {Command} {lattice read_user} num
+Reads and displays the user register
+for FPGA @var{num}.
+@end deffn
+
+@deffn {Command} {lattice write_user} num val
+Writes the user register.
+for FPGA @var{num} with value @var{val}.
+@end deffn
+
+@deffn {Command} {lattice set_preload} num length
+Set the length of the register for the preload. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices).
+The load command for the FPGA @var{num} will use a length for the preload of @var{length}.
+@end deffn
+@end deffn
+
+
+@deffn {FPGA Driver} {efinix}
+Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration.
+This driver can be used to load the bitstream into the FPGA.
+@end deffn
+
+
+@deffn {FPGA Driver} {intel} [@option{family}]
+This driver can be used to load the bitstream into Intel (former Altera) FPGAs.
+The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported.
+@c Arria V and Arria 10, MAX II, MAX V, MAX10)
+
+The option @option{family} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}.
+This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families).
+
+As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated
+from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|}
+
+Defines a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}:
+@example
+pld device intel cycloneiii.tap cycloneiii
+@end example
+
+@deffn {Command} {intel set_bscan} num len
+Set boundary scan register length of FPGA @var{num} to @var{len}. This is needed because the
+length can vary between chips with the same JTAG ID.
+@end deffn
+
+@deffn {Command} {intel set_check_pos} num pos
+Selects the position @var{pos} in the boundary-scan register. The bit at this
+position is checked after loading the bitstream and must be '1', which is the case when no error occurred.
+With a value of -1 for @var{pos} the check will be omitted.
+@end deffn
+@end deffn
+
+
+@deffn {FPGA Driver} {gowin}
+This driver can be used to load the bitstream into FPGAs from Gowin.
+It is possible to program the SRAM. Programming the flash is not supported.
+The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are supported.
+@end deffn
+
+
+@deffn {FPGA Driver} {gatemate}
+This driver can be used to load the bitstream into GateMate FPGAs form CologneChip.
+The files @verb{|.bit|} and @verb{|.cfg|} both generated by p_r tool from CologneChip are supported.
+@end deffn
+
+
@node General Commands
@chapter General Commands
@cindex commands
@@ -11370,6 +11447,46 @@ Stop current trace as started by the tracestart command.
Dump trace memory to a file.
@end deffn
+@section Espressif Specific Commands
+
+@deffn {Command} {esp apptrace} (start <destination> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+Starts
+@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}.
+Data will be stored to specified destination. Available destinations are:
+@itemize @bullet
+@item @code{file://<outfile>} - Save trace logs into file.
+@item @code{tcp://<host>:<port>} - Send trace logs to tcp port on specified host. OpenOCD will act as a tcp client.
+@item @code{con:} - Print trace logs to the stdout.
+@end itemize
+Other parameters will be same for each destination.
+@itemize @bullet
+@item @code{poll_period} - trace data polling period in ms.
+@item @code{trace_size} - maximum trace data size.
+Tracing will be stopped automatically when that amount is reached.
+Use "-1" to disable the limitation.
+@item @code{stop_tmo} - Data reception timeout in ms.
+Tracing will be stopped automatically when no data is received within that period.
+@item @code{wait4halt} - if non-zero then wait for target to be halted before tracing start.
+@item @code{skip_size} - amount of tracing data to be skipped before writing it to destination.
+@end itemize
+@end deffn
+
+@deffn {Command} {esp apptrace} (stop)
+Stops tracing started with above command.
+@end deffn
+
+@deffn {Command} {esp apptrace} (status)
+Requests ongoing tracing status.
+@end deffn
+
+@deffn {Command} {esp apptrace} (dump file://<outfile>)
+Dumps tracing data from target buffer. It can be useful to dump the latest data
+buffered on target for post-mortem analysis. For example when target starts tracing automatically
+w/o OpenOCD command and keeps only the latest data window which fit into the buffer.
+@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}.
+Data will be stored to specified destination.
+@end deffn
+
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support
diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c
index 02e5c09..ce79e13 100644
--- a/src/flash/nand/driver.c
+++ b/src/flash/nand/driver.c
@@ -13,25 +13,6 @@
#include "core.h"
#include "driver.h"
-/* NAND flash controller
- */
-extern struct nand_flash_controller nonce_nand_controller;
-extern struct nand_flash_controller davinci_nand_controller;
-extern struct nand_flash_controller lpc3180_nand_controller;
-extern struct nand_flash_controller lpc32xx_nand_controller;
-extern struct nand_flash_controller orion_nand_controller;
-extern struct nand_flash_controller s3c2410_nand_controller;
-extern struct nand_flash_controller s3c2412_nand_controller;
-extern struct nand_flash_controller s3c2440_nand_controller;
-extern struct nand_flash_controller s3c2443_nand_controller;
-extern struct nand_flash_controller s3c6400_nand_controller;
-extern struct nand_flash_controller mxc_nand_flash_controller;
-extern struct nand_flash_controller imx31_nand_flash_controller;
-extern struct nand_flash_controller at91sam9_nand_controller;
-extern struct nand_flash_controller nuc910_nand_controller;
-
-/* extern struct nand_flash_controller boundary_scan_nand_controller; */
-
static struct nand_flash_controller *nand_flash_controllers[] = {
&nonce_nand_controller,
&davinci_nand_controller,
@@ -47,7 +28,6 @@ static struct nand_flash_controller *nand_flash_controllers[] = {
&imx31_nand_flash_controller,
&at91sam9_nand_controller,
&nuc910_nand_controller,
-/* &boundary_scan_nand_controller, */
NULL
};
diff --git a/src/flash/nand/driver.h b/src/flash/nand/driver.h
index a874cc8..4e84f10 100644
--- a/src/flash/nand/driver.h
+++ b/src/flash/nand/driver.h
@@ -89,4 +89,19 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *);
*/
int nand_driver_walk(nand_driver_walker_t f, void *x);
+extern struct nand_flash_controller at91sam9_nand_controller;
+extern struct nand_flash_controller davinci_nand_controller;
+extern struct nand_flash_controller imx31_nand_flash_controller;
+extern struct nand_flash_controller lpc3180_nand_controller;
+extern struct nand_flash_controller lpc32xx_nand_controller;
+extern struct nand_flash_controller mxc_nand_flash_controller;
+extern struct nand_flash_controller nonce_nand_controller;
+extern struct nand_flash_controller nuc910_nand_controller;
+extern struct nand_flash_controller orion_nand_controller;
+extern struct nand_flash_controller s3c2410_nand_controller;
+extern struct nand_flash_controller s3c2412_nand_controller;
+extern struct nand_flash_controller s3c2440_nand_controller;
+extern struct nand_flash_controller s3c2443_nand_controller;
+extern struct nand_flash_controller s3c6400_nand_controller;
+
#endif /* OPENOCD_FLASH_NAND_DRIVER_H */
diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c
index 2c578d1..f8b59b3 100644
--- a/src/flash/nand/lpc32xx.c
+++ b/src/flash/nand/lpc32xx.c
@@ -1029,7 +1029,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand,
LOG_DEBUG("SLC write page %" PRIx32 " data=%d, oob=%d, "
"data_size=%" PRIu32 ", oob_size=%" PRIu32,
- page, data != 0, oob != 0, data_size, oob_size);
+ page, !!data, !!oob, data_size, oob_size);
target_mem_base = pworking_area->address;
/*
diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c
index fb6d98b..b1cb8f1 100644
--- a/src/flash/nor/at91sam3.c
+++ b/src/flash/nor/at91sam3.c
@@ -67,8 +67,6 @@
#define OFFSET_EFC_FSR 8
#define OFFSET_EFC_FRR 12
-extern const struct flash_driver at91sam3_flash;
-
static float _tomhz(uint32_t freq_hz)
{
float f;
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index 6b94373..6212753 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -62,8 +62,6 @@
#define OFFSET_EFC_FSR 8
#define OFFSET_EFC_FRR 12
-extern const struct flash_driver at91sam4_flash;
-
static float _tomhz(uint32_t freq_hz)
{
float f;
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index 416f077..36298f1 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -78,7 +78,7 @@
#define SAMD_GET_DEVSEL(id) (id & 0xFF)
/* Bits to mask out lockbits in user row */
-#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF)
+#define NVMUSERROW_LOCKBIT_MASK 0x0000FFFFFFFFFFFFULL
struct samd_part {
uint8_t id;
@@ -316,31 +316,31 @@ struct samd_family {
static const struct samd_family samd_families[] = {
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20,
samd20_parts, ARRAY_SIZE(samd20_parts),
- (uint64_t)0xFFFF01FFFE01FF77 },
+ 0xFFFF01FFFE01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
samd21_parts, ARRAY_SIZE(samd21_parts),
- (uint64_t)0xFFFF01FFFE01FF77 },
+ 0xFFFF01FFFE01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09,
samd09_parts, ARRAY_SIZE(samd09_parts),
- (uint64_t)0xFFFF01FFFE01FF77 },
+ 0xFFFF01FFFE01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10,
samd10_parts, ARRAY_SIZE(samd10_parts),
- (uint64_t)0xFFFF01FFFE01FF77 },
+ 0xFFFF01FFFE01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11,
samd11_parts, ARRAY_SIZE(samd11_parts),
- (uint64_t)0xFFFF01FFFE01FF77 },
+ 0xFFFF01FFFE01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21,
saml21_parts, ARRAY_SIZE(saml21_parts),
- (uint64_t)0xFFFF03FFFC01FF77 },
+ 0xFFFF03FFFC01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22,
saml22_parts, ARRAY_SIZE(saml22_parts),
- (uint64_t)0xFFFF03FFFC01FF77 },
+ 0xFFFF03FFFC01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20,
samc20_parts, ARRAY_SIZE(samc20_parts),
- (uint64_t)0xFFFF03FFFC01FF77 },
+ 0xFFFF03FFFC01FF77ULL },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21,
samc21_parts, ARRAY_SIZE(samc21_parts),
- (uint64_t)0xFFFF03FFFC01FF77 },
+ 0xFFFF03FFFC01FF77ULL },
};
struct samd_info {
diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c
index fdd610f..c590081 100644
--- a/src/flash/nor/atsame5.c
+++ b/src/flash/nor/atsame5.c
@@ -93,7 +93,7 @@
#define SAMD_GET_DEVSEL(id) (id & 0xFF)
/* Bits to mask user row */
-#define NVMUSERROW_SAM_E5_D5_MASK ((uint64_t)0x7FFF00FF3C007FFF)
+#define NVMUSERROW_SAM_E5_D5_MASK 0x7FFF00FF3C007FFFULL
struct samd_part {
uint8_t id;
diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c
index 67533fc..24c432c 100644
--- a/src/flash/nor/atsamv.c
+++ b/src/flash/nor/atsamv.c
@@ -53,8 +53,6 @@
#define SAMV_PAGE_SIZE 512
#define SAMV_FLASH_BASE 0x00400000
-extern const struct flash_driver atsamv_flash;
-
struct samv_flash_bank {
bool probed;
unsigned size_bytes;
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 931f794..889a811 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -237,4 +237,75 @@ struct flash_driver {
*/
const struct flash_driver *flash_driver_find_by_name(const char *name);
+extern const struct flash_driver aduc702x_flash;
+extern const struct flash_driver aducm360_flash;
+extern const struct flash_driver ambiqmicro_flash;
+extern const struct flash_driver at91sam3_flash;
+extern const struct flash_driver at91sam4_flash;
+extern const struct flash_driver at91sam4l_flash;
+extern const struct flash_driver at91sam7_flash;
+extern const struct flash_driver at91samd_flash;
+extern const struct flash_driver ath79_flash;
+extern const struct flash_driver atsame5_flash;
+extern const struct flash_driver atsamv_flash;
+extern const struct flash_driver avr_flash;
+extern const struct flash_driver bluenrgx_flash;
+extern const struct flash_driver cc26xx_flash;
+extern const struct flash_driver cc3220sf_flash;
+extern const struct flash_driver cfi_flash;
+extern const struct flash_driver dsp5680xx_flash;
+extern const struct flash_driver efm32_flash;
+extern const struct flash_driver em357_flash;
+extern const struct flash_driver esirisc_flash;
+extern const struct flash_driver faux_flash;
+extern const struct flash_driver fespi_flash;
+extern const struct flash_driver fm3_flash;
+extern const struct flash_driver fm4_flash;
+extern const struct flash_driver jtagspi_flash;
+extern const struct flash_driver kinetis_flash;
+extern const struct flash_driver kinetis_ke_flash;
+extern const struct flash_driver lpc2000_flash;
+extern const struct flash_driver lpc288x_flash;
+extern const struct flash_driver lpc2900_flash;
+extern const struct flash_driver lpcspifi_flash;
+extern const struct flash_driver max32xxx_flash;
+extern const struct flash_driver mdr_flash;
+extern const struct flash_driver mrvlqspi_flash;
+extern const struct flash_driver msp432_flash;
+extern const struct flash_driver niietcm4_flash;
+extern const struct flash_driver npcx_flash;
+extern const struct flash_driver nrf51_flash;
+extern const struct flash_driver nrf5_flash;
+extern const struct flash_driver numicro_flash;
+extern const struct flash_driver ocl_flash;
+extern const struct flash_driver pic32mx_flash;
+extern const struct flash_driver psoc4_flash;
+extern const struct flash_driver psoc5lp_eeprom_flash;
+extern const struct flash_driver psoc5lp_flash;
+extern const struct flash_driver psoc5lp_nvl_flash;
+extern const struct flash_driver psoc6_flash;
+extern const struct flash_driver renesas_rpchf_flash;
+extern const struct flash_driver rp2040_flash;
+extern const struct flash_driver rsl10_flash;
+extern const struct flash_driver sh_qspi_flash;
+extern const struct flash_driver sim3x_flash;
+extern const struct flash_driver stellaris_flash;
+extern const struct flash_driver stm32f1x_flash;
+extern const struct flash_driver stm32f2x_flash;
+extern const struct flash_driver stm32h7x_flash;
+extern const struct flash_driver stm32l4x_flash;
+extern const struct flash_driver stm32lx_flash;
+extern const struct flash_driver stmqspi_flash;
+extern const struct flash_driver stmsmi_flash;
+extern const struct flash_driver str7x_flash;
+extern const struct flash_driver str9x_flash;
+extern const struct flash_driver str9xpec_flash;
+extern const struct flash_driver swm050_flash;
+extern const struct flash_driver tms470_flash;
+extern const struct flash_driver virtual_flash;
+extern const struct flash_driver w600_flash;
+extern const struct flash_driver xcf_flash;
+extern const struct flash_driver xmc1xxx_flash;
+extern const struct flash_driver xmc4xxx_flash;
+
#endif /* OPENOCD_FLASH_NOR_DRIVER_H */
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index bd3363b..a0e135f 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -9,78 +9,6 @@
#endif
#include "imp.h"
-extern const struct flash_driver aduc702x_flash;
-extern const struct flash_driver aducm360_flash;
-extern const struct flash_driver ambiqmicro_flash;
-extern const struct flash_driver at91sam3_flash;
-extern const struct flash_driver at91sam4_flash;
-extern const struct flash_driver at91sam4l_flash;
-extern const struct flash_driver at91sam7_flash;
-extern const struct flash_driver at91samd_flash;
-extern const struct flash_driver ath79_flash;
-extern const struct flash_driver atsame5_flash;
-extern const struct flash_driver atsamv_flash;
-extern const struct flash_driver avr_flash;
-extern const struct flash_driver bluenrgx_flash;
-extern const struct flash_driver cc3220sf_flash;
-extern const struct flash_driver cc26xx_flash;
-extern const struct flash_driver cfi_flash;
-extern const struct flash_driver dsp5680xx_flash;
-extern const struct flash_driver efm32_flash;
-extern const struct flash_driver em357_flash;
-extern const struct flash_driver esirisc_flash;
-extern const struct flash_driver faux_flash;
-extern const struct flash_driver fm3_flash;
-extern const struct flash_driver fm4_flash;
-extern const struct flash_driver fespi_flash;
-extern const struct flash_driver gd32vf103_flash;
-extern const struct flash_driver jtagspi_flash;
-extern const struct flash_driver kinetis_flash;
-extern const struct flash_driver kinetis_ke_flash;
-extern const struct flash_driver lpc2000_flash;
-extern const struct flash_driver lpc288x_flash;
-extern const struct flash_driver lpc2900_flash;
-extern const struct flash_driver lpcspifi_flash;
-extern const struct flash_driver max32xxx_flash;
-extern const struct flash_driver mdr_flash;
-extern const struct flash_driver mrvlqspi_flash;
-extern const struct flash_driver msp432_flash;
-extern const struct flash_driver niietcm4_flash;
-extern const struct flash_driver npcx_flash;
-extern const struct flash_driver nrf5_flash;
-extern const struct flash_driver nrf51_flash;
-extern const struct flash_driver numicro_flash;
-extern const struct flash_driver ocl_flash;
-extern const struct flash_driver pic32mx_flash;
-extern const struct flash_driver psoc4_flash;
-extern const struct flash_driver psoc5lp_flash;
-extern const struct flash_driver psoc5lp_eeprom_flash;
-extern const struct flash_driver psoc5lp_nvl_flash;
-extern const struct flash_driver psoc6_flash;
-extern const struct flash_driver renesas_rpchf_flash;
-extern const struct flash_driver rp2040_flash;
-extern const struct flash_driver sh_qspi_flash;
-extern const struct flash_driver sim3x_flash;
-extern const struct flash_driver stellaris_flash;
-extern const struct flash_driver stm32f1x_flash;
-extern const struct flash_driver stm32f2x_flash;
-extern const struct flash_driver stm32lx_flash;
-extern const struct flash_driver stm32l4x_flash;
-extern const struct flash_driver stm32h7x_flash;
-extern const struct flash_driver stmqspi_flash;
-extern const struct flash_driver stmsmi_flash;
-extern const struct flash_driver str7x_flash;
-extern const struct flash_driver str9x_flash;
-extern const struct flash_driver str9xpec_flash;
-extern const struct flash_driver swm050_flash;
-extern const struct flash_driver tms470_flash;
-extern const struct flash_driver virtual_flash;
-extern const struct flash_driver w600_flash;
-extern const struct flash_driver xcf_flash;
-extern const struct flash_driver xmc1xxx_flash;
-extern const struct flash_driver xmc4xxx_flash;
-extern const struct flash_driver rsl10_flash;
-
/**
* The list of built-in flash drivers.
* @todo Make this dynamically extendable with loadable modules.
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
index d9b9695..5e2935d 100644
--- a/src/flash/nor/msp432.c
+++ b/src/flash/nor/msp432.c
@@ -375,7 +375,7 @@ static int msp432_init(struct flash_bank *bank)
buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR);
/* Begin executing the flash helper algorithm */
- retval = target_start_algorithm(target, 0, 0, 1, reg_params,
+ retval = target_start_algorithm(target, 0, NULL, 1, reg_params,
algo_entry_addr, 0, &msp432_bank->armv7m_info);
destroy_reg_param(&reg_params[0]);
if (retval != ERROR_OK) {
diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c
index 0b04ce4..a0c6e0c 100644
--- a/src/flash/nor/numicro.c
+++ b/src/flash/nor/numicro.c
@@ -536,8 +536,8 @@ struct numicro_flash_bank {
};
/* Private variables */
-uint32_t m_page_size = NUMICRO_PAGESIZE;
-uint32_t m_address_bias_offset;
+static uint32_t m_page_size = NUMICRO_PAGESIZE;
+static uint32_t m_address_bias_offset;
/* Private methods */
static int numicro_get_arm_arch(struct target *target)
diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c
index b0d118b..6c18c7b 100644
--- a/src/flash/nor/rp2040.c
+++ b/src/flash/nor/rp2040.c
@@ -520,7 +520,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
return ERROR_OK;
}
-struct flash_driver rp2040_flash = {
+const struct flash_driver rp2040_flash = {
.name = "rp2040_flash",
.flash_bank_command = rp2040_flash_bank_command,
.erase = rp2040_flash_erase,
diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c
index d92c4b8..5f0ac9b 100644
--- a/src/flash/nor/rsl10.c
+++ b/src/flash/nor/rsl10.c
@@ -107,7 +107,7 @@ static const char *const rsl10_error_list[] = {
[RSL10_FLASH_ERR_PROG_FAILED] = "prog failed",
};
-const char *rsl10_error(enum rsl10_flash_status x)
+static const char *rsl10_error(enum rsl10_flash_status x)
{
if (x >= RSL10_FLASH_MAX_ERR_CODES || !rsl10_error_list[x])
return "unknown";
diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
index 3a78952..972686e 100644
--- a/src/flash/nor/stellaris.c
+++ b/src/flash/nor/stellaris.c
@@ -1342,7 +1342,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
* cycle to recover.
*/
- Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0);
+ Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0);
if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) {
retval = ERROR_OK;
goto user_action;
diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c
index 77ea4c4..c9fc1bf 100644
--- a/src/flash/nor/stmqspi.c
+++ b/src/flash/nor/stmqspi.c
@@ -2447,7 +2447,7 @@ static const struct command_registration stmqspi_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct flash_driver stmqspi_flash = {
+const struct flash_driver stmqspi_flash = {
.name = "stmqspi",
.commands = stmqspi_command_handlers,
.flash_bank_command = stmqspi_flash_bank_command,
diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c
index 89e59ae..dcf59d3 100644
--- a/src/flash/nor/swm050.c
+++ b/src/flash/nor/swm050.c
@@ -183,7 +183,7 @@ static const struct command_registration swm050_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-struct flash_driver swm050_flash = {
+const struct flash_driver swm050_flash = {
.name = "swm050",
.commands = swm050_command_handlers,
.flash_bank_command = swm050_flash_bank_command,
diff --git a/src/helper/command.c b/src/helper/command.c
index 235bec8..945b890 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -582,7 +582,7 @@ int command_run_line(struct command_context *context, char *line)
Jim_DeleteAssocData(interp, "retval");
retcode = Jim_SetAssocData(interp, "retval", NULL, &retval);
if (retcode == JIM_OK) {
- retcode = Jim_Eval_Named(interp, line, 0, 0);
+ retcode = Jim_Eval_Named(interp, line, NULL, 0);
Jim_DeleteAssocData(interp, "retval");
}
diff --git a/src/helper/jep106.c b/src/helper/jep106.c
index d422561..62d24a9 100644
--- a/src/helper/jep106.c
+++ b/src/helper/jep106.c
@@ -26,7 +26,7 @@ const char *jep106_table_manufacturer(unsigned int bank, unsigned int id)
/* index is zero based */
id--;
- if (bank >= ARRAY_SIZE(jep106) || jep106[bank][id] == 0)
+ if (bank >= ARRAY_SIZE(jep106) || !jep106[bank][id])
return "<unknown>";
return jep106[bank][id];
diff --git a/src/helper/options.c b/src/helper/options.c
index 327c418..05cde67 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -39,12 +39,12 @@ static int help_flag, version_flag;
static const struct option long_options[] = {
{"help", no_argument, &help_flag, 1},
{"version", no_argument, &version_flag, 1},
- {"debug", optional_argument, 0, 'd'},
- {"file", required_argument, 0, 'f'},
- {"search", required_argument, 0, 's'},
- {"log_output", required_argument, 0, 'l'},
- {"command", required_argument, 0, 'c'},
- {0, 0, 0, 0}
+ {"debug", optional_argument, NULL, 'd'},
+ {"file", required_argument, NULL, 'f'},
+ {"search", required_argument, NULL, 's'},
+ {"log_output", required_argument, NULL, 'l'},
+ {"command", required_argument, NULL, 'c'},
+ {NULL, 0, NULL, 0}
};
int configuration_output_handler(struct command_context *context, const char *line)
diff --git a/src/helper/util.c b/src/helper/util.c
index 5e12021..2e9f615 100644
--- a/src/helper/util.c
+++ b/src/helper/util.c
@@ -12,6 +12,7 @@
#include "log.h"
#include "time_support.h"
+#include "util.h"
COMMAND_HANDLER(handler_util_ms)
{
diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c
index 7db3c7b..a372720 100644
--- a/src/jtag/drivers/arm-jtag-ew.c
+++ b/src/jtag/drivers/arm-jtag-ew.c
@@ -213,7 +213,7 @@ static int armjtagew_init(void)
armjtagew_handle = armjtagew_usb_open();
- if (armjtagew_handle == 0) {
+ if (!armjtagew_handle) {
LOG_ERROR(
"Cannot find ARM-JTAG-EW Interface! Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED;
diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c
index 08daa00..ba9ee5e 100644
--- a/src/jtag/drivers/at91rm9200.c
+++ b/src/jtag/drivers/at91rm9200.c
@@ -107,7 +107,7 @@ static int at91rm9200_quit(void);
static struct bitbang_interface at91rm9200_bitbang = {
.read = at91rm9200_read,
.write = at91rm9200_write,
- .blink = 0
+ .blink = NULL,
};
static bb_value_t at91rm9200_read(void)
@@ -157,8 +157,12 @@ COMMAND_HANDLER(at91rm9200_handle_device_command)
return ERROR_COMMAND_SYNTAX_ERROR;
/* only if the device name wasn't overwritten by cmdline */
- if (at91rm9200_device == 0) {
+ if (!at91rm9200_device) {
at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char));
+ if (!at91rm9200_device) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
strcpy(at91rm9200_device, CMD_ARGV[0]);
}
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index 635d9a5..879ca3c 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -19,7 +19,7 @@
#include <sys/mman.h>
-uint32_t bcm2835_peri_base = 0x20000000;
+static uint32_t bcm2835_peri_base = 0x20000000;
#define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
#define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000)
diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c
index 393fc7e..c3e841d 100644
--- a/src/jtag/drivers/ep93xx.c
+++ b/src/jtag/drivers/ep93xx.c
@@ -37,7 +37,7 @@ static int ep93xx_reset(int trst, int srst);
static int ep93xx_init(void);
static int ep93xx_quit(void);
-struct timespec ep93xx_zzzz;
+static struct timespec ep93xx_zzzz;
static struct jtag_interface ep93xx_interface = {
.supported = DEBUG_CAP_TMS_SEQ,
@@ -58,7 +58,7 @@ struct adapter_driver ep93xx_adapter_driver = {
static struct bitbang_interface ep93xx_bitbang = {
.read = ep93xx_read,
.write = ep93xx_write,
- .blink = 0,
+ .blink = NULL,
};
static bb_value_t ep93xx_read(void)
diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c
index 816b2d0..1d73af4 100644
--- a/src/jtag/drivers/ft232r.c
+++ b/src/jtag/drivers/ft232r.c
@@ -235,7 +235,7 @@ static int ft232r_speed(int divisor)
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
- SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) {
+ SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000) != 0) {
LOG_ERROR("cannot set baud rate");
return ERROR_JTAG_DEVICE_ERROR;
}
@@ -266,7 +266,7 @@ static int ft232r_init(void)
/* Reset the device. */
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
- SIO_RESET, 0, 0, 0, 0, 1000) != 0) {
+ SIO_RESET, 0, 0, NULL, 0, 1000) != 0) {
LOG_ERROR("unable to reset device");
return ERROR_JTAG_INIT_FAILED;
}
@@ -275,7 +275,7 @@ static int ft232r_init(void)
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BITMODE, (1<<tck_gpio) | (1<<tdi_gpio) | (1<<tms_gpio) | (1<<ntrst_gpio) | (1<<nsysrst_gpio) | 0x400,
- 0, 0, 0, 1000) != 0) {
+ 0, NULL, 0, 1000) != 0) {
LOG_ERROR("cannot set sync bitbang mode");
return ERROR_JTAG_INIT_FAILED;
}
@@ -288,13 +288,13 @@ static int ft232r_init(void)
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BAUD_RATE, divisor,
- 0, 0, 0, 1000) != 0) {
+ 0, NULL, 0, 1000) != 0) {
LOG_ERROR("cannot set baud rate");
return ERROR_JTAG_INIT_FAILED;
}
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
- SIO_SET_LATENCY_TIMER, latency_timer, 0, 0, 0, 1000) != 0) {
+ SIO_SET_LATENCY_TIMER, latency_timer, 0, NULL, 0, 1000) != 0) {
LOG_ERROR("unable to set latency timer");
return ERROR_JTAG_INIT_FAILED;
}
@@ -315,7 +315,7 @@ static int ft232r_quit(void)
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BITMODE, ft232r_restore_bitmode,
- 0, 0, 0, 1000) != 0) {
+ 0, NULL, 0, 1000) != 0) {
LOG_ERROR("cannot set bitmode to restore serial port");
}
}
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 9c8b80f..dd8cb16 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -64,6 +64,7 @@
#include <transport/transport.h>
#include <helper/time_support.h>
#include <helper/log.h>
+#include <helper/nvp.h>
#if IS_CYGWIN == 1
#include <windows.h>
@@ -224,7 +225,7 @@ static int ftdi_set_signal(const struct signal *s, char value)
oe = s->invert_oe;
break;
default:
- assert(0 && "invalid signal level specifier");
+ LOG_ERROR("invalid signal level specifier \'%c\'(0x%02x)", value, value);
return ERROR_FAIL;
}
@@ -1272,22 +1273,22 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command)
COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command)
{
- struct jim_nvp *n;
- static const struct jim_nvp nvp_ftdi_jtag_modes[] = {
+ const struct nvp *n;
+ static const struct nvp nvp_ftdi_jtag_modes[] = {
{ .name = "rising", .value = JTAG_MODE },
{ .name = "falling", .value = JTAG_MODE_ALT },
{ .name = NULL, .value = -1 },
};
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_ftdi_jtag_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_ftdi_jtag_modes, CMD_ARGV[0]);
if (!n->name)
return ERROR_COMMAND_SYNTAX_ERROR;
ftdi_jtag_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_ftdi_jtag_modes, ftdi_jtag_mode);
+ n = nvp_value2name(nvp_ftdi_jtag_modes, ftdi_jtag_mode);
command_print(CMD, "ftdi samples TDO on %s edge of TCK", n->name);
return ERROR_OK;
diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c
index 9f2fdde..fad91dd 100644
--- a/src/jtag/drivers/mpsse.c
+++ b/src/jtag/drivers/mpsse.c
@@ -313,7 +313,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const
int err;
if (!ctx)
- return 0;
+ return NULL;
bit_copy_queue_init(&ctx->read_queue);
ctx->read_chunk_size = 16384;
@@ -348,7 +348,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const
description ? description : "*",
serial ? serial : "*",
location ? location : "*");
- ctx->usb_dev = 0;
+ ctx->usb_dev = NULL;
goto error;
}
@@ -378,7 +378,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const
return ctx;
error:
mpsse_close(ctx);
- return 0;
+ return NULL;
}
void mpsse_close(struct mpsse_ctx *ctx)
@@ -465,13 +465,13 @@ static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_
void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
unsigned length, uint8_t mode)
{
- mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode);
+ mpsse_clock_data(ctx, out, out_offset, NULL, 0, length, mode);
}
void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length,
uint8_t mode)
{
- mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode);
+ mpsse_clock_data(ctx, NULL, 0, in, in_offset, length, mode);
}
void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
@@ -548,7 +548,7 @@ void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_of
void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset,
unsigned length, bool tdi, uint8_t mode)
{
- mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode);
+ mpsse_clock_tms_cs(ctx, out, out_offset, NULL, 0, length, tdi, mode);
}
void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in,
@@ -842,7 +842,7 @@ int mpsse_flush(struct mpsse_ctx *ctx)
if (ctx->write_count == 0)
return retval;
- struct libusb_transfer *read_transfer = 0;
+ struct libusb_transfer *read_transfer = NULL;
struct transfer_result read_result = { .ctx = ctx, .done = true };
if (ctx->read_count) {
buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */
diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c
index c353aef..ad980bf 100644
--- a/src/jtag/drivers/opendous.c
+++ b/src/jtag/drivers/opendous.c
@@ -347,7 +347,7 @@ static int opendous_init(void)
opendous_jtag_handle = opendous_usb_open();
- if (opendous_jtag_handle == 0) {
+ if (!opendous_jtag_handle) {
LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED;
}
diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c
index 4073d06..d26a510 100644
--- a/src/jtag/drivers/parport.c
+++ b/src/jtag/drivers/parport.c
@@ -411,9 +411,13 @@ COMMAND_HANDLER(parport_handle_parport_cable_command)
return ERROR_OK;
/* only if the cable name wasn't overwritten by cmdline */
- if (parport_cable == 0) {
+ if (!parport_cable) {
/* REVISIT first verify that it's listed in cables[] ... */
parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char));
+ if (!parport_cable) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
strcpy(parport_cable, CMD_ARGV[0]);
}
diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c
index c933b3e..65f7494 100644
--- a/src/jtag/drivers/rlink.c
+++ b/src/jtag/drivers/rlink.c
@@ -632,7 +632,7 @@ static int dtc_queue_run(void)
uint8_t dtc_mask, tdo_mask;
uint8_t reply_buffer[USB_EP2IN_SIZE];
- assert((dtc_queue.rq_head != 0) == (dtc_queue.reply_index > 0));
+ assert((!!dtc_queue.rq_head) == (dtc_queue.reply_index > 0));
assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE);
assert(dtc_queue.reply_index <= USB_EP2IN_SIZE);
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index 5b051c1..ee62954 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -3694,7 +3694,7 @@ static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode
h = calloc(1, sizeof(struct stlink_usb_handle_s));
- if (h == 0) {
+ if (!h) {
LOG_DEBUG("malloc failed");
return ERROR_FAIL;
}
diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c
index ee254d6..a5f5fd3 100644
--- a/src/jtag/drivers/sysfsgpio.c
+++ b/src/jtag/drivers/sysfsgpio.c
@@ -571,7 +571,7 @@ static struct bitbang_interface sysfsgpio_bitbang = {
.swdio_read = sysfsgpio_swdio_read,
.swdio_drive = sysfsgpio_swdio_drive,
.swd_write = sysfsgpio_swd_write,
- .blink = 0
+ .blink = NULL,
};
/* helper func to close and cleanup files only if they were valid/ used */
diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c
index ca52559..3e36218 100644
--- a/src/jtag/drivers/ti_icdi_usb.c
+++ b/src/jtag/drivers/ti_icdi_usb.c
@@ -369,7 +369,7 @@ static int icdi_usb_query(void *handle)
if (h->max_packet != ICDI_PACKET_SIZE) {
h->read_buffer = realloc(h->read_buffer, h->max_packet);
h->write_buffer = realloc(h->write_buffer, h->max_packet);
- if (h->read_buffer == 0 || h->write_buffer == 0) {
+ if (!h->read_buffer || !h->write_buffer) {
LOG_ERROR("unable to reallocate memory");
return ERROR_FAIL;
}
@@ -664,7 +664,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
h = calloc(1, sizeof(struct icdi_usb_handle_s));
- if (h == 0) {
+ if (!h) {
LOG_ERROR("unable to allocate memory");
return ERROR_FAIL;
}
@@ -712,7 +712,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
h->write_buffer = malloc(ICDI_PACKET_SIZE);
h->max_packet = ICDI_PACKET_SIZE;
- if (h->read_buffer == 0 || h->write_buffer == 0) {
+ if (!h->read_buffer || !h->write_buffer) {
LOG_DEBUG("malloc failed");
goto error_open;
}
diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c
index 0c0f24e..5d41656 100644
--- a/src/jtag/drivers/usbprog.c
+++ b/src/jtag/drivers/usbprog.c
@@ -148,7 +148,7 @@ static int usbprog_init(void)
usbprog_jtag_handle = usbprog_jtag_open();
tms_chain_index = 0;
- if (usbprog_jtag_handle == 0) {
+ if (!usbprog_jtag_handle) {
LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED;
}
diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c
index 7898e9d..9223be2 100644
--- a/src/jtag/drivers/vdebug.c
+++ b/src/jtag/drivers/vdebug.c
@@ -344,7 +344,7 @@ static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem)
return rc;
}
-int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count)
+static int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count)
{
uint8_t num_pre, num_post, tdi, tms;
unsigned int num, anum, bytes, hwords, words;
@@ -420,7 +420,7 @@ int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count)
return rc;
}
-int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count)
+static int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count)
{
unsigned int num, awidth, wwidth;
unsigned int req, waddr, rwords;
diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c
index 47d06f1..55692b1 100644
--- a/src/jtag/drivers/xds110.c
+++ b/src/jtag/drivers/xds110.c
@@ -1300,7 +1300,7 @@ static int xds110_swd_run_queue(void)
/* Transfer results into caller's buffers */
for (result = 0; result < xds110.txn_result_count; result++)
- if (xds110.txn_dap_results[result] != 0)
+ if (xds110.txn_dap_results[result])
*xds110.txn_dap_results[result] = dap_results[result];
xds110.txn_request_size = 0;
@@ -1611,7 +1611,7 @@ static void xds110_flush(void)
}
bits = 0;
}
- if (xds110.txn_scan_results[result].buffer != 0)
+ if (xds110.txn_scan_results[result].buffer)
bit_copy(xds110.txn_scan_results[result].buffer, 0, data_pntr,
bits, xds110.txn_scan_results[result].num_bits);
bits += xds110.txn_scan_results[result].num_bits;
@@ -1687,8 +1687,8 @@ static void xds110_execute_pathmove(struct jtag_command *cmd)
if (num_states == 0)
return;
- path = (uint8_t *)malloc(num_states * sizeof(uint8_t));
- if (path == 0) {
+ path = malloc(num_states * sizeof(uint8_t));
+ if (!path) {
LOG_ERROR("XDS110: unable to allocate memory");
return;
}
@@ -1766,7 +1766,7 @@ static void xds110_queue_scan(struct jtag_command *cmd)
/* Clear data out buffer to default value of all zeros */
memset((void *)buffer, 0x00, total_bytes);
for (i = 0; i < cmd->cmd.scan->num_fields; i++) {
- if (cmd->cmd.scan->fields[i].out_value != 0) {
+ if (cmd->cmd.scan->fields[i].out_value) {
/* Copy over data to scan out into request buffer */
bit_copy(buffer, offset, cmd->cmd.scan->fields[i].out_value, 0,
cmd->cmd.scan->fields[i].num_bits);
diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c
index b3cbc48..934b603 100644
--- a/src/jtag/tcl.c
+++ b/src/jtag/tcl.c
@@ -72,181 +72,134 @@ static bool scan_is_safe(tap_state_t state)
}
}
-static int jim_command_drscan(Jim_Interp *interp, int argc, Jim_Obj * const *args)
+static COMMAND_HELPER(handle_jtag_command_drscan_fields, struct scan_field *fields)
{
- int retval;
- struct scan_field *fields;
- int num_fields;
- int field_count = 0;
- int i, e;
- struct jtag_tap *tap;
- tap_state_t endstate;
+ unsigned int field_count = 0;
+ for (unsigned int i = 1; i < CMD_ARGC; i += 2) {
+ unsigned int bits;
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], bits);
+ fields[field_count].num_bits = bits;
- /* args[1] = device
- * args[2] = num_bits
- * args[3] = hex string
- * ... repeat num bits and hex string ...
- *
- * .. optionally:
- * args[N-2] = "-endstate"
- * args[N-1] = statename
- */
- if ((argc < 4) || ((argc % 2) != 0)) {
- Jim_WrongNumArgs(interp, 1, args, "wrong arguments");
- return JIM_ERR;
+ void *t = malloc(DIV_ROUND_UP(bits, 8));
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ fields[field_count].out_value = t;
+ str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0);
+ fields[field_count].in_value = t;
+ field_count++;
}
- endstate = TAP_IDLE;
+ return ERROR_OK;
+}
- /* validate arguments as numbers */
- e = JIM_OK;
- for (i = 2; i < argc; i += 2) {
- long bits;
- const char *cp;
+COMMAND_HANDLER(handle_jtag_command_drscan)
+{
+ /*
+ * CMD_ARGV[0] = device
+ * CMD_ARGV[1] = num_bits
+ * CMD_ARGV[2] = hex string
+ * ... repeat num bits and hex string ...
+ *
+ * ... optionally:
+ * CMD_ARGV[CMD_ARGC-2] = "-endstate"
+ * CMD_ARGV[CMD_ARGC-1] = statename
+ */
- e = Jim_GetLong(interp, args[i], &bits);
- /* If valid - try next arg */
- if (e == JIM_OK)
- continue;
+ if (CMD_ARGC < 3 || (CMD_ARGC % 2) != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
- /* Not valid.. are we at the end? */
- if (((i + 2) != argc)) {
- /* nope, then error */
- return e;
- }
+ struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[0]);
+ if (!tap) {
+ command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
- /* it could be: "-endstate FOO"
- * e.g. DRPAUSE so we can issue more instructions
- * before entering RUN/IDLE and executing them.
- */
+ if (tap->bypass) {
+ command_print(CMD, "Can't execute as the selected tap is in BYPASS");
+ return ERROR_FAIL;
+ }
- /* get arg as a string. */
- cp = Jim_GetString(args[i], NULL);
- /* is it the magic? */
- if (strcmp("-endstate", cp) == 0) {
- /* is the statename valid? */
- cp = Jim_GetString(args[i + 1], NULL);
-
- /* see if it is a valid state name */
- endstate = tap_state_by_name(cp);
- if (endstate < 0) {
- /* update the error message */
- Jim_SetResultFormatted(interp, "endstate: %s invalid", cp);
- } else {
- if (!scan_is_safe(endstate))
- LOG_WARNING("drscan with unsafe "
- "endstate \"%s\"", cp);
-
- /* valid - so clear the error */
- e = JIM_OK;
- /* and remove the last 2 args */
- argc -= 2;
- }
+ tap_state_t endstate = TAP_IDLE;
+ if (CMD_ARGC > 3 && !strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2])) {
+ const char *state_name = CMD_ARGV[CMD_ARGC - 1];
+ endstate = tap_state_by_name(state_name);
+ if (endstate < 0) {
+ command_print(CMD, "endstate: %s invalid", state_name);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- /* Still an error? */
- if (e != JIM_OK)
- return e; /* too bad */
- } /* validate args */
-
- assert(e == JIM_OK);
-
- tap = jtag_tap_by_jim_obj(interp, args[1]);
- if (!tap)
- return JIM_ERR;
+ if (!scan_is_safe(endstate))
+ LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name);
- num_fields = (argc-2)/2;
- if (num_fields <= 0) {
- Jim_SetResultString(interp, "drscan: no scan fields supplied", -1);
- return JIM_ERR;
+ CMD_ARGC -= 2;
}
- fields = malloc(sizeof(struct scan_field) * num_fields);
- for (i = 2; i < argc; i += 2) {
- long bits;
- int len;
- const char *str;
-
- Jim_GetLong(interp, args[i], &bits);
- str = Jim_GetString(args[i + 1], &len);
- fields[field_count].num_bits = bits;
- void *t = malloc(DIV_ROUND_UP(bits, 8));
- fields[field_count].out_value = t;
- str_to_buf(str, len, t, bits, 0);
- fields[field_count].in_value = t;
- field_count++;
+ unsigned int num_fields = (CMD_ARGC - 1) / 2;
+ struct scan_field *fields = calloc(num_fields, sizeof(struct scan_field));
+ if (!fields) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
}
+ int retval = CALL_COMMAND_HANDLER(handle_jtag_command_drscan_fields, fields);
+ if (retval != ERROR_OK)
+ goto fail;
+
jtag_add_dr_scan(tap, num_fields, fields, endstate);
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
- Jim_SetResultString(interp, "drscan: jtag execute failed", -1);
-
- for (i = 0; i < field_count; i++)
- free(fields[i].in_value);
- free(fields);
-
- return JIM_ERR;
+ command_print(CMD, "drscan: jtag execute failed");
+ goto fail;
}
- field_count = 0;
- Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
- for (i = 2; i < argc; i += 2) {
- long bits;
- char *str;
-
- Jim_GetLong(interp, args[i], &bits);
- str = buf_to_hex_str(fields[field_count].in_value, bits);
- free(fields[field_count].in_value);
-
- Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str)));
+ for (unsigned int i = 0; i < num_fields; i++) {
+ char *str = buf_to_hex_str(fields[i].in_value, fields[i].num_bits);
+ command_print(CMD, "%s", str);
free(str);
- field_count++;
}
- Jim_SetResult(interp, list);
-
+fail:
+ for (unsigned int i = 0; i < num_fields; i++)
+ free(fields[i].in_value);
free(fields);
- return JIM_OK;
+ return retval;
}
-
-static int jim_command_pathmove(Jim_Interp *interp, int argc, Jim_Obj * const *args)
+COMMAND_HANDLER(handle_jtag_command_pathmove)
{
tap_state_t states[8];
- if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) {
- Jim_WrongNumArgs(interp, 1, args, "wrong arguments");
- return JIM_ERR;
- }
+ if (CMD_ARGC < 1 || CMD_ARGC > ARRAY_SIZE(states))
+ return ERROR_COMMAND_SYNTAX_ERROR;
- int i;
- for (i = 0; i < argc-1; i++) {
- const char *cp;
- cp = Jim_GetString(args[i + 1], NULL);
- states[i] = tap_state_by_name(cp);
+ for (unsigned int i = 0; i < CMD_ARGC; i++) {
+ states[i] = tap_state_by_name(CMD_ARGV[i]);
if (states[i] < 0) {
- /* update the error message */
- Jim_SetResultFormatted(interp, "endstate: %s invalid", cp);
- return JIM_ERR;
+ command_print(CMD, "endstate: %s invalid", CMD_ARGV[i]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
}
- if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue() != ERROR_OK)) {
- Jim_SetResultString(interp, "pathmove: jtag execute failed", -1);
- return JIM_ERR;
+ int retval = jtag_add_statemove(states[0]);
+ if (retval == ERROR_OK)
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ command_print(CMD, "pathmove: jtag execute failed");
+ return retval;
}
- jtag_add_pathmove(argc - 2, states + 1);
-
- if (jtag_execute_queue() != ERROR_OK) {
- Jim_SetResultString(interp, "pathmove: failed", -1);
- return JIM_ERR;
+ jtag_add_pathmove(CMD_ARGC - 1, states + 1);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ command_print(CMD, "pathmove: failed");
+ return retval;
}
- return JIM_OK;
+ return ERROR_OK;
}
COMMAND_HANDLER(handle_jtag_flush_count)
@@ -274,10 +227,10 @@ static const struct command_registration jtag_command_handlers_to_move[] = {
{
.name = "drscan",
.mode = COMMAND_EXEC,
- .jim_handler = jim_command_drscan,
+ .handler = handle_jtag_command_drscan,
.help = "Execute Data Register (DR) scan for one TAP. "
"Other TAPs must be in BYPASS mode.",
- .usage = "tap_name [num_bits value]* ['-endstate' state_name]",
+ .usage = "tap_name (num_bits value)+ ['-endstate' state_name]",
},
{
.name = "flush_count",
@@ -290,7 +243,7 @@ static const struct command_registration jtag_command_handlers_to_move[] = {
{
.name = "pathmove",
.mode = COMMAND_EXEC,
- .jim_handler = jim_command_pathmove,
+ .handler = handle_jtag_command_pathmove,
.usage = "start_state state1 [state2 [state3 ...]]",
.help = "Move JTAG state machine from current state "
"(start_state) to state1, then state2, state3, etc.",
diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am
index 14786af..69e457c 100644
--- a/src/pld/Makefile.am
+++ b/src/pld/Makefile.am
@@ -2,9 +2,26 @@
noinst_LTLIBRARIES += %D%/libpld.la
%C%_libpld_la_SOURCES = \
+ %D%/certus.c \
+ %D%/ecp2_3.c \
+ %D%/ecp5.c \
+ %D%/efinix.c \
+ %D%/gatemate.c \
+ %D%/gowin.c \
+ %D%/intel.c \
+ %D%/lattice.c \
+ %D%/lattice_bit.c \
%D%/pld.c \
+ %D%/raw_bit.c \
%D%/xilinx_bit.c \
%D%/virtex2.c \
+ %D%/certus.h \
+ %D%/ecp2_3.h \
+ %D%/ecp5.h \
+ %D%/lattice.h \
+ %D%/lattice_bit.h \
+ %D%/lattice_cmd.h \
%D%/pld.h \
+ %D%/raw_bit.h \
%D%/xilinx_bit.h \
%D%/virtex2.h
diff --git a/src/pld/certus.c b/src/pld/certus.c
new file mode 100644
index 0000000..1309c1b
--- /dev/null
+++ b/src/pld/certus.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "certus.h"
+#include "lattice.h"
+#include "lattice_cmd.h"
+
+#define LSC_ENABLE_X 0x74
+#define LSC_REFRESH 0x79
+#define LSC_DEVICE_CTRL 0x7D
+
+int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out)
+{
+ return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out);
+}
+
+int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out)
+{
+ return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false);
+}
+
+int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
+{
+ LOG_ERROR("Not supported to write usercode on certus devices");
+ return ERROR_FAIL;
+}
+
+static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap)
+{
+ struct scan_field field;
+
+ int retval = lattice_set_instr(tap, LSC_ENABLE_X, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint8_t buffer = 0x0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+static int lattice_certus_erase_device(struct lattice_pld_device *lattice_device)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 8;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ buffer = 0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ buffer = 0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(100, TAP_IDLE);
+ jtag_add_sleep(5000);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* check done is cleared and fail is cleared */
+ const uint64_t status_done_flag = 0x100;
+ const uint64_t status_fail_flag = 0x2000;
+ return lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_done_flag | status_fail_flag);
+}
+
+static int lattice_certus_enable_programming(struct jtag_tap *tap)
+{
+ struct scan_field field;
+
+ int retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ uint8_t buffer = 0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+static int lattice_certus_init_address(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+static int lattice_certus_exit_programming_mode(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(100, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+static int lattice_certus_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file)
+{
+ struct scan_field field;
+
+ int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8;
+ field.out_value = bit_file->raw_bit.data + bit_file->offset;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_preload(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* check password protection is disabled */
+ const uint64_t status_pwd_protection = 0x20000;
+ retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_pwd_protection);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Password protection is set");
+ return retval;
+ }
+
+ retval = lattice_certus_enable_transparent_mode(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Check the SRAM Erase Lock */
+ const uint64_t status_otp = 0x40;
+ retval = lattice_verify_status_register_u64(lattice_device, 0x0, status_otp, status_otp);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("NV User Feature Sector OTP is Set");
+ return retval;
+ }
+
+ /* Check the SRAM Lock */
+ const uint64_t status_write_protected = 0x400;
+ retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_write_protected);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("NV User Feature Sector OTP is Set");
+ return retval;
+ }
+
+ retval = lattice_certus_enable_programming(tap);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("failed to enable programming mode");
+ return retval;
+ }
+
+ retval = lattice_certus_erase_device(lattice_device);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("erasing device failed");
+ return retval;
+ }
+
+ retval = lattice_certus_init_address(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_certus_program_config_map(tap, bit_file);
+ if (retval != ERROR_OK)
+ return retval;
+ const uint32_t expected = 0x100; // done
+ const uint32_t mask = expected |
+ 0x3000 | // Busy Flag and Fail Flag
+ 0xf000000; // BSE Error
+ retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x100, mask);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return lattice_certus_exit_programming_mode(tap);
+}
diff --git a/src/pld/certus.h b/src/pld/certus.h
new file mode 100644
index 0000000..51defc5
--- /dev/null
+++ b/src/pld/certus.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_CERTUS_H
+#define OPENOCD_PLD_CERTUS_H
+
+#include "lattice.h"
+
+int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out);
+int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out);
+int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode);
+int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_CERTUS_H */
diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c
new file mode 100644
index 0000000..b1c2833
--- /dev/null
+++ b/src/pld/ecp2_3.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ecp2_3.h"
+#include "lattice.h"
+
+#define LSCC_REFRESH 0x23
+#define ISC_ENABLE 0x15
+#define LSCC_RESET_ADDRESS 0x21
+#define ISC_PROGRAM_USERCODE 0x1A
+#define ISC_ERASE 0x03
+#define READ_USERCODE 0x17
+#define ISC_DISABLE 0x1E
+#define LSCC_READ_STATUS 0x53
+#define LSCC_BITSTREAM_BURST 0x02
+
+#define STATUS_DONE_BIT 0x00020000
+#define STATUS_ERROR_BITS_ECP2 0x00040003
+#define STATUS_ERROR_BITS_ECP3 0x00040007
+#define REGISTER_ALL_BITS_1 0xffffffff
+#define REGISTER_ALL_BITS_0 0x00000000
+
+int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle)
+{
+ return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle);
+}
+
+int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out)
+{
+ return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false);
+}
+
+int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(20000);
+
+ retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer[4];
+ h_u32_to_le(buffer, usercode);
+ field.num_bits = 32;
+ field.out_value = buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(200000);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1);
+}
+
+static int lattice_ecp2_3_erase_device(struct lattice_pld_device *lattice_device)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ /* program user code with all bits set */
+ int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE);
+ if (retval != ERROR_OK)
+ return retval;
+ struct scan_field field;
+ uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff};
+ field.num_bits = 32;
+ field.out_value = buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ /* verify every bit is set */
+ const uint32_t out = REGISTER_ALL_BITS_1;
+ const uint32_t mask = REGISTER_ALL_BITS_1;
+ const uint32_t expected_pre = REGISTER_ALL_BITS_1;
+ retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ if (lattice_device->family == LATTICE_ECP2)
+ jtag_add_sleep(100000);
+ else
+ jtag_add_sleep(2000000);
+
+ retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ /* after erasing check all bits in user register are cleared */
+ const uint32_t expected_post = REGISTER_ALL_BITS_0;
+ return lattice_verify_usercode(lattice_device, out, expected_post, mask);
+}
+
+static int lattice_ecp2_3_program_config_map(struct lattice_pld_device *lattice_device,
+ struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ struct scan_field field;
+ retval = lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8;
+ field.out_value = bit_file->raw_bit.data + bit_file->offset;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(256, TAP_IDLE);
+ jtag_add_sleep(2000);
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device *lattice_device)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(200000);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(100, TAP_IDLE);
+ jtag_add_sleep(1000);
+ return jtag_execute_queue();
+}
+
+int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_preload(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Enable the programming mode */
+ retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(20000);
+
+ /* Erase the device */
+ retval = lattice_ecp2_3_erase_device(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Program Fuse Map */
+ retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t out = REGISTER_ALL_BITS_1;
+ const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2;
+ const uint32_t expected = STATUS_DONE_BIT;
+ return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false);
+}
+
+int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ /* Program Bscan register */
+ int retval = lattice_preload(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Enable the programming mode */
+ retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(500000);
+ retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(20000);
+
+ retval = lattice_ecp2_3_erase_device(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Program Fuse Map */
+ retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp2_3_exit_programming_mode(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t out = REGISTER_ALL_BITS_1;
+ const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3;
+ const uint32_t expected = STATUS_DONE_BIT;
+ return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false);
+}
diff --git a/src/pld/ecp2_3.h b/src/pld/ecp2_3.h
new file mode 100644
index 0000000..5f3e9e97
--- /dev/null
+++ b/src/pld/ecp2_3.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_ECP2_3_H
+#define OPENOCD_PLD_ECP2_3_H
+
+#include "lattice.h"
+
+int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle);
+int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out);
+int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode);
+int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file);
+int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_ECP2_3_H */
diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c
new file mode 100644
index 0000000..2e1009b
--- /dev/null
+++ b/src/pld/ecp5.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "ecp5.h"
+#include "lattice.h"
+#include "lattice_cmd.h"
+
+#define ISC_PROGRAM_USERCODE 0xC2
+
+#define STATUS_DONE_BIT 0x00000100
+#define STATUS_ERROR_BITS 0x00020040
+#define STATUS_FEA_OTP 0x00004000
+#define STATUS_FAIL_FLAG 0x00002000
+#define STATUS_BUSY_FLAG 0x00001000
+#define REGISTER_ALL_BITS_1 0xffffffff
+
+int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle)
+{
+ return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle);
+}
+
+int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out)
+{
+ return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true);
+}
+
+int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(20000);
+
+ retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint8_t buffer[4];
+ struct scan_field field;
+ h_u32_to_le(buffer, usercode);
+ field.num_bits = 32;
+ field.out_value = buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(2000);
+
+ retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(5, TAP_IDLE);
+ jtag_add_sleep(200000);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1);
+}
+
+static int lattice_ecp5_enable_sram_programming(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 0x0;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_erase_sram(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 1;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(200000);
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_init_address(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct scan_field field;
+ uint8_t buffer = 1;
+ field.num_bits = 8;
+ field.out_value = &buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file)
+{
+ int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ struct scan_field field;
+ field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8;
+ field.out_value = bit_file->raw_bit.data + bit_file->offset;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(100, TAP_IDLE);
+ jtag_add_sleep(10000);
+
+ return jtag_execute_queue();
+}
+
+static int lattice_ecp5_exit_programming_mode(struct jtag_tap *tap)
+{
+ int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(200000);
+ retval = lattice_set_instr(tap, BYPASS, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(1000);
+ return jtag_execute_queue();
+}
+
+int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ int retval = lattice_preload(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_enable_sram_programming(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t out = 0x0;
+ const uint32_t expected1 = 0x0;
+ const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP;
+ retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_erase_sram(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG;
+ retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_init_address(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_program_config_map(tap, bit_file);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_ecp5_exit_programming_mode(tap);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t expected2 = STATUS_DONE_BIT;
+ const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG;
+ return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false);
+}
diff --git a/src/pld/ecp5.h b/src/pld/ecp5.h
new file mode 100644
index 0000000..7b0c86b
--- /dev/null
+++ b/src/pld/ecp5.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_ECP5_H
+#define OPENOCD_PLD_ECP5_H
+
+#include "lattice.h"
+
+int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle);
+int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out);
+int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode);
+int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file);
+
+#endif /* OPENOCD_PLD_ECP5_H */
diff --git a/src/pld/efinix.c b/src/pld/efinix.c
new file mode 100644
index 0000000..f084394
--- /dev/null
+++ b/src/pld/efinix.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+
+#include "pld.h"
+#include "raw_bit.h"
+
+#define PROGRAM 0x4
+#define ENTERUSER 0x7
+
+#define TRAILING_ZEROS 4000
+#define RUNTEST_START_CYCLES 100
+#define RUNTEST_FINISH_CYCLES 100
+
+struct efinix_pld_device {
+ struct jtag_tap *tap;
+};
+
+static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename)
+{
+ FILE *input_file = fopen(filename, "r");
+ if (!input_file) {
+ LOG_ERROR("couldn't open %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ fseek(input_file, 0, SEEK_END);
+ long length = ftell(input_file);
+ fseek(input_file, 0, SEEK_SET);
+
+ if (length < 0 || ((length % 3))) {
+ fclose(input_file);
+ LOG_ERROR("Failed to get length from file %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+ bit_file->length = DIV_ROUND_UP(length, 3);
+
+ bit_file->data = malloc(bit_file->length);
+ if (!bit_file->data) {
+ fclose(input_file);
+ LOG_ERROR("Out of memory");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ bool end_detected = false;
+ char buffer[3];
+ for (size_t idx = 0; !end_detected && idx < bit_file->length; ++idx) {
+ size_t read_count = fread(buffer, sizeof(char), 3, input_file);
+ end_detected = feof(input_file);
+ if ((read_count == 3 && buffer[2] != '\n') ||
+ (read_count != 3 && !end_detected) ||
+ (read_count != 2 && end_detected)) {
+ fclose(input_file);
+ free(bit_file->data);
+ bit_file->data = NULL;
+ LOG_ERROR("unexpected line length");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (!isxdigit(buffer[0]) || !isxdigit(buffer[1])) {
+ fclose(input_file);
+ free(bit_file->data);
+ bit_file->data = NULL;
+ LOG_ERROR("unexpected char in hex string");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+ unhexify(&bit_file->data[idx], buffer, 2);
+ }
+
+ fclose(input_file);
+
+ return ERROR_OK;
+}
+
+static int efinix_read_file(struct raw_bit_file *bit_file, const char *filename)
+{
+ if (!filename || !bit_file)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* check if binary .bin or ascii .bit/.hex */
+ const char *file_ending_pos = strrchr(filename, '.');
+ if (!file_ending_pos) {
+ LOG_ERROR("Unable to detect filename suffix");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (strcasecmp(file_ending_pos, ".bin") == 0) {
+ return cpld_read_raw_bit_file(bit_file, filename);
+ } else if ((strcasecmp(file_ending_pos, ".bit") == 0) ||
+ (strcasecmp(file_ending_pos, ".hex") == 0)) {
+ return efinix_read_bit_file(bit_file, filename);
+ }
+
+ LOG_ERROR("Unable to detect filetype");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+}
+
+static int efinix_set_instr(struct jtag_tap *tap, uint8_t new_instr)
+{
+ struct scan_field field;
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+ free(t);
+ return ERROR_OK;
+}
+
+static int efinix_load(struct pld_device *pld_device, const char *filename)
+{
+ struct raw_bit_file bit_file;
+ struct scan_field field[2];
+
+ if (!pld_device || !pld_device->driver_priv)
+ return ERROR_FAIL;
+
+ struct efinix_pld_device *efinix_info = pld_device->driver_priv;
+ if (!efinix_info || !efinix_info->tap)
+ return ERROR_FAIL;
+ struct jtag_tap *tap = efinix_info->tap;
+
+ jtag_add_tlr();
+
+ int retval = efinix_set_instr(tap, PROGRAM);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(RUNTEST_START_CYCLES, TAP_IDLE);
+ retval = efinix_set_instr(tap, PROGRAM); /* fix for T20 */
+ if (retval != ERROR_OK)
+ return retval;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = efinix_read_file(&bit_file, filename);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (size_t i = 0; i < bit_file.length; i++)
+ bit_file.data[i] = flip_u32(bit_file.data[i], 8);
+
+ /* shift in the bitstream */
+ field[0].num_bits = bit_file.length * 8;
+ field[0].out_value = bit_file.data;
+ field[0].in_value = NULL;
+
+ /* followed by zeros */
+ field[1].num_bits = TRAILING_ZEROS;
+ uint8_t *buf = calloc(TRAILING_ZEROS / 8, 1);
+ if (!buf) {
+ free(bit_file.data);
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field[1].out_value = buf;
+ field[1].in_value = NULL;
+
+ jtag_add_dr_scan(tap, 2, field, TAP_DRPAUSE);
+ retval = jtag_execute_queue();
+ free(bit_file.data);
+ free(buf);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = efinix_set_instr(tap, ENTERUSER);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* entering RUN/TEST for 100 cycles */
+ jtag_add_runtest(RUNTEST_FINISH_CYCLES, TAP_IDLE);
+ retval = jtag_execute_queue();
+
+ return retval;
+}
+
+PLD_DEVICE_COMMAND_HANDLER(efinix_pld_device_command)
+{
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]);
+ if (!tap) {
+ command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+ return ERROR_FAIL;
+ }
+
+ struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device));
+ if (!efinix_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ efinix_info->tap = tap;
+
+ pld->driver_priv = efinix_info;
+
+ return ERROR_OK;
+}
+
+struct pld_driver efinix_pld = {
+ .name = "efinix",
+ .pld_device_command = &efinix_pld_device_command,
+ .load = &efinix_load,
+};
diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c
new file mode 100644
index 0000000..43b3f02
--- /dev/null
+++ b/src/pld/gatemate.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#include "pld.h"
+#include "raw_bit.h"
+
+#define JTAG_CONFIGURE 0x06
+
+struct gatemate_pld_device {
+ struct jtag_tap *tap;
+};
+
+struct gatemate_bit_file {
+ struct raw_bit_file raw_file;
+ size_t capacity;
+};
+
+static int gatemate_add_byte_to_bitfile(struct gatemate_bit_file *bit_file, uint8_t byte)
+{
+ const size_t chunk_size = 8192;
+ if (bit_file->raw_file.length + 1 > bit_file->capacity) {
+ uint8_t *buffer;
+ if (bit_file->raw_file.data)
+ buffer = realloc(bit_file->raw_file.data, bit_file->capacity + chunk_size);
+ else
+ buffer = malloc(chunk_size);
+ if (!buffer) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ bit_file->raw_file.data = buffer;
+ bit_file->capacity += chunk_size;
+ }
+
+ bit_file->raw_file.data[bit_file->raw_file.length++] = byte;
+
+ return ERROR_OK;
+}
+
+static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char *line_buffer, size_t nread)
+{
+ for (size_t idx = 0; idx < nread; ++idx) {
+ if (line_buffer[idx] == ' ') {
+ continue;
+ } else if (line_buffer[idx] == 0) {
+ break;
+ } else if (idx + 1 < nread) {
+ if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) {
+ uint8_t byte;
+ unhexify(&byte, line_buffer + idx, 2);
+ int retval = gatemate_add_byte_to_bitfile(bit_file, byte);
+ if (retval != ERROR_OK)
+ return retval;
+ } else if (line_buffer[idx] == '/' && line_buffer[idx + 1] == '/') {
+ break;
+ }
+ ++idx;
+ } else {
+ LOG_ERROR("parsing failed");
+ return ERROR_FAIL;
+ }
+ }
+ return ERROR_OK;
+}
+
+static int gatemate_getline(char **buffer, size_t *buf_size, FILE *input_file)
+{
+ const size_t chunk_size = 32;
+ if (!*buffer)
+ *buf_size = 0;
+
+ size_t read = 0;
+ do {
+ if (read + 1 > *buf_size) {
+ char *new_buffer;
+ if (*buffer)
+ new_buffer = realloc(*buffer, *buf_size + chunk_size);
+ else
+ new_buffer = malloc(chunk_size);
+ if (!new_buffer) {
+ LOG_ERROR("Out of memory");
+ return -1;
+ }
+ *buffer = new_buffer;
+ *buf_size += chunk_size;
+ }
+
+ int c = fgetc(input_file);
+ if ((c == EOF && read) || (char)c == '\n') {
+ (*buffer)[read++] = 0;
+ return read;
+ } else if (c == EOF) {
+ return -1;
+ }
+
+ (*buffer)[read++] = (char)c;
+ } while (1);
+
+ return -1;
+}
+
+static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char *filename)
+{
+ FILE *input_file = fopen(filename, "r");
+
+ if (!input_file) {
+ LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ int retval = ERROR_OK;
+ char *line_buffer = NULL;
+ size_t buffer_length = 0;
+ int nread;
+ while (((nread = gatemate_getline(&line_buffer, &buffer_length, input_file)) != -1) && (retval == ERROR_OK))
+ retval = gatemate_read_cfg_line(bit_file, line_buffer, (size_t)nread);
+
+ if (line_buffer)
+ free(line_buffer);
+
+ fclose(input_file);
+ if (retval != ERROR_OK)
+ free(bit_file->raw_file.data);
+ return retval;
+}
+
+static int gatemate_read_file(struct gatemate_bit_file *bit_file, const char *filename)
+{
+ memset(bit_file, 0, sizeof(struct gatemate_bit_file));
+
+ if (!filename || !bit_file)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* check if binary .bit or ascii .cfg */
+ const char *file_suffix_pos = strrchr(filename, '.');
+ if (!file_suffix_pos) {
+ LOG_ERROR("Unable to detect filename suffix");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (strcasecmp(file_suffix_pos, ".bit") == 0)
+ return cpld_read_raw_bit_file(&bit_file->raw_file, filename);
+ else if (strcasecmp(file_suffix_pos, ".cfg") == 0)
+ return gatemate_read_cfg_file(bit_file, filename);
+
+ LOG_ERROR("Filetype not supported, expecting .bit or .cfg file");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+}
+
+static int gatemate_set_instr(struct jtag_tap *tap, uint8_t new_instr)
+{
+ struct scan_field field;
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+ jtag_add_runtest(3, TAP_IDLE);
+ free(t);
+ return ERROR_OK;
+}
+
+static int gatemate_load(struct pld_device *pld_device, const char *filename)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct gatemate_pld_device *gatemate_info = pld_device->driver_priv;
+
+ if (!gatemate_info || !gatemate_info->tap)
+ return ERROR_FAIL;
+ struct jtag_tap *tap = gatemate_info->tap;
+
+ struct gatemate_bit_file bit_file;
+ int retval = gatemate_read_file(&bit_file, filename);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = gatemate_set_instr(tap, JTAG_CONFIGURE);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ struct scan_field field;
+ field.num_bits = bit_file.raw_file.length * 8;
+ field.out_value = bit_file.raw_file.data;
+ field.in_value = NULL;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+
+ retval = jtag_execute_queue();
+ free(bit_file.raw_file.data);
+
+ return retval;
+}
+
+PLD_DEVICE_COMMAND_HANDLER(gatemate_pld_device_command)
+{
+ struct jtag_tap *tap;
+
+ struct gatemate_pld_device *gatemate_info;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ tap = jtag_tap_by_string(CMD_ARGV[1]);
+ if (!tap) {
+ command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+ return ERROR_FAIL;
+ }
+
+ gatemate_info = malloc(sizeof(struct gatemate_pld_device));
+ if (!gatemate_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ gatemate_info->tap = tap;
+
+ pld->driver_priv = gatemate_info;
+
+ return ERROR_OK;
+}
+
+struct pld_driver gatemate_pld = {
+ .name = "gatemate",
+ .pld_device_command = &gatemate_pld_device_command,
+ .load = &gatemate_load,
+};
diff --git a/src/pld/gowin.c b/src/pld/gowin.c
new file mode 100644
index 0000000..467b799
--- /dev/null
+++ b/src/pld/gowin.c
@@ -0,0 +1,581 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#include <helper/bits.h>
+#include "pld.h"
+#include "raw_bit.h"
+
+#define NO_OP 0x02
+#define ERASE_SRAM 0x05
+#define SRAM_ERASE_DONE 0x09
+#define IDCODE 0x11
+#define ADDRESS_INITIALIZATION 0x12
+#define READ_USERCODE 0x13
+#define CONFIG_ENABLE 0x15
+#define TRANSFER_CONFIGURATION_DATA 0x17
+#define CONFIG_DISABLE 0x3A
+#define RELOAD 0x3C
+#define STATUS_REGISTER 0x41
+#define ERASE_FLASH 0x75
+#define ENABLE_2ND_FLASH 0x78
+
+#define STAUS_MASK_MEMORY_ERASE BIT(5)
+#define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7)
+
+struct gowin_pld_device {
+ struct jtag_tap *tap;
+};
+
+struct gowin_bit_file {
+ struct raw_bit_file raw_file;
+ size_t capacity;
+ uint32_t id;
+ uint16_t stored_checksum;
+ int compressed;
+ int crc_en;
+ uint16_t checksum;
+ uint8_t replace8x;
+ uint8_t replace4x;
+ uint8_t replace2x;
+};
+
+static uint64_t gowin_read_fs_file_bitsequence(const char *bits, int length)
+{
+ uint64_t res = 0;
+ for (int i = 0; i < length; i++)
+ res = (res << 1) | (*bits++ == '1' ? 1 : 0);
+ return res;
+}
+
+static int gowin_add_byte_to_bit_file(struct gowin_bit_file *bit_file, uint8_t byte)
+{
+ if (bit_file->raw_file.length + 1 > bit_file->capacity) {
+ uint8_t *buffer;
+ if (bit_file->raw_file.data)
+ buffer = realloc(bit_file->raw_file.data, bit_file->capacity + 8192);
+ else
+ buffer = malloc(8192);
+ if (!buffer) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ bit_file->raw_file.data = buffer;
+ bit_file->capacity += 8192;
+ }
+
+ bit_file->raw_file.data[bit_file->raw_file.length++] = byte;
+
+ return ERROR_OK;
+}
+
+static int gowin_read_fs_file_header(struct gowin_bit_file *bit_file, FILE *stream)
+{
+ if (!bit_file)
+ return ERROR_FAIL;
+
+ int end_of_header = 0;
+ while (!end_of_header) {
+ char buffer[256];
+ char *line = fgets(buffer, 256, stream);
+ if (!line || feof(stream) || ferror(stream))
+ return ERROR_FAIL;
+
+ if (line[0] == '/')
+ continue;
+
+ size_t line_length = strlen(line);
+ if (line[line_length - 1] != '\n')
+ return ERROR_FAIL;
+ line_length--;
+
+ for (unsigned int i = 0; i < line_length; i += 8) {
+ uint8_t byte = gowin_read_fs_file_bitsequence(line + i, 8);
+ int retval = gowin_add_byte_to_bit_file(bit_file, byte);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ uint8_t key = gowin_read_fs_file_bitsequence(line, 8);
+ line += 8;
+ uint64_t value = gowin_read_fs_file_bitsequence(line, line_length - 8);
+
+ if (key == 0x06) {
+ bit_file->id = value & 0xffffffff;
+ } else if (key == 0x3B) {
+ end_of_header = 1;
+ bit_file->crc_en = (value & BIT(23)) ? 1 : 0;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int gowin_read_fs_file(struct gowin_bit_file *bit_file, const char *filename)
+{
+ FILE *input_file = fopen(filename, "r");
+
+ if (!input_file) {
+ LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ int retval = gowin_read_fs_file_header(bit_file, input_file);
+ if (retval != ERROR_OK) {
+ free(bit_file->raw_file.data);
+ fclose(input_file);
+ return retval;
+ }
+
+ char digits_buffer[9]; /* 8 + 1 trailing zero */
+ do {
+ char *digits = fgets(digits_buffer, 9, input_file);
+ if (feof(input_file))
+ break;
+ if (!digits || ferror(input_file)) {
+ free(bit_file->raw_file.data);
+ fclose(input_file);
+ return ERROR_FAIL;
+ }
+ if (digits[0] == '\n')
+ continue;
+
+ if (strlen(digits) != 8) {
+ free(bit_file->raw_file.data);
+ fclose(input_file);
+ return ERROR_FAIL;
+ }
+ uint8_t byte = gowin_read_fs_file_bitsequence(digits, 8);
+ retval = gowin_add_byte_to_bit_file(bit_file, byte);
+ if (retval != ERROR_OK) {
+ free(bit_file->raw_file.data);
+ fclose(input_file);
+ return ERROR_FAIL;
+ }
+ } while (1);
+
+ fclose(input_file);
+ return ERROR_OK;
+}
+
+static int gowin_read_file(struct gowin_bit_file *bit_file, const char *filename, bool *is_fs)
+{
+ memset(bit_file, 0, sizeof(struct gowin_bit_file));
+
+ if (!filename || !bit_file)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ const char *file_suffix_pos = strrchr(filename, '.');
+ if (!file_suffix_pos) {
+ LOG_ERROR("Unable to detect filename suffix");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ /* check if binary .bin or ascii .fs */
+ if (strcasecmp(file_suffix_pos, ".bin") == 0) {
+ *is_fs = false;
+ return cpld_read_raw_bit_file(&bit_file->raw_file, filename);
+ } else if (strcasecmp(file_suffix_pos, ".fs") == 0) {
+ *is_fs = true;
+ return gowin_read_fs_file(bit_file, filename);
+ }
+
+ LOG_ERROR("Filetype not supported, expecting .fs or .bin file");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+}
+
+static int gowin_set_instr(struct jtag_tap *tap, uint8_t new_instr)
+{
+ struct scan_field field;
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+ jtag_add_runtest(3, TAP_IDLE);
+ free(t);
+ return ERROR_OK;
+}
+
+static int gowin_read_register(struct jtag_tap *tap, uint32_t reg, uint32_t *result)
+{
+ struct scan_field field;
+
+ int retval = gowin_set_instr(tap, reg);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint8_t buf[4] = {0};
+ field.check_mask = NULL;
+ field.check_value = NULL;
+ field.num_bits = 32;
+ field.out_value = buf;
+ field.in_value = buf;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ *result = le_to_h_u32(buf);
+ return retval;
+}
+
+static int gowin_check_status_flag(struct jtag_tap *tap, uint32_t mask, uint32_t flag)
+{
+ uint32_t status = 0;
+
+ int retries = 0;
+ do {
+ int retval = gowin_read_register(tap, STATUS_REGISTER, &status);
+ if (retval != ERROR_OK)
+ return retval;
+ if (retries++ == 100000)
+ return ERROR_FAIL;
+ } while ((status & mask) != flag);
+
+ return ERROR_OK;
+}
+
+static int gowin_enable_config(struct jtag_tap *tap)
+{
+ int retval = gowin_set_instr(tap, CONFIG_ENABLE);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, STAUS_MASK_SYSTEM_EDIT_MODE);
+}
+
+static int gowin_disable_config(struct jtag_tap *tap)
+{
+ int retval = gowin_set_instr(tap, CONFIG_DISABLE);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, 0);
+}
+
+static int gowin_reload(struct jtag_tap *tap)
+{
+ int retval = gowin_set_instr(tap, RELOAD);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = gowin_set_instr(tap, NO_OP);
+ if (retval != ERROR_OK)
+ return retval;
+ return jtag_execute_queue();
+}
+
+static int gowin_runtest_idle(struct jtag_tap *tap, unsigned int frac_sec)
+{
+ int speed = adapter_get_speed_khz() * 1000;
+ int cycles = DIV_ROUND_UP(speed, frac_sec);
+ jtag_add_runtest(cycles, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+static int gowin_erase_sram(struct jtag_tap *tap, bool tx_erase_done)
+{
+ /* config is already enabled */
+ int retval = gowin_set_instr(tap, ERASE_SRAM);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = gowin_set_instr(tap, NO_OP);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Delay or Run Test 2~10ms */
+ /* 10 ms is worst case for GW2A-55 */
+ jtag_add_sleep(10000);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = gowin_check_status_flag(tap, STAUS_MASK_MEMORY_ERASE,
+ STAUS_MASK_MEMORY_ERASE);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (tx_erase_done) {
+ retval = gowin_set_instr(tap, SRAM_ERASE_DONE);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = gowin_set_instr(tap, NO_OP);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ /* gen clock cycles in RUN/IDLE for 500us -> 1/500us = 2000/s */
+ retval = gowin_runtest_idle(tap, 2000);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ retval = gowin_set_instr(tap, NO_OP);
+ if (retval != ERROR_OK)
+ return retval;
+ return jtag_execute_queue();
+}
+
+static int gowin_load_to_sram(struct pld_device *pld_device, const char *filename)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct gowin_pld_device *gowin_info = pld_device->driver_priv;
+
+ if (!gowin_info || !gowin_info->tap)
+ return ERROR_FAIL;
+ struct jtag_tap *tap = gowin_info->tap;
+
+ bool is_fs = false;
+ struct gowin_bit_file bit_file;
+ int retval = gowin_read_file(&bit_file, filename, &is_fs);
+ if (retval != ERROR_OK)
+ return retval;
+
+ for (unsigned int i = 0; i < bit_file.raw_file.length; i++)
+ bit_file.raw_file.data[i] = flip_u32(bit_file.raw_file.data[i], 8);
+
+ uint32_t id;
+ retval = gowin_read_register(tap, IDCODE, &id);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ if (is_fs && id != bit_file.id) {
+ free(bit_file.raw_file.data);
+ LOG_ERROR("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.",
+ id, bit_file.id);
+ return ERROR_FAIL;
+ }
+
+ retval = gowin_enable_config(tap);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ retval = gowin_erase_sram(tap, false);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ retval = gowin_set_instr(tap, ADDRESS_INITIALIZATION);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+ retval = gowin_set_instr(tap, TRANSFER_CONFIGURATION_DATA);
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ /* scan out the bitstream */
+ struct scan_field field;
+ field.num_bits = bit_file.raw_file.length * 8;
+ field.out_value = bit_file.raw_file.data;
+ field.in_value = bit_file.raw_file.data;
+ jtag_add_dr_scan(gowin_info->tap, 1, &field, TAP_IDLE);
+ jtag_add_runtest(3, TAP_IDLE);
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ free(bit_file.raw_file.data);
+ return retval;
+ }
+
+ retval = gowin_disable_config(tap);
+ free(bit_file.raw_file.data);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = gowin_set_instr(gowin_info->tap, NO_OP);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = jtag_execute_queue();
+
+ return retval;
+}
+
+static int gowin_read_register_command(struct pld_device *pld_device, uint32_t cmd, uint32_t *value)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct gowin_pld_device *gowin_info = pld_device->driver_priv;
+
+ if (!gowin_info || !gowin_info->tap)
+ return ERROR_FAIL;
+
+ return gowin_read_register(gowin_info->tap, cmd, value);
+}
+
+static int gowin_reload_command(struct pld_device *pld_device)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct gowin_pld_device *gowin_info = pld_device->driver_priv;
+
+ if (!gowin_info || !gowin_info->tap)
+ return ERROR_FAIL;
+
+ return gowin_reload(gowin_info->tap);
+}
+
+COMMAND_HANDLER(gowin_read_status_command_handler)
+{
+ int dev_id;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ uint32_t status = 0;
+ int retval = gowin_read_register_command(device, STATUS_REGISTER, &status);
+
+ if (retval == ERROR_OK)
+ command_print(CMD, "0x%8.8" PRIx32, status);
+
+ return retval;
+}
+
+COMMAND_HANDLER(gowin_read_user_register_command_handler)
+{
+ int dev_id;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ uint32_t user_reg = 0;
+ int retval = gowin_read_register_command(device, READ_USERCODE, &user_reg);
+
+ if (retval == ERROR_OK)
+ command_print(CMD, "0x%8.8" PRIx32, user_reg);
+
+ return retval;
+}
+
+COMMAND_HANDLER(gowin_reload_command_handler)
+{
+ int dev_id;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ return gowin_reload_command(device);
+}
+
+static const struct command_registration gowin_exec_command_handlers[] = {
+ {
+ .name = "read_status",
+ .mode = COMMAND_EXEC,
+ .handler = gowin_read_status_command_handler,
+ .help = "reading status register from FPGA",
+ .usage = "num_pld",
+ }, {
+ .name = "read_user",
+ .mode = COMMAND_EXEC,
+ .handler = gowin_read_user_register_command_handler,
+ .help = "reading user register from FPGA",
+ .usage = "num_pld",
+ }, {
+ .name = "reload",
+ .mode = COMMAND_EXEC,
+ .handler = gowin_reload_command_handler,
+ .help = "reloading bitstream from flash to SRAM",
+ .usage = "num_pld",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration gowin_command_handler[] = {
+ {
+ .name = "gowin",
+ .mode = COMMAND_ANY,
+ .help = "gowin specific commands",
+ .usage = "",
+ .chain = gowin_exec_command_handlers
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+PLD_DEVICE_COMMAND_HANDLER(gowin_pld_device_command)
+{
+ struct jtag_tap *tap;
+
+ struct gowin_pld_device *gowin_info;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ tap = jtag_tap_by_string(CMD_ARGV[1]);
+ if (!tap) {
+ command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+ return ERROR_FAIL;
+ }
+
+ gowin_info = malloc(sizeof(struct gowin_pld_device));
+ if (!gowin_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ gowin_info->tap = tap;
+
+ pld->driver_priv = gowin_info;
+
+ return ERROR_OK;
+}
+
+struct pld_driver gowin_pld = {
+ .name = "gowin",
+ .commands = gowin_command_handler,
+ .pld_device_command = &gowin_pld_device_command,
+ .load = &gowin_load_to_sram,
+};
diff --git a/src/pld/intel.c b/src/pld/intel.c
new file mode 100644
index 0000000..119a569
--- /dev/null
+++ b/src/pld/intel.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#include <helper/system.h>
+#include <helper/log.h>
+
+#include "pld.h"
+#include "raw_bit.h"
+
+#define BYPASS 0x3FF
+
+enum intel_family_e {
+ INTEL_CYCLONEIII,
+ INTEL_CYCLONEIV,
+ INTEL_CYCLONEV,
+ INTEL_CYCLONE10,
+ INTEL_ARRIAII,
+ INTEL_UNKNOWN
+};
+
+struct intel_pld_device {
+ struct jtag_tap *tap;
+ unsigned int boundary_scan_length;
+ int checkpos;
+ enum intel_family_e family;
+};
+
+struct intel_device_parameters_elem {
+ uint32_t id;
+ unsigned int boundary_scan_length;
+ int checkpos;
+ enum intel_family_e family;
+};
+
+static const struct intel_device_parameters_elem intel_device_parameters[] = {
+ {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */
+ {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */
+ {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */
+ {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */
+ {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */
+ {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */
+ {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/
+ {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */
+ {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */
+ {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */
+ {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */
+
+ {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */
+ {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */
+ {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */
+ {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */
+ {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */
+ {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */
+ {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */
+ {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */
+ {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */
+ {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */
+ {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */
+ {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */
+ {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */
+ {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */
+ {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */
+
+ {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */
+ {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23
+ 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */
+ {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23
+ 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35
+ 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */
+ {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */
+ {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31
+ 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31
+ 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */
+ {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23
+ 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */
+ {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */
+ {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27
+ 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27
+ 5CGTFD5CU19 */
+ {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19
+ 5CSXFC2C6U23 */
+ {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23
+ 5CGXBC4CF27 5CGXFC4CF23 */
+ {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23
+ 5CEFA9F23 */
+ {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */
+ {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27
+ 5CEFA7M15 5CEBA7U19 5CEBA7F31 */
+ {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */
+
+ {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */
+ {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */
+ {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */
+ {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */
+ {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */
+ {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */
+ {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */
+
+ {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */
+ {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */
+ {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */
+ {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */
+
+ {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */
+ {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */
+ {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */
+ {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */
+ {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */
+ {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */
+ {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */
+ {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */
+ {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */
+};
+
+static int intel_fill_device_parameters(struct intel_pld_device *intel_info)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) {
+ if (intel_device_parameters[i].id == intel_info->tap->idcode &&
+ intel_info->family == intel_device_parameters[i].family) {
+ if (intel_info->boundary_scan_length == 0)
+ intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length;
+
+ if (intel_info->checkpos == -1)
+ intel_info->checkpos = intel_device_parameters[i].checkpos;
+
+ return ERROR_OK;
+ }
+ }
+
+ return ERROR_FAIL;
+}
+
+static int intel_check_for_unique_id(struct intel_pld_device *intel_info)
+{
+ int found = 0;
+ for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) {
+ if (intel_device_parameters[i].id == intel_info->tap->idcode) {
+ ++found;
+ intel_info->family = intel_device_parameters[i].family;
+ }
+ }
+
+ return (found == 1) ? ERROR_OK : ERROR_FAIL;
+}
+
+static int intel_check_config(struct intel_pld_device *intel_info)
+{
+ if (!intel_info->tap->hasidcode) {
+ LOG_ERROR("no IDCODE");
+ return ERROR_FAIL;
+ }
+
+ if (intel_info->family == INTEL_UNKNOWN) {
+ if (intel_check_for_unique_id(intel_info) != ERROR_OK) {
+ LOG_ERROR("id is ambiguous, please specify family");
+ return ERROR_FAIL;
+ }
+ }
+
+ if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) {
+ int ret = intel_fill_device_parameters(intel_info);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) {
+ LOG_ERROR("checkpos has to be smaller than scan length %d < %u",
+ intel_info->checkpos, intel_info->boundary_scan_length);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int intel_read_file(struct raw_bit_file *bit_file, const char *filename)
+{
+ if (!filename || !bit_file)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* check if binary .bin or ascii .bit/.hex */
+ const char *file_ending_pos = strrchr(filename, '.');
+ if (!file_ending_pos) {
+ LOG_ERROR("Unable to detect filename suffix");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (strcasecmp(file_ending_pos, ".rbf") == 0)
+ return cpld_read_raw_bit_file(bit_file, filename);
+
+ LOG_ERROR("Unable to detect filetype");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+}
+
+static int intel_set_instr(struct jtag_tap *tap, uint16_t new_instr)
+{
+ struct scan_field field;
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+ free(t);
+ return ERROR_OK;
+}
+
+
+static int intel_load(struct pld_device *pld_device, const char *filename)
+{
+ unsigned int speed = adapter_get_speed_khz();
+ if (speed < 1)
+ speed = 1;
+
+ unsigned int cycles = DIV_ROUND_UP(speed, 200);
+ if (cycles < 1)
+ cycles = 1;
+
+ if (!pld_device || !pld_device->driver_priv)
+ return ERROR_FAIL;
+
+ struct intel_pld_device *intel_info = pld_device->driver_priv;
+ if (!intel_info || !intel_info->tap)
+ return ERROR_FAIL;
+ struct jtag_tap *tap = intel_info->tap;
+
+ int retval = intel_check_config(intel_info);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct raw_bit_file bit_file;
+ retval = intel_read_file(&bit_file, filename);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = intel_set_instr(tap, 0x002);
+ if (retval != ERROR_OK) {
+ free(bit_file.data);
+ return retval;
+ }
+ jtag_add_runtest(speed, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ free(bit_file.data);
+ return retval;
+ }
+
+ /* shift in the bitstream */
+ struct scan_field field;
+ field.num_bits = bit_file.length * 8;
+ field.out_value = bit_file.data;
+ field.in_value = NULL;
+
+ jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE);
+ retval = jtag_execute_queue();
+ free(bit_file.data);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = intel_set_instr(tap, 0x004);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(cycles, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (intel_info->boundary_scan_length != 0) {
+ uint8_t *buf = calloc(DIV_ROUND_UP(intel_info->boundary_scan_length, 8), 1);
+ if (!buf) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ field.num_bits = intel_info->boundary_scan_length;
+ field.out_value = buf;
+ field.in_value = buf;
+ jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE);
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ free(buf);
+ return retval;
+ }
+
+ if (intel_info->checkpos != -1)
+ retval = ((buf[intel_info->checkpos / 8] & (1 << (intel_info->checkpos % 8)))) ?
+ ERROR_OK : ERROR_FAIL;
+ free(buf);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Check failed");
+ return ERROR_FAIL;
+ }
+ }
+
+ retval = intel_set_instr(tap, 0x003);
+ if (retval != ERROR_OK)
+ return retval;
+ switch (intel_info->family) {
+ case INTEL_CYCLONEIII:
+ case INTEL_CYCLONEIV:
+ jtag_add_runtest(5 * speed + 512, TAP_IDLE);
+ break;
+ case INTEL_CYCLONEV:
+ jtag_add_runtest(5 * speed + 512, TAP_IDLE);
+ break;
+ case INTEL_CYCLONE10:
+ jtag_add_runtest(DIV_ROUND_UP(512ul * speed, 125ul) + 512, TAP_IDLE);
+ break;
+ case INTEL_ARRIAII:
+ jtag_add_runtest(DIV_ROUND_UP(64ul * speed, 125ul) + 512, TAP_IDLE);
+ break;
+ case INTEL_UNKNOWN:
+ LOG_ERROR("unknown family");
+ return ERROR_FAIL;
+ }
+
+ retval = intel_set_instr(tap, BYPASS);
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_runtest(speed, TAP_IDLE);
+ return jtag_execute_queue();
+}
+
+COMMAND_HANDLER(intel_set_bscan_command_handler)
+{
+ int dev_id;
+ unsigned int boundary_scan_length;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *pld_device = get_pld_device_by_num(dev_id);
+ if (!pld_device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], boundary_scan_length);
+
+ struct intel_pld_device *intel_info = pld_device->driver_priv;
+
+ if (!intel_info)
+ return ERROR_FAIL;
+
+ intel_info->boundary_scan_length = boundary_scan_length;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(intel_set_check_pos_command_handler)
+{
+ int dev_id;
+ int checkpos;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *pld_device = get_pld_device_by_num(dev_id);
+ if (!pld_device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], checkpos);
+
+ struct intel_pld_device *intel_info = pld_device->driver_priv;
+
+ if (!intel_info)
+ return ERROR_FAIL;
+
+ intel_info->checkpos = checkpos;
+
+ return ERROR_OK;
+}
+
+
+PLD_DEVICE_COMMAND_HANDLER(intel_pld_device_command)
+{
+ if (CMD_ARGC < 2 || CMD_ARGC > 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]);
+ if (!tap) {
+ command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+ return ERROR_FAIL;
+ }
+
+ struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device));
+ if (!intel_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ enum intel_family_e family = INTEL_UNKNOWN;
+
+ if (CMD_ARGC == 3) {
+ if (strcmp(CMD_ARGV[2], "cycloneiii") == 0) {
+ family = INTEL_CYCLONEIII;
+ } else if (strcmp(CMD_ARGV[2], "cycloneiv") == 0) {
+ family = INTEL_CYCLONEIV;
+ } else if (strcmp(CMD_ARGV[2], "cyclonev") == 0) {
+ family = INTEL_CYCLONEV;
+ } else if (strcmp(CMD_ARGV[2], "cyclone10") == 0) {
+ family = INTEL_CYCLONE10;
+ } else if (strcmp(CMD_ARGV[2], "arriaii") == 0) {
+ family = INTEL_ARRIAII;
+ } else {
+ command_print(CMD, "unknown family");
+ free(intel_info);
+ return ERROR_FAIL;
+ }
+ }
+ intel_info->tap = tap;
+ intel_info->boundary_scan_length = 0;
+ intel_info->checkpos = -1;
+ intel_info->family = family;
+
+ pld->driver_priv = intel_info;
+
+ return ERROR_OK;
+}
+
+static const struct command_registration intel_exec_command_handlers[] = {
+ {
+ .name = "set_bscan",
+ .mode = COMMAND_EXEC,
+ .handler = intel_set_bscan_command_handler,
+ .help = "set boundary scan register length of FPGA",
+ .usage = "num_pld len",
+ }, {
+ .name = "set_check_pos",
+ .mode = COMMAND_EXEC,
+ .handler = intel_set_check_pos_command_handler,
+ .help = "set check_pos of FPGA",
+ .usage = "num_pld pos",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration intel_command_handler[] = {
+ {
+ .name = "intel",
+ .mode = COMMAND_ANY,
+ .help = "intel specific commands",
+ .usage = "",
+ .chain = intel_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct pld_driver intel_pld = {
+ .name = "intel",
+ .commands = intel_command_handler,
+ .pld_device_command = &intel_pld_device_command,
+ .load = &intel_load,
+};
diff --git a/src/pld/lattice.c b/src/pld/lattice.c
new file mode 100644
index 0000000..4ab5f63
--- /dev/null
+++ b/src/pld/lattice.c
@@ -0,0 +1,529 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+#include <jtag/jtag.h>
+#include "pld.h"
+#include "lattice_bit.h"
+#include "ecp2_3.h"
+#include "ecp5.h"
+#include "certus.h"
+
+#define PRELOAD 0x1C
+
+struct lattice_devices_elem {
+ uint32_t id;
+ size_t preload_length;
+ enum lattice_family_e family;
+};
+
+static const struct lattice_devices_elem lattice_devices[] = {
+ {0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */},
+ {0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */},
+ {0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */},
+ {0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */},
+ {0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */},
+ {0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */},
+ {0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */},
+ {0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */},
+ {0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */},
+ {0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */},
+ {0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */},
+ {0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/},
+ {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/},
+ {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/},
+ {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/},
+ {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */},
+ {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */},
+ {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */},
+ {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */},
+ {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */},
+ {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */},
+ {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */},
+ {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */},
+ {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */},
+ {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */},
+ {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */},
+ {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */},
+ {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */},
+};
+
+int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate)
+{
+ struct scan_field field;
+ field.num_bits = tap->ir_length;
+ void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+ jtag_add_ir_scan(tap, &field, endstate);
+ free(t);
+ return ERROR_OK;
+}
+
+static int lattice_check_device_family(struct lattice_pld_device *lattice_device)
+{
+ if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0)
+ return ERROR_OK;
+
+ if (!lattice_device->tap || !lattice_device->tap->hasidcode)
+ return ERROR_FAIL;
+
+ for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) {
+ if (lattice_devices[i].id == lattice_device->tap->idcode) {
+ if (lattice_device->family == LATTICE_UNKNOWN)
+ lattice_device->family = lattice_devices[i].family;
+ if (lattice_device->preload_length == 0)
+ lattice_device->preload_length = lattice_devices[i].preload_length;
+ return ERROR_OK;
+ }
+ }
+ LOG_ERROR("Unknown id! Specify family and preload-length manually.");
+ return ERROR_FAIL;
+}
+
+int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val,
+ uint32_t out_val, bool do_idle)
+{
+ struct scan_field field;
+ uint8_t buffer[4];
+
+ int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ if (do_idle) {
+ jtag_add_runtest(2, TAP_IDLE);
+ jtag_add_sleep(1000);
+ }
+
+ h_u32_to_le(buffer, out_val);
+ field.num_bits = 32;
+ field.out_value = buffer;
+ field.in_value = buffer;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval == ERROR_OK)
+ *in_val = le_to_h_u32(buffer);
+
+ return retval;
+}
+
+int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val,
+ uint64_t out_val)
+{
+ struct scan_field field;
+ uint8_t buffer[8];
+
+ int retval = lattice_set_instr(tap, cmd, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ h_u64_to_le(buffer, out_val);
+ field.num_bits = 64;
+ field.out_value = buffer;
+ field.in_value = buffer;
+ jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ if (retval == ERROR_OK)
+ *in_val = le_to_h_u64(buffer);
+
+ return retval;
+}
+
+int lattice_preload(struct lattice_pld_device *lattice_device)
+{
+ struct scan_field field;
+ size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8);
+
+ int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE);
+ if (retval != ERROR_OK)
+ return retval;
+ uint8_t *buffer = malloc(sz_bytes);
+ if (!buffer) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ memset(buffer, 0xff, sz_bytes);
+
+ field.num_bits = lattice_device->preload_length;
+ field.out_value = buffer;
+ field.in_value = NULL;
+ jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE);
+ retval = jtag_execute_queue();
+ free(buffer);
+ return retval;
+}
+
+static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out)
+{
+ struct jtag_tap *tap = lattice_device->tap;
+ if (!tap)
+ return ERROR_FAIL;
+
+ if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
+ return lattice_ecp2_3_read_usercode(tap, usercode, out);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_read_usercode(tap, usercode, out);
+ else if (lattice_device->family == LATTICE_CERTUS)
+ return lattice_certus_read_usercode(tap, usercode, out);
+
+ return ERROR_FAIL;
+}
+
+int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out,
+ uint32_t expected, uint32_t mask)
+{
+ uint32_t usercode;
+
+ int retval = lattice_read_usercode(lattice_device, &usercode, out);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((usercode & mask) != expected) {
+ LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
+ usercode & mask, expected);
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode)
+{
+ if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
+ return lattice_ecp2_3_write_usercode(lattice_device, usercode);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_write_usercode(lattice_device, usercode);
+ else if (lattice_device->family == LATTICE_CERTUS)
+ return lattice_certus_write_usercode(lattice_device, usercode);
+
+ return ERROR_FAIL;
+}
+
+static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status,
+ uint32_t out, bool do_idle)
+{
+ if (!lattice_device->tap)
+ return ERROR_FAIL;
+
+ if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3)
+ return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle);
+ else if (lattice_device->family == LATTICE_ECP5)
+ return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle);
+
+ return ERROR_FAIL;
+}
+static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, uint64_t *status,
+ uint64_t out)
+{
+ if (!lattice_device->tap)
+ return ERROR_FAIL;
+
+ if (lattice_device->family == LATTICE_CERTUS)
+ return lattice_certus_read_status(lattice_device->tap, status, out);
+
+ return ERROR_FAIL;
+}
+
+int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out,
+ uint32_t expected, uint32_t mask, bool do_idle)
+{
+ uint32_t status;
+ int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((status & mask) != expected) {
+ LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32,
+ status & mask, expected);
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out,
+ uint64_t expected, uint64_t mask)
+{
+ uint64_t status;
+ int retval = lattice_read_status_u64(lattice_device, &status, out);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if ((status & mask) != expected) {
+ LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 " expected: 0x%08" PRIx64,
+ status & mask, expected);
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+static int lattice_load_command(struct pld_device *pld_device, const char *filename)
+{
+ if (!pld_device)
+ return ERROR_FAIL;
+
+ struct lattice_pld_device *lattice_device = pld_device->driver_priv;
+ if (!lattice_device || !lattice_device->tap)
+ return ERROR_FAIL;
+ struct jtag_tap *tap = lattice_device->tap;
+
+ if (!tap || !tap->hasidcode)
+ return ERROR_FAIL;
+
+ int retval = lattice_check_device_family(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ struct lattice_bit_file bit_file;
+ retval = lattice_read_file(&bit_file, filename, lattice_device->family);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t id = tap->idcode;
+ retval = ERROR_FAIL;
+ switch (lattice_device->family) {
+ case LATTICE_ECP2:
+ retval = lattice_ecp2_load(lattice_device, &bit_file);
+ break;
+ case LATTICE_ECP3:
+ retval = lattice_ecp3_load(lattice_device, &bit_file);
+ break;
+ case LATTICE_ECP5:
+ case LATTICE_CERTUS:
+ if (bit_file.has_id && id != bit_file.idcode)
+ LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.",
+ id, bit_file.idcode);
+ if (lattice_device->family == LATTICE_ECP5)
+ retval = lattice_ecp5_load(lattice_device, &bit_file);
+ else
+ retval = lattice_certus_load(lattice_device, &bit_file);
+ break;
+ default:
+ LOG_ERROR("loading unknown device family");
+ break;
+ }
+ free(bit_file.raw_bit.data);
+ return retval;
+}
+
+PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command)
+{
+ if (CMD_ARGC < 2 || CMD_ARGC > 3)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]);
+ if (!tap) {
+ command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]);
+ return ERROR_FAIL;
+ }
+
+ struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device));
+ if (!lattice_device) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+ /* id is not known yet -> postpone lattice_check_device_family() */
+ enum lattice_family_e family = LATTICE_UNKNOWN;
+ if (CMD_ARGC == 3) {
+ if (strcasecmp(CMD_ARGV[2], "ecp2") == 0) {
+ family = LATTICE_ECP2;
+ } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) {
+ family = LATTICE_ECP3;
+ } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) {
+ family = LATTICE_ECP5;
+ } else if (strcasecmp(CMD_ARGV[2], "certus") == 0) {
+ family = LATTICE_CERTUS;
+ } else {
+ command_print(CMD, "unknown family");
+ free(lattice_device);
+ return ERROR_FAIL;
+ }
+ }
+ lattice_device->tap = tap;
+ lattice_device->family = family;
+ lattice_device->preload_length = 0;
+
+ pld->driver_priv = lattice_device;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(lattice_read_usercode_register_command_handler)
+{
+ int dev_id;
+ uint32_t usercode;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ struct lattice_pld_device *lattice_device = device->driver_priv;
+ if (!lattice_device)
+ return ERROR_FAIL;
+
+ int retval = lattice_check_device_family(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = lattice_read_usercode(lattice_device, &usercode, 0x0);
+ if (retval == ERROR_OK)
+ command_print(CMD, "0x%8.8" PRIx32, usercode);
+
+ return retval;
+}
+
+COMMAND_HANDLER(lattice_set_preload_command_handler)
+{
+ int dev_id;
+ unsigned int preload_length;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length);
+
+ struct lattice_pld_device *lattice_device = device->driver_priv;
+
+ if (!lattice_device)
+ return ERROR_FAIL;
+
+ lattice_device->preload_length = preload_length;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(lattice_write_usercode_register_command_handler)
+{
+ int dev_id;
+ uint32_t usercode;
+
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode);
+
+ struct lattice_pld_device *lattice_device = device->driver_priv;
+ if (!lattice_device)
+ return ERROR_FAIL;
+
+ int retval = lattice_check_device_family(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return lattice_write_usercode(lattice_device, usercode);
+}
+
+COMMAND_HANDLER(lattice_read_status_command_handler)
+{
+ int dev_id;
+
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id);
+ struct pld_device *device = get_pld_device_by_num(dev_id);
+ if (!device) {
+ command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]);
+ return ERROR_FAIL;
+ }
+
+ struct lattice_pld_device *lattice_device = device->driver_priv;
+ if (!lattice_device)
+ return ERROR_FAIL;
+
+ int retval = lattice_check_device_family(lattice_device);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (lattice_device->family == LATTICE_CERTUS) {
+ uint64_t status;
+ retval = lattice_read_status_u64(lattice_device, &status, 0x0);
+ if (retval == ERROR_OK)
+ command_print(CMD, "0x%016" PRIx64, status);
+ } else {
+ uint32_t status;
+ const bool do_idle = lattice_device->family == LATTICE_ECP5;
+ retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle);
+ if (retval == ERROR_OK)
+ command_print(CMD, "0x%8.8" PRIx32, status);
+ }
+
+ return retval;
+}
+
+static const struct command_registration lattice_exec_command_handlers[] = {
+ {
+ .name = "read_status",
+ .mode = COMMAND_EXEC,
+ .handler = lattice_read_status_command_handler,
+ .help = "reading status register from FPGA",
+ .usage = "num_pld",
+ }, {
+ .name = "read_user",
+ .mode = COMMAND_EXEC,
+ .handler = lattice_read_usercode_register_command_handler,
+ .help = "reading usercode register from FPGA",
+ .usage = "num_pld",
+ }, {
+ .name = "write_user",
+ .mode = COMMAND_EXEC,
+ .handler = lattice_write_usercode_register_command_handler,
+ .help = "writing usercode register to FPGA",
+ .usage = "num_pld value",
+ }, {
+ .name = "set_preload",
+ .mode = COMMAND_EXEC,
+ .handler = lattice_set_preload_command_handler,
+ .help = "set length for preload (device specific)",
+ .usage = "num_pld value",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration lattice_command_handler[] = {
+ {
+ .name = "lattice",
+ .mode = COMMAND_ANY,
+ .help = "lattice specific commands",
+ .usage = "",
+ .chain = lattice_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct pld_driver lattice_pld = {
+ .name = "lattice",
+ .commands = lattice_command_handler,
+ .pld_device_command = &lattice_pld_device_command,
+ .load = &lattice_load_command,
+};
diff --git a/src/pld/lattice.h b/src/pld/lattice.h
new file mode 100644
index 0000000..9a76a4e
--- /dev/null
+++ b/src/pld/lattice.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_H
+#define OPENOCD_PLD_LATTICE_H
+
+#include <jtag/jtag.h>
+#include "pld.h"
+#include "lattice_bit.h"
+
+#define BYPASS 0xFF
+
+struct lattice_pld_device {
+ struct jtag_tap *tap;
+ size_t preload_length;
+ enum lattice_family_e family;
+};
+
+int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate);
+int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val,
+ uint32_t out_val, bool do_idle);
+int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val,
+ uint64_t out_val);
+int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out,
+ uint32_t expected, uint32_t mask);
+int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out,
+ uint32_t expected, uint32_t mask, bool do_idle);
+int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out,
+ uint64_t expected, uint64_t mask);
+int lattice_preload(struct lattice_pld_device *lattice_device);
+
+#endif /* OPENOCD_PLD_LATTICE_H */
diff --git a/src/pld/lattice_bit.c b/src/pld/lattice_bit.c
new file mode 100644
index 0000000..562b17d
--- /dev/null
+++ b/src/pld/lattice_bit.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "lattice_bit.h"
+#include "raw_bit.h"
+#include "pld.h"
+#include <helper/system.h>
+#include <helper/log.h>
+#include <helper/binarybuffer.h>
+
+enum read_bit_state {
+ SEEK_HEADER_START,
+ SEEK_HEADER_END,
+ SEEK_PREAMBLE,
+ SEEK_ID,
+ DONE,
+};
+
+static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family)
+{
+ int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename);
+ if (retval != ERROR_OK)
+ return retval;
+
+ bit_file->part = 0;
+ bit_file->has_id = false;
+ enum read_bit_state state = SEEK_HEADER_START;
+ for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) {
+ switch (state) {
+ case SEEK_HEADER_START:
+ if (bit_file->raw_bit.data[pos] == 0 && bit_file->raw_bit.data[pos - 1] == 0xff)
+ state = SEEK_HEADER_END;
+ break;
+ case SEEK_HEADER_END:
+ if (pos + 6 < bit_file->raw_bit.length &&
+ strncmp((const char *)(bit_file->raw_bit.data + pos), "Part: ", 6) == 0) {
+ bit_file->part = (const char *)bit_file->raw_bit.data + pos + 6;
+ LOG_INFO("part found: %s\n", bit_file->part);
+ } else if (bit_file->raw_bit.data[pos] == 0xff && bit_file->raw_bit.data[pos - 1] == 0) {
+ bit_file->offset = pos;
+ state = (family != LATTICE_ECP2 && family != LATTICE_ECP3) ? SEEK_PREAMBLE : DONE;
+ }
+ break;
+ case SEEK_PREAMBLE:
+ if (pos >= 4) {
+ uint32_t preamble = be_to_h_u32(bit_file->raw_bit.data + pos - 3);
+ switch (preamble) {
+ case 0xffffbdb3:
+ state = SEEK_ID;
+ break;
+ case 0xffffbfb3:
+ case 0xffffbeb3:
+ state = DONE;
+ break;
+ }
+ }
+ break;
+ case SEEK_ID:
+ if (pos + 7 < bit_file->raw_bit.length && bit_file->raw_bit.data[pos] == 0xe2) {
+ bit_file->idcode = be_to_h_u32(&bit_file->raw_bit.data[pos + 4]);
+ bit_file->has_id = true;
+ state = DONE;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (state != DONE) {
+ LOG_ERROR("parsing bitstream failed");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ for (size_t i = bit_file->offset; i < bit_file->raw_bit.length; i++)
+ bit_file->raw_bit.data[i] = flip_u32(bit_file->raw_bit.data[i], 8);
+
+ return ERROR_OK;
+}
+
+int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family)
+{
+ if (!filename || !bit_file)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* check if binary .bin or ascii .bit/.hex */
+ const char *file_suffix_pos = strrchr(filename, '.');
+ if (!file_suffix_pos) {
+ LOG_ERROR("Unable to detect filename suffix");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (strcasecmp(file_suffix_pos, ".bit") == 0)
+ return lattice_read_bit_file(bit_file, filename, family);
+
+ LOG_ERROR("Filetype not supported");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+}
diff --git a/src/pld/lattice_bit.h b/src/pld/lattice_bit.h
new file mode 100644
index 0000000..33f1b34
--- /dev/null
+++ b/src/pld/lattice_bit.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_BIT_H
+#define OPENOCD_PLD_LATTICE_BIT_H
+
+#include "helper/types.h"
+#include "raw_bit.h"
+
+
+struct lattice_bit_file {
+ struct raw_bit_file raw_bit;
+ size_t offset;
+ uint32_t idcode;
+ const char *part; /* reuses memory in raw_bit_file */
+ bool has_id;
+};
+
+enum lattice_family_e {
+ LATTICE_ECP2,
+ LATTICE_ECP3,
+ LATTICE_ECP5,
+ LATTICE_CERTUS,
+ LATTICE_UNKNOWN,
+};
+
+int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family);
+
+#endif /* OPENOCD_PLD_LATTICE_BIT_H */
diff --git a/src/pld/lattice_cmd.h b/src/pld/lattice_cmd.h
new file mode 100644
index 0000000..8d66ac4
--- /dev/null
+++ b/src/pld/lattice_cmd.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_CMD_H
+#define OPENOCD_PLD_LATTICE_CMD_H
+
+#define ISC_ERASE 0x0E
+#define ISC_DISABLE 0x26
+#define LSC_READ_STATUS 0x3C
+#define LSC_INIT_ADDRESS 0x46
+#define LSC_BITSTREAM_BURST 0x7A
+#define READ_USERCODE 0xC0
+#define ISC_ENABLE 0xC6
+
+#endif /* OPENOCD_PLD_LATTICE_CMD_H */
diff --git a/src/pld/pld.c b/src/pld/pld.c
index e2e0ef4..7dd2cec 100644
--- a/src/pld/pld.c
+++ b/src/pld/pld.c
@@ -10,16 +10,18 @@
#endif
#include "pld.h"
+#include <sys/stat.h>
#include <helper/log.h>
#include <helper/replacements.h>
#include <helper/time_support.h>
-/* pld drivers
- */
-extern struct pld_driver virtex2_pld;
-
static struct pld_driver *pld_drivers[] = {
+ &efinix_pld,
+ &gatemate_pld,
+ &gowin_pld,
+ &intel_pld,
+ &lattice_pld,
&virtex2_pld,
NULL,
};
@@ -134,6 +136,22 @@ COMMAND_HANDLER(handle_pld_load_command)
return ERROR_OK;
}
+ struct stat input_stat;
+ if (stat(CMD_ARGV[1], &input_stat) == -1) {
+ LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (S_ISDIR(input_stat.st_mode)) {
+ LOG_ERROR("%s is a directory", CMD_ARGV[1]);
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ if (input_stat.st_size == 0) {
+ LOG_ERROR("Empty file %s", CMD_ARGV[1]);
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
retval = p->driver->load(p, CMD_ARGV[1]);
if (retval != ERROR_OK) {
command_print(CMD, "failed loading file %s to pld device %u",
diff --git a/src/pld/pld.h b/src/pld/pld.h
index a7cd20f..322b96e 100644
--- a/src/pld/pld.h
+++ b/src/pld/pld.h
@@ -38,4 +38,11 @@ struct pld_device *get_pld_device_by_num(int num);
#define ERROR_PLD_DEVICE_INVALID (-1000)
#define ERROR_PLD_FILE_LOAD_FAILED (-1001)
+extern struct pld_driver efinix_pld;
+extern struct pld_driver gatemate_pld;
+extern struct pld_driver gowin_pld;
+extern struct pld_driver intel_pld;
+extern struct pld_driver lattice_pld;
+extern struct pld_driver virtex2_pld;
+
#endif /* OPENOCD_PLD_PLD_H */
diff --git a/src/pld/raw_bit.c b/src/pld/raw_bit.c
new file mode 100644
index 0000000..0c3b92e
--- /dev/null
+++ b/src/pld/raw_bit.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "raw_bit.h"
+#include "pld.h"
+
+#include <helper/system.h>
+#include <helper/log.h>
+
+
+int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename)
+{
+ FILE *input_file = fopen(filename, "rb");
+
+ if (!input_file) {
+ LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ fseek(input_file, 0, SEEK_END);
+ long length = ftell(input_file);
+ fseek(input_file, 0, SEEK_SET);
+
+ if (length < 0) {
+ fclose(input_file);
+ LOG_ERROR("Failed to get length of file %s: %s", filename, strerror(errno));
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+ bit_file->length = (size_t)length;
+
+ bit_file->data = malloc(bit_file->length);
+ if (!bit_file->data) {
+ fclose(input_file);
+ LOG_ERROR("Out of memory");
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ size_t read_count = fread(bit_file->data, sizeof(char), bit_file->length, input_file);
+ fclose(input_file);
+ if (read_count != bit_file->length) {
+ free(bit_file->data);
+ bit_file->data = NULL;
+ return ERROR_PLD_FILE_LOAD_FAILED;
+ }
+
+ return ERROR_OK;
+}
diff --git a/src/pld/raw_bit.h b/src/pld/raw_bit.h
new file mode 100644
index 0000000..583ff76
--- /dev/null
+++ b/src/pld/raw_bit.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2022 by Daniel Anselmi *
+ * danselmi@gmx.ch *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_RAW_BIN_H
+#define OPENOCD_PLD_RAW_BIN_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct raw_bit_file {
+ size_t length;
+ uint8_t *data;
+};
+
+int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename);
+
+#endif /* OPENOCD_PLD_RAW_BIN_H */
diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c
index 98fd58a..3c174ae 100644
--- a/src/pld/virtex2.c
+++ b/src/pld/virtex2.c
@@ -23,6 +23,10 @@ static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr)
field.num_bits = tap->ir_length;
void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1);
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
field.out_value = t;
buf_set_u32(t, 0, field.num_bits, new_instr);
field.in_value = NULL;
@@ -44,6 +48,10 @@ static int virtex2_send_32(struct pld_device *pld_device,
int i;
values = malloc(num_words * 4);
+ if (!values) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
scan_field.num_bits = num_words * 32;
scan_field.out_value = values;
@@ -52,7 +60,11 @@ static int virtex2_send_32(struct pld_device *pld_device,
for (i = 0; i < num_words; i++)
buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32));
- virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */
+ int retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */
+ if (retval != ERROR_OK) {
+ free(values);
+ return retval;
+ }
jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE);
@@ -77,7 +89,9 @@ static int virtex2_receive_32(struct pld_device *pld_device,
scan_field.out_value = NULL;
scan_field.in_value = NULL;
- virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */
+ int retval = virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */
+ if (retval != ERROR_OK)
+ return retval;
while (num_words--) {
scan_field.in_value = (uint8_t *)words;
@@ -103,15 +117,72 @@ static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status)
data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */
data[3] = 0x20000000; /* NOOP */
data[4] = 0x20000000; /* NOOP */
- virtex2_send_32(pld_device, 5, data);
+ int retval = virtex2_send_32(pld_device, 5, data);
+ if (retval != ERROR_OK)
+ return retval;
- virtex2_receive_32(pld_device, 1, status);
+ retval = virtex2_receive_32(pld_device, 1, status);
+ if (retval != ERROR_OK)
+ return retval;
- jtag_execute_queue();
+ retval = jtag_execute_queue();
+ if (retval == ERROR_OK)
+ LOG_DEBUG("status: 0x%8.8" PRIx32, *status);
- LOG_DEBUG("status: 0x%8.8" PRIx32 "", *status);
+ return retval;
+}
- return ERROR_OK;
+static int virtex2_load_prepare(struct pld_device *pld_device)
+{
+ struct virtex2_pld_device *virtex2_info = pld_device->driver_priv;
+ int retval;
+
+ retval = virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+ jtag_add_sleep(1000);
+
+ retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */
+ if (retval != ERROR_OK)
+ return retval;
+
+ return jtag_execute_queue();
+}
+
+static int virtex2_load_cleanup(struct pld_device *pld_device)
+{
+ struct virtex2_pld_device *virtex2_info = pld_device->driver_priv;
+ int retval;
+
+ jtag_add_tlr();
+
+ if (!(virtex2_info->no_jstart)) {
+ retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ jtag_add_runtest(13, TAP_IDLE);
+ retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
+ if (retval != ERROR_OK)
+ return retval;
+ retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
+ if (retval != ERROR_OK)
+ return retval;
+ if (!(virtex2_info->no_jstart)) {
+ retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */
+ if (retval != ERROR_OK)
+ return retval;
+ }
+ jtag_add_runtest(13, TAP_IDLE);
+ retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
+ if (retval != ERROR_OK)
+ return retval;
+
+ return jtag_execute_queue();
}
static int virtex2_load(struct pld_device *pld_device, const char *filename)
@@ -128,12 +199,11 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename)
if (retval != ERROR_OK)
return retval;
- virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */
- jtag_execute_queue();
- jtag_add_sleep(1000);
-
- virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */
- jtag_execute_queue();
+ retval = virtex2_load_prepare(pld_device);
+ if (retval != ERROR_OK) {
+ xilinx_free_bit_file(&bit_file);
+ return retval;
+ }
for (i = 0; i < bit_file.length; i++)
bit_file.data[i] = flip_u32(bit_file.data[i], 8);
@@ -142,24 +212,17 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename)
field.out_value = bit_file.data;
jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE);
- jtag_execute_queue();
-
- jtag_add_tlr();
+ retval = jtag_execute_queue();
+ if (retval != ERROR_OK) {
+ xilinx_free_bit_file(&bit_file);
+ return retval;
+ }
- if (!(virtex2_info->no_jstart))
- virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */
- jtag_add_runtest(13, TAP_IDLE);
- virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
- virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
- if (!(virtex2_info->no_jstart))
- virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */
- jtag_add_runtest(13, TAP_IDLE);
- virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */
- jtag_execute_queue();
+ retval = virtex2_load_cleanup(pld_device);
xilinx_free_bit_file(&bit_file);
- return ERROR_OK;
+ return retval;
}
COMMAND_HANDLER(virtex2_handle_read_stat_command)
@@ -201,6 +264,10 @@ PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command)
}
virtex2_info = malloc(sizeof(struct virtex2_pld_device));
+ if (!virtex2_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
virtex2_info->tap = tap;
virtex2_info->no_jstart = 0;
diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c
index 792b337..e4cc52e 100644
--- a/src/pld/xilinx_bit.c
+++ b/src/pld/xilinx_bit.c
@@ -13,7 +13,6 @@
#include "pld.h"
#include <helper/log.h>
-#include <sys/stat.h>
#include <helper/system.h>
static int read_section(FILE *input_file, int length_size, char section,
@@ -60,27 +59,11 @@ static int read_section(FILE *input_file, int length_size, char section,
int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename)
{
FILE *input_file;
- struct stat input_stat;
int read_count;
if (!filename || !bit_file)
return ERROR_COMMAND_SYNTAX_ERROR;
- if (stat(filename, &input_stat) == -1) {
- LOG_ERROR("couldn't stat() %s: %s", filename, strerror(errno));
- return ERROR_PLD_FILE_LOAD_FAILED;
- }
-
- if (S_ISDIR(input_stat.st_mode)) {
- LOG_ERROR("%s is a directory", filename);
- return ERROR_PLD_FILE_LOAD_FAILED;
- }
-
- if (input_stat.st_size == 0) {
- LOG_ERROR("Empty file %s", filename);
- return ERROR_PLD_FILE_LOAD_FAILED;
- }
-
input_file = fopen(filename, "rb");
if (!input_file) {
LOG_ERROR("couldn't open %s: %s", filename, strerror(errno));
diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c
index 68fe8a1..2037827 100644
--- a/src/rtos/chibios.c
+++ b/src/rtos/chibios.c
@@ -80,12 +80,12 @@ struct chibios_params {
static struct chibios_params chibios_params_list[] = {
{
"cortex_m", /* target_name */
- 0,
+ NULL,
NULL, /* stacking_info */
},
{
"hla_target", /* target_name */
- 0,
+ NULL,
NULL, /* stacking_info */
}
};
@@ -198,7 +198,7 @@ static int chibios_update_memory_signature(struct rtos *rtos)
errfree:
/* Error reading the ChibiOS memory structure */
free(signature);
- param->signature = 0;
+ param->signature = NULL;
return -1;
}
@@ -468,7 +468,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
return -1;
/* Update stacking if it can only be determined from runtime information */
- if ((param->stacking_info == 0) &&
+ if (!param->stacking_info &&
(chibios_update_stacking(rtos) != ERROR_OK)) {
LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name);
return -1;
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
index f9edabc..7517ec7 100644
--- a/src/rtos/linux.c
+++ b/src/rtos/linux.c
@@ -123,7 +123,7 @@ static int linux_read_memory(struct target *target,
target->rtos->rtos_specific_params;
uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base;
#endif
- if (address < 0xc000000) {
+ if (address < 0xc0000000) {
LOG_ERROR("linux awareness : address in user space");
return ERROR_FAIL;
}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index c3870b7..b4f6a1f 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -16,22 +16,6 @@
#include "helper/binarybuffer.h"
#include "server/gdb_server.h"
-/* RTOSs */
-extern const struct rtos_type freertos_rtos;
-extern const struct rtos_type threadx_rtos;
-extern const struct rtos_type ecos_rtos;
-extern const struct rtos_type linux_rtos;
-extern const struct rtos_type chibios_rtos;
-extern const struct rtos_type chromium_ec_rtos;
-extern const struct rtos_type embkernel_rtos;
-extern const struct rtos_type mqx_rtos;
-extern const struct rtos_type ucos_iii_rtos;
-extern const struct rtos_type nuttx_rtos;
-extern const struct rtos_type hwthread_rtos;
-extern const struct rtos_type riot_rtos;
-extern const struct rtos_type zephyr_rtos;
-extern const struct rtos_type rtkernel_rtos;
-
static const struct rtos_type *rtos_types[] = {
&threadx_rtos,
&freertos_rtos,
diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h
index f36288d..1ec7674 100644
--- a/src/rtos/rtos.h
+++ b/src/rtos/rtos.h
@@ -173,4 +173,19 @@ struct target *rtos_swbp_target(struct target *target, target_addr_t address,
uint32_t length, enum breakpoint_type type);
struct rtos *rtos_of_target(struct target *target);
+extern const struct rtos_type chibios_rtos;
+extern const struct rtos_type chromium_ec_rtos;
+extern const struct rtos_type ecos_rtos;
+extern const struct rtos_type embkernel_rtos;
+extern const struct rtos_type freertos_rtos;
+extern const struct rtos_type hwthread_rtos;
+extern const struct rtos_type linux_rtos;
+extern const struct rtos_type mqx_rtos;
+extern const struct rtos_type nuttx_rtos;
+extern const struct rtos_type riot_rtos;
+extern const struct rtos_type rtkernel_rtos;
+extern const struct rtos_type threadx_rtos;
+extern const struct rtos_type ucos_iii_rtos;
+extern const struct rtos_type zephyr_rtos;
+
#endif /* OPENOCD_RTOS_RTOS_H */
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 45e9829..aa23938 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -2405,6 +2405,7 @@ static int smp_reg_list_noread(struct target *target,
local_list = realloc(local_list, combined_allocated * sizeof(struct reg *));
if (!local_list) {
LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *));
+ free(reg_list);
return ERROR_FAIL;
}
}
diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c
index 755d051..69d0f57 100644
--- a/src/server/ipdbg.c
+++ b/src/server/ipdbg.c
@@ -315,6 +315,10 @@ static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr)
}
uint8_t *ir_out_val = calloc(DIV_ROUND_UP(tap->ir_length, 8), 1);
+ if (!ir_out_val) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
buf_set_u32(ir_out_val, 0, tap->ir_length, instr);
struct scan_field fields;
@@ -344,6 +348,10 @@ static int ipdbg_shift_vir(struct ipdbg_hub *hub)
return ERROR_FAIL;
uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->virtual_ir->length, 8), 1);
+ if (!dr_out_val) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
buf_set_u32(dr_out_val, 0, hub->virtual_ir->length, hub->virtual_ir->value);
struct scan_field fields;
@@ -366,8 +374,21 @@ static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *u
return ERROR_FAIL;
uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1);
+ if (!dr_out_val) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
buf_set_u32(dr_out_val, 0, hub->data_register_length, dn_data);
- uint8_t *dr_in_val = up_data ? calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1) : NULL;
+
+ uint8_t *dr_in_val = NULL;
+ if (up_data) {
+ dr_in_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1);
+ if (!dr_in_val) {
+ LOG_ERROR("Out of memory");
+ free(dr_out_val);
+ return ERROR_FAIL;
+ }
+ }
struct scan_field fields;
ipdbg_init_scan_field(&fields, dr_in_val, hub->data_register_length, dr_out_val);
diff --git a/src/target/aarch64.c b/src/target/aarch64.c
index 3c33032..5a16b3a 100644
--- a/src/target/aarch64.c
+++ b/src/target/aarch64.c
@@ -21,6 +21,7 @@
#include "arm_semihosting.h"
#include "jtag/interface.h"
#include "smp.h"
+#include <helper/nvp.h>
#include <helper/time_support.h>
enum restart_mode {
@@ -588,7 +589,7 @@ static int aarch64_restore_one(struct target *target, int current,
resume_pc &= 0xFFFFFFFC;
break;
case ARM_STATE_AARCH64:
- resume_pc &= 0xFFFFFFFFFFFFFFFC;
+ resume_pc &= 0xFFFFFFFFFFFFFFFCULL;
break;
case ARM_STATE_THUMB:
case ARM_STATE_THUMB_EE:
@@ -1066,9 +1067,12 @@ static int aarch64_post_debug_entry(struct target *target)
armv8_identify_cache(armv8);
armv8_read_mpidr(armv8);
}
-
- armv8->armv8_mmu.mmu_enabled =
+ if (armv8->is_armv8r) {
+ armv8->armv8_mmu.mmu_enabled = 0;
+ } else {
+ armv8->armv8_mmu.mmu_enabled =
(aarch64->system_control_reg & 0x1U) ? 1 : 0;
+ }
armv8->armv8_mmu.armv8_cache.d_u_cache_enabled =
(aarch64->system_control_reg & 0x4U) ? 1 : 0;
armv8->armv8_mmu.armv8_cache.i_cache_enabled =
@@ -1245,7 +1249,7 @@ static int aarch64_set_breakpoint(struct target *target,
| (byte_addr_select << 5)
| (3 << 1) | 1;
brp_list[brp_i].used = 1;
- brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC;
+ brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL;
brp_list[brp_i].control = control;
bpt_value = brp_list[brp_i].value;
@@ -1297,28 +1301,28 @@ static int aarch64_set_breakpoint(struct target *target,
buf_set_u32(code, 0, 32, opcode);
retval = target_read_memory(target,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
armv8_cache_d_inner_flush_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
retval = target_write_memory(target,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length, 1, code);
if (retval != ERROR_OK)
return retval;
armv8_cache_d_inner_flush_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
armv8_cache_i_inner_inval_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
breakpoint->is_set = true;
@@ -1450,7 +1454,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin
| (iva_byte_addr_select << 5)
| (3 << 1) | 1;
brp_list[brp_2].used = 1;
- brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC;
+ brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL;
brp_list[brp_2].control = control_iva;
retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base
+ CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn,
@@ -1574,29 +1578,29 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br
/* restore original instruction (kept in target endianness) */
armv8_cache_d_inner_flush_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
if (breakpoint->length == 4) {
retval = target_write_memory(target,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
4, 1, breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
} else {
retval = target_write_memory(target,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
2, 1, breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
}
armv8_cache_d_inner_flush_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
armv8_cache_i_inner_inval_virt(armv8,
- breakpoint->address & 0xFFFFFFFFFFFFFFFE,
+ breakpoint->address & 0xFFFFFFFFFFFFFFFEULL,
breakpoint->length);
}
breakpoint->is_set = false;
@@ -2726,6 +2730,25 @@ static int aarch64_init_arch_info(struct target *target,
return ERROR_OK;
}
+static int armv8r_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct aarch64_private_config *pc = target->private_config;
+ struct aarch64_common *aarch64;
+
+ if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK)
+ return ERROR_FAIL;
+
+ aarch64 = calloc(1, sizeof(struct aarch64_common));
+ if (!aarch64) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ aarch64->armv8_common.is_armv8r = true;
+
+ return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap);
+}
+
static int aarch64_target_create(struct target *target, Jim_Interp *interp)
{
struct aarch64_private_config *pc = target->private_config;
@@ -2740,6 +2763,8 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp)
return ERROR_FAIL;
}
+ aarch64->armv8_common.is_armv8r = false;
+
return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap);
}
@@ -2762,12 +2787,16 @@ static void aarch64_deinit_target(struct target *target)
static int aarch64_mmu(struct target *target, int *enabled)
{
+ struct aarch64_common *aarch64 = target_to_aarch64(target);
+ struct armv8_common *armv8 = &aarch64->armv8_common;
if (target->state != TARGET_HALTED) {
LOG_ERROR("%s: target %s not halted", __func__, target_name(target));
return ERROR_TARGET_INVALID;
}
-
- *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled;
+ if (armv8->is_armv8r)
+ *enabled = 0;
+ else
+ *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled;
return ERROR_OK;
}
@@ -2929,15 +2958,15 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
struct target *target = get_current_target(CMD_CTX);
struct aarch64_common *aarch64 = target_to_aarch64(target);
- static const struct jim_nvp nvp_maskisr_modes[] = {
+ static const struct nvp nvp_maskisr_modes[] = {
{ .name = "off", .value = AARCH64_ISRMASK_OFF },
{ .name = "on", .value = AARCH64_ISRMASK_ON },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]);
if (!n->name) {
LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -2946,7 +2975,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
aarch64->isrmasking_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode);
+ n = nvp_value2name(nvp_maskisr_modes, aarch64->isrmasking_mode);
command_print(CMD, "aarch64 interrupt mask %s", n->name);
return ERROR_OK;
@@ -3165,3 +3194,39 @@ struct target_type aarch64_target = {
.mmu = aarch64_mmu,
.virt2phys = aarch64_virt2phys,
};
+
+struct target_type armv8r_target = {
+ .name = "armv8r",
+
+ .poll = aarch64_poll,
+ .arch_state = armv8_arch_state,
+
+ .halt = aarch64_halt,
+ .resume = aarch64_resume,
+ .step = aarch64_step,
+
+ .assert_reset = aarch64_assert_reset,
+ .deassert_reset = aarch64_deassert_reset,
+
+ /* REVISIT allow exporting VFP3 registers ... */
+ .get_gdb_arch = armv8_get_gdb_arch,
+ .get_gdb_reg_list = armv8_get_gdb_reg_list,
+
+ .read_memory = aarch64_read_phys_memory,
+ .write_memory = aarch64_write_phys_memory,
+
+ .add_breakpoint = aarch64_add_breakpoint,
+ .add_context_breakpoint = aarch64_add_context_breakpoint,
+ .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint,
+ .remove_breakpoint = aarch64_remove_breakpoint,
+ .add_watchpoint = aarch64_add_watchpoint,
+ .remove_watchpoint = aarch64_remove_watchpoint,
+ .hit_watchpoint = aarch64_hit_watchpoint,
+
+ .commands = aarch64_command_handlers,
+ .target_create = armv8r_target_create,
+ .target_jim_configure = aarch64_jim_configure,
+ .init_target = aarch64_init_target,
+ .deinit_target = aarch64_deinit_target,
+ .examine = aarch64_examine,
+};
diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c
index 805330f..3bacfae 100644
--- a/src/target/arm9tdmi.c
+++ b/src/target/arm9tdmi.c
@@ -57,7 +57,7 @@ static const struct arm9tdmi_vector {
{"dabt", ARM9TDMI_DABT_VECTOR},
{"irq", ARM9TDMI_IRQ_VECTOR},
{"fiq", ARM9TDMI_FIQ_VECTOR},
- {0, 0},
+ {NULL, 0},
};
int arm9tdmi_examine_debug_reason(struct target *target)
diff --git a/src/target/armv8.c b/src/target/armv8.c
index ff71a8e..ffed263 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -19,6 +19,7 @@
#include "register.h"
#include <helper/binarybuffer.h>
#include <helper/command.h>
+#include <helper/nvp.h>
#include <stdlib.h>
#include <string.h>
@@ -236,7 +237,7 @@ static int armv8_read_ttbcr(struct target *target)
armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7);
armv8->page_size = (ttbcr_64 >> 14) & 3;
armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0;
- armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF;
+ armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFFULL;
retval += dpm->instr_read_data_r0_64(dpm,
ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0),
&armv8->ttbr_base);
@@ -1043,7 +1044,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
unsigned int argp = 0;
int retval;
- static const struct jim_nvp nvp_ecatch_modes[] = {
+ static const struct nvp nvp_ecatch_modes[] = {
{ .name = "off", .value = 0 },
{ .name = "nsec_el1", .value = (1 << 5) },
{ .name = "nsec_el2", .value = (2 << 5) },
@@ -1053,7 +1054,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
{ .name = "sec_el13", .value = (5 << 1) },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC == 0) {
const char *sec = NULL, *nsec = NULL;
@@ -1063,11 +1064,11 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
if (retval != ERROR_OK)
return retval;
- n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0x0f);
+ n = nvp_value2name(nvp_ecatch_modes, edeccr & 0x0f);
if (n->name)
sec = n->name;
- n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0xf0);
+ n = nvp_value2name(nvp_ecatch_modes, edeccr & 0xf0);
if (n->name)
nsec = n->name;
@@ -1081,7 +1082,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command)
}
while (argp < CMD_ARGC) {
- n = jim_nvp_name2value_simple(nvp_ecatch_modes, CMD_ARGV[argp]);
+ n = nvp_name2value(nvp_ecatch_modes, CMD_ARGV[argp]);
if (!n->name) {
LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]);
return ERROR_FAIL;
diff --git a/src/target/armv8.h b/src/target/armv8.h
index 54aa086..f5aa211 100644
--- a/src/target/armv8.h
+++ b/src/target/armv8.h
@@ -204,6 +204,7 @@ struct armv8_common {
uint8_t pa_size;
uint32_t page_size;
uint64_t ttbr_base;
+ bool is_armv8r;
struct armv8_mmu_common armv8_mmu;
diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c
index f40beb8..d1eefe5 100644
--- a/src/target/armv8_dpm.c
+++ b/src/target/armv8_dpm.c
@@ -274,7 +274,7 @@ static int dpmv8_instr_write_data_dcc(struct arm_dpm *dpm,
if (retval != ERROR_OK)
return retval;
- return dpmv8_exec_opcode(dpm, opcode, 0);
+ return dpmv8_exec_opcode(dpm, opcode, NULL);
}
static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm,
@@ -287,7 +287,7 @@ static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm,
if (retval != ERROR_OK)
return retval;
- return dpmv8_exec_opcode(dpm, opcode, 0);
+ return dpmv8_exec_opcode(dpm, opcode, NULL);
}
static int dpmv8_instr_write_data_r0(struct arm_dpm *dpm,
@@ -587,6 +587,9 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
}
LOG_DEBUG("target_el = %i, last_el = %i", target_el, dpm->last_el);
+ if (dpm->last_el == target_el)
+ return ERROR_OK; /* nothing to do */
+
if (target_el > dpm->last_el) {
retval = dpm->instr_execute(dpm,
armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el);
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 3db9c62..d9688be 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -52,6 +52,7 @@
#include "transport/transport.h"
#include "smp.h"
#include <helper/bits.h>
+#include <helper/nvp.h>
#include <helper/time_support.h>
static int cortex_a_poll(struct target *target);
@@ -3246,15 +3247,15 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command)
struct target *target = get_current_target(CMD_CTX);
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
- static const struct jim_nvp nvp_maskisr_modes[] = {
+ static const struct nvp nvp_maskisr_modes[] = {
{ .name = "off", .value = CORTEX_A_ISRMASK_OFF },
{ .name = "on", .value = CORTEX_A_ISRMASK_ON },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]);
if (!n->name) {
LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -3263,7 +3264,7 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command)
cortex_a->isrmasking_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode);
+ n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode);
command_print(CMD, "cortex_a interrupt mask %s", n->name);
return ERROR_OK;
@@ -3274,22 +3275,22 @@ COMMAND_HANDLER(handle_cortex_a_dacrfixup_command)
struct target *target = get_current_target(CMD_CTX);
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
- static const struct jim_nvp nvp_dacrfixup_modes[] = {
+ static const struct nvp nvp_dacrfixup_modes[] = {
{ .name = "off", .value = CORTEX_A_DACRFIXUP_OFF },
{ .name = "on", .value = CORTEX_A_DACRFIXUP_ON },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]);
if (!n->name)
return ERROR_COMMAND_SYNTAX_ERROR;
cortex_a->dacrfixup_mode = n->value;
}
- n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
+ n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
command_print(CMD, "cortex_a domain access control fixup %s", n->name);
return ERROR_OK;
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index 88e9bb2..8e55014 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -29,6 +29,7 @@
#include "arm_opcodes.h"
#include "arm_semihosting.h"
#include "smp.h"
+#include <helper/nvp.h>
#include <helper/time_support.h>
#include <rtt/rtt.h>
@@ -2935,14 +2936,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command)
struct cortex_m_common *cortex_m = target_to_cm(target);
int retval;
- static const struct jim_nvp nvp_maskisr_modes[] = {
+ static const struct nvp nvp_maskisr_modes[] = {
{ .name = "auto", .value = CORTEX_M_ISRMASK_AUTO },
{ .name = "off", .value = CORTEX_M_ISRMASK_OFF },
{ .name = "on", .value = CORTEX_M_ISRMASK_ON },
{ .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY },
{ .name = NULL, .value = -1 },
};
- const struct jim_nvp *n;
+ const struct nvp *n;
retval = cortex_m_verify_pointer(CMD, cortex_m);
@@ -2955,14 +2956,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command)
}
if (CMD_ARGC > 0) {
- n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+ n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]);
if (!n->name)
return ERROR_COMMAND_SYNTAX_ERROR;
cortex_m->isrmasking_mode = n->value;
cortex_m_set_maskints_for_halt(target);
}
- n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_m->isrmasking_mode);
+ n = nvp_value2name(nvp_maskisr_modes, cortex_m->isrmasking_mode);
command_print(CMD, "cortex_m interrupt mask %s", n->name);
return ERROR_OK;
diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c
index 2244506..866f331 100644
--- a/src/target/dsp563xx_once.c
+++ b/src/target/dsp563xx_once.c
@@ -60,7 +60,7 @@ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t
{
int err;
- err = dsp563xx_write_dr_u8(tap, 0, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0);
+ err = dsp563xx_write_dr_u8(tap, NULL, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0);
if (err != ERROR_OK)
return err;
if (flush)
@@ -226,7 +226,7 @@ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32
err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0);
if (err != ERROR_OK)
return err;
- err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0);
+ err = dsp563xx_write_dr_u32(tap, NULL, data, 24, 0);
if (err != ERROR_OK)
return err;
if (flush)
@@ -242,7 +242,7 @@ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
if (err != ERROR_OK)
return err;
- err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
+ err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0);
if (err != ERROR_OK)
return err;
if (flush)
@@ -258,7 +258,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0);
if (err != ERROR_OK)
return err;
- err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0);
+ err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0);
if (err != ERROR_OK)
return err;
if (flush) {
@@ -270,7 +270,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode
err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0);
if (err != ERROR_OK)
return err;
- err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0);
+ err = dsp563xx_write_dr_u32(tap, NULL, operand, 24, 0);
if (err != ERROR_OK)
return err;
if (flush) {
diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am
index 8367a38..c1759ed 100644
--- a/src/target/espressif/Makefile.am
+++ b/src/target/espressif/Makefile.am
@@ -8,6 +8,10 @@ noinst_LTLIBRARIES += %D%/libespressif.la
%D%/esp_xtensa_smp.h \
%D%/esp_xtensa_semihosting.c \
%D%/esp_xtensa_semihosting.h \
+ %D%/esp_xtensa_apptrace.c \
+ %D%/esp_xtensa_apptrace.h \
+ %D%/esp32_apptrace.c \
+ %D%/esp32_apptrace.h \
%D%/esp32.c \
%D%/esp32s2.c \
%D%/esp32s3.c \
diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c
index 63055cf..74bbe50 100644
--- a/src/target/espressif/esp32.c
+++ b/src/target/espressif/esp32.c
@@ -441,6 +441,11 @@ static const struct command_registration esp32_command_handlers[] = {
.chain = esp_xtensa_smp_command_handlers,
},
{
+ .name = "esp",
+ .usage = "",
+ .chain = esp32_apptrace_command_handlers,
+ },
+ {
.name = "esp32",
.usage = "",
.chain = smp_command_handlers,
diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c
new file mode 100644
index 0000000..291503e
--- /dev/null
+++ b/src/target/espressif/esp32_apptrace.c
@@ -0,0 +1,1372 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * ESP32xx application tracing module for OpenOCD *
+ * Copyright (C) 2017 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifndef _WIN32
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <helper/list.h>
+#include <helper/time_support.h>
+#include <target/target.h>
+#include <target/target_type.h>
+#include <target/smp.h>
+#include <server/server.h>
+#include "esp_xtensa.h"
+#include "esp_xtensa_smp.h"
+#include "esp_xtensa_apptrace.h"
+#include "esp32_apptrace.h"
+
+#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15)
+#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15))
+
+#define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4
+
+#define ESP_APPTRACE_CMD_MODE_GEN 0
+#define ESP_APPTRACE_CMD_MODE_SYSVIEW 1
+#define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2
+#define ESP_APPTRACE_CMD_MODE_SYNC 3
+
+#define ESP32_APPTRACE_TGT_STATE_TMO 5000
+#define ESP_APPTRACE_BLOCKS_POOL_SZ 10
+
+struct esp32_apptrace_dest_file_data {
+ int fout;
+};
+
+struct esp32_apptrace_dest_tcp_data {
+ int sockfd;
+};
+
+struct esp32_apptrace_target_state {
+ int running;
+ uint32_t block_id;
+ uint32_t data_len;
+};
+
+struct esp_apptrace_target2host_hdr {
+ uint16_t block_sz;
+ uint16_t wr_sz;
+};
+#define APPTRACE_BLOCK_SIZE_OFFSET 0
+#define APPTRACE_WR_SIZE_OFFSET 2
+
+struct esp32_apptrace_block {
+ struct list_head node;
+ uint8_t *data;
+ uint32_t data_len;
+};
+
+static int esp32_apptrace_data_processor(void *priv);
+static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx,
+ struct esp32_apptrace_target_state *target_state,
+ uint32_t *fired_target_num);
+static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
+ struct esp32_apptrace_target_state *targets);
+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,
+ struct esp32_apptrace_block *block);
+
+static const bool s_time_stats_enable = true;
+
+/*********************************************************************
+* Trace destination API
+**********************************************************************/
+
+static int esp32_apptrace_file_dest_write(void *priv, uint8_t *data, int size)
+{
+ struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv;
+
+ int wr_sz = write(dest_data->fout, data, size);
+ if (wr_sz != size) {
+ LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size, errno, wr_sz);
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_file_dest_cleanup(void *priv)
+{
+ struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv;
+
+ if (dest_data->fout > 0)
+ close(dest_data->fout);
+ free(dest_data);
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
+{
+ struct esp32_apptrace_dest_file_data *dest_data = calloc(1, sizeof(*dest_data));
+ if (!dest_data) {
+ LOG_ERROR("Failed to alloc mem for file dest!");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("Open file %s", dest_name);
+ dest_data->fout = open(dest_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (dest_data->fout <= 0) {
+ LOG_ERROR("Failed to open file %s", dest_name);
+ free(dest_data);
+ return ERROR_FAIL;
+ }
+
+ dest->priv = dest_data;
+ dest->write = esp32_apptrace_file_dest_write;
+ dest->clean = esp32_apptrace_file_dest_cleanup;
+ dest->log_progress = true;
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_console_dest_write(void *priv, uint8_t *data, int size)
+{
+ LOG_USER_N("%.*s", size, data);
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_console_dest_cleanup(void *priv)
+{
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
+{
+ dest->priv = NULL;
+ dest->write = esp32_apptrace_console_dest_write;
+ dest->clean = esp32_apptrace_console_dest_cleanup;
+ dest->log_progress = false;
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_tcp_dest_write(void *priv, uint8_t *data, int size)
+{
+ struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv;
+ int wr_sz = write_socket(dest_data->sockfd, data, size);
+ if (wr_sz != size) {
+ LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size, errno, wr_sz);
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_tcp_dest_cleanup(void *priv)
+{
+ struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv;
+
+ if (dest_data->sockfd > 0)
+ close_socket(dest_data->sockfd);
+ free(dest_data);
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name)
+{
+ const char *port_sep = strchr(dest_name, ':');
+ /* separator not found, or was the first or the last character */
+ if (!port_sep || port_sep == dest_name || port_sep == dest_name + strlen(dest_name) - 1) {
+ LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ size_t hostname_len = port_sep - dest_name;
+
+ char hostname[64] = { 0 };
+ if (hostname_len >= sizeof(hostname)) {
+ LOG_ERROR("apptrace: Hostname too long");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ memcpy(hostname, dest_name, hostname_len);
+
+ const char *port_str = port_sep + 1;
+ struct addrinfo *ai;
+ int flags = 0;
+#ifdef AI_NUMERICSERV
+ flags |= AI_NUMERICSERV;
+#endif /* AI_NUMERICSERV */
+ struct addrinfo hint = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = 0,
+ .ai_flags = flags
+ };
+ int res = getaddrinfo(hostname, port_str, &hint, &ai);
+ if (res != 0) {
+ LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname);
+ return ERROR_FAIL;
+ }
+ int sockfd = -1;
+ for (struct addrinfo *ai_it = ai; ai_it; ai_it = ai_it->ai_next) {
+ sockfd = socket(ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol);
+ if (sockfd < 0) {
+ LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)",
+ ai_it->ai_family,
+ ai_it->ai_socktype,
+ ai_it->ai_protocol,
+ strerror(errno));
+ continue;
+ }
+
+ char cur_hostname[NI_MAXHOST];
+ char cur_portname[NI_MAXSERV];
+ res =
+ getnameinfo(ai_it->ai_addr, ai_it->ai_addrlen, cur_hostname,
+ sizeof(cur_hostname),
+ cur_portname, sizeof(cur_portname),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (res != 0)
+ continue;
+
+ LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname, cur_portname);
+ if (connect(sockfd, ai_it->ai_addr, ai_it->ai_addrlen) < 0) {
+ close_socket(sockfd);
+ sockfd = -1;
+ LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno));
+ continue;
+ }
+ break;
+ }
+ freeaddrinfo(ai);
+ if (sockfd < 0) {
+ LOG_ERROR("apptrace: Could not connect to %s:%s", hostname, port_str);
+ return ERROR_FAIL;
+ }
+ LOG_INFO("apptrace: Connected!");
+
+ struct esp32_apptrace_dest_tcp_data *dest_data = calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data));
+ if (!dest_data) {
+ LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!");
+ close_socket(sockfd);
+ return ERROR_FAIL;
+ }
+
+ dest_data->sockfd = sockfd;
+ dest->priv = dest_data;
+ dest->write = esp32_apptrace_tcp_dest_write;
+ dest->clean = esp32_apptrace_tcp_dest_cleanup;
+ dest->log_progress = true;
+
+ return ERROR_OK;
+}
+
+int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests)
+{
+ int res;
+ unsigned int i;
+
+ for (i = 0; i < max_dests; i++) {
+ if (strncmp(dest_paths[i], "file://", 7) == 0)
+ res = esp32_apptrace_file_dest_init(&dest[i], &dest_paths[i][7]);
+ else if (strncmp(dest_paths[i], "con:", 4) == 0)
+ res = esp32_apptrace_console_dest_init(&dest[i], NULL);
+ else if (strncmp(dest_paths[i], "tcp://", 6) == 0)
+ res = esp32_apptrace_tcp_dest_init(&dest[i], &dest_paths[i][6]);
+ else
+ break;
+
+ if (res != ERROR_OK) {
+ LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths[i]);
+ return 0;
+ }
+ }
+
+ return i;
+}
+
+int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests)
+{
+ for (unsigned int i = 0; i < max_dests; i++) {
+ if (dest[i].clean && dest[i].priv) {
+ int res = dest[i].clean(dest[i].priv);
+ dest[i].priv = NULL;
+ return res;
+ }
+ }
+ return ERROR_OK;
+}
+
+/*********************************************************************
+* Trace data blocks management API
+**********************************************************************/
+static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ struct esp32_apptrace_block *cur;
+ struct list_head *head = &ctx->free_trace_blocks;
+ struct list_head *tmp, *pos;
+
+ list_for_each_safe(pos, tmp, head) {
+ cur = list_entry(pos, struct esp32_apptrace_block, node);
+ if (cur) {
+ list_del(&cur->node);
+ free(cur->data);
+ free(cur);
+ }
+ }
+
+ head = &ctx->ready_trace_blocks;
+
+ list_for_each_safe(pos, tmp, head) {
+ cur = list_entry(pos, struct esp32_apptrace_block, node);
+ if (cur) {
+ list_del(&cur->node);
+ free(cur->data);
+ free(cur);
+ }
+ }
+}
+
+struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ struct esp32_apptrace_block *block = NULL;
+
+ if (!list_empty(&ctx->free_trace_blocks)) {
+ /*get first */
+ block = list_first_entry(&ctx->free_trace_blocks, struct esp32_apptrace_block, node);
+ list_del(&block->node);
+ }
+
+ return block;
+}
+
+static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block)
+{
+ LOG_DEBUG("esp32_apptrace_ready_block_put");
+ /* add to ready blocks list */
+ INIT_LIST_HEAD(&block->node);
+ list_add(&block->node, &ctx->ready_trace_blocks);
+
+ return ERROR_OK;
+}
+
+static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ if (list_empty(&ctx->ready_trace_blocks))
+ return NULL;
+
+ struct esp32_apptrace_block *block =
+ list_last_entry(&ctx->ready_trace_blocks, struct esp32_apptrace_block, node);
+
+ /* remove it from ready list */
+ list_del(&block->node);
+
+ return block;
+}
+
+static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block)
+{
+ /* add to free blocks list */
+ INIT_LIST_HEAD(&block->node);
+ list_add(&block->node, &ctx->free_trace_blocks);
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ int64_t timeout = timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 70000 : 5000);
+ while (!list_empty(&ctx->ready_trace_blocks)) {
+ alive_sleep(100);
+ if (timeval_ms() >= timeout) {
+ LOG_ERROR("Failed to wait for pended trace blocks!");
+ return ERROR_FAIL;
+ }
+ }
+ /* signal timer callback to stop */
+ ctx->running = 0;
+ target_unregister_timer_callback(esp32_apptrace_data_processor, ctx);
+ return ERROR_OK;
+}
+
+/*********************************************************************
+* Trace commands
+**********************************************************************/
+
+int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode)
+{
+ struct target *target = get_current_target(CMD_CTX);
+
+ memset(cmd_ctx, 0, sizeof(struct esp32_apptrace_cmd_ctx));
+ cmd_ctx->target = target;
+ cmd_ctx->mode = mode;
+ cmd_ctx->target_state = target->state;
+ cmd_ctx->cmd = cmd;
+
+ if (target->smp) {
+ struct target_list *head;
+ struct target *curr;
+ unsigned int i = 0;
+ cmd_ctx->cores_num = 0;
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ if (i == ESP32_APPTRACE_MAX_CORES_NUM) {
+ command_print(cmd, "Too many cores configured! Max %d cores are supported.",
+ ESP32_APPTRACE_MAX_CORES_NUM);
+ return ERROR_FAIL;
+ }
+ if (!target_was_examined(curr))
+ continue;
+ cmd_ctx->cores_num++;
+ cmd_ctx->cpus[i++] = curr;
+ }
+ } else {
+ cmd_ctx->cores_num = 1;
+ cmd_ctx->cpus[0] = target;
+ }
+ /* some relies on ESP32_APPTRACE_MAX_CORES_NUM
+ * TODO: remove that dependency */
+ assert(cmd_ctx->cores_num <= ESP32_APPTRACE_MAX_CORES_NUM && "Too many cores number!");
+
+ struct xtensa *xtensa = target->arch_info;
+ if (xtensa->common_magic == XTENSA_COMMON_MAGIC) {
+ cmd_ctx->hw = target_to_esp_xtensa(target)->apptrace.hw;
+ } else { /* TODO: riscv is not supported yet */
+ command_print(cmd, "Unsupported target arch 0x%X", xtensa->common_magic);
+ return ERROR_FAIL;
+ }
+
+ cmd_ctx->max_trace_block_sz = cmd_ctx->hw->max_block_size_get(cmd_ctx->cpus[0]);
+ if (cmd_ctx->max_trace_block_sz == 0) {
+ command_print(cmd, "Failed to get max trace block size!");
+ return ERROR_FAIL;
+ }
+ LOG_INFO("Total trace memory: %" PRIu32 " bytes", cmd_ctx->max_trace_block_sz);
+
+ INIT_LIST_HEAD(&cmd_ctx->ready_trace_blocks);
+ INIT_LIST_HEAD(&cmd_ctx->free_trace_blocks);
+ for (unsigned int i = 0; i < ESP_APPTRACE_BLOCKS_POOL_SZ; i++) {
+ struct esp32_apptrace_block *block = calloc(1, sizeof(struct esp32_apptrace_block));
+ if (!block) {
+ command_print(cmd, "Failed to alloc trace buffer entry!");
+ esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
+ return ERROR_FAIL;
+ }
+ block->data = malloc(cmd_ctx->max_trace_block_sz);
+ if (!block->data) {
+ free(block);
+ command_print(cmd, "Failed to alloc trace buffer %" PRIu32 " bytes!", cmd_ctx->max_trace_block_sz);
+ esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
+ return ERROR_FAIL;
+ }
+ INIT_LIST_HEAD(&block->node);
+ list_add(&block->node, &cmd_ctx->free_trace_blocks);
+ }
+
+ cmd_ctx->running = 1;
+ if (cmd_ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) {
+ int res = target_register_timer_callback(esp32_apptrace_data_processor,
+ 0,
+ TARGET_TIMER_TYPE_PERIODIC,
+ cmd_ctx);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to start trace data timer callback (%d)!", res);
+ esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
+ return ERROR_FAIL;
+ }
+ }
+
+ if (s_time_stats_enable) {
+ cmd_ctx->stats.min_blk_read_time = 1000000.0;
+ cmd_ctx->stats.min_blk_proc_time = 1000000.0;
+ }
+ if (duration_start(&cmd_ctx->idle_time) != 0) {
+ command_print(cmd, "Failed to start idle time measurement!");
+ esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
+{
+ esp32_apptrace_blocks_pool_cleanup(cmd_ctx);
+ return ERROR_OK;
+}
+
+#define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \
+ do { \
+ if ((_arg_) == 0 && (_start_) == (_end_)) { \
+ command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \
+ return; \
+ } \
+ } while (0)
+
+void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+ struct esp32_apptrace_cmd_data *cmd_data,
+ const char **argv,
+ int argc)
+{
+ char *end;
+
+ cmd_data->poll_period = strtoul(argv[0], &end, 10);
+ ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->poll_period, argv[0], end);
+ if (argc > 1) {
+ cmd_data->max_len = strtoul(argv[1], &end, 10);
+ ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->max_len, argv[1], end);
+ if (argc > 2) {
+ int32_t tmo = strtol(argv[2], &end, 10);
+ ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, tmo, argv[2], end);
+ cmd_ctx->stop_tmo = 1.0 * tmo;
+ if (argc > 3) {
+ cmd_data->wait4halt = strtoul(argv[3], &end, 10);
+ ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->wait4halt, argv[3], end);
+ if (argc > 4) {
+ cmd_data->skip_len = strtoul(argv[4], &end, 10);
+ ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->skip_len, argv[4], end);
+ }
+ }
+ }
+ }
+}
+
+static int esp32_apptrace_core_id_get(struct target *target, uint8_t *hdr_buf)
+{
+ return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET));
+}
+
+static uint32_t esp32_apptrace_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len)
+{
+ *wr_len = ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_WR_SIZE_OFFSET));
+ return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET));
+}
+
+static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+ struct command_invocation *cmd,
+ int mode,
+ const char **argv,
+ int argc)
+{
+ struct esp32_apptrace_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;
+
+ cmd_data = calloc(1, sizeof(*cmd_data));
+ assert(cmd_data && "No memory for command data!");
+ cmd_ctx->cmd_priv = cmd_data;
+
+ /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */
+ res = esp32_apptrace_dest_init(&cmd_data->data_dest, argv, 1);
+ if (res != 1) { /* only one destination needs to be initialized */
+ command_print(cmd, "Wrong args! Needs a trace data destination!");
+ free(cmd_data);
+ goto on_error;
+ }
+ cmd_ctx->stop_tmo = -1.0; /* infinite */
+ cmd_data->max_len = UINT32_MAX;
+ cmd_data->poll_period = 0 /*ms*/;
+ if (argc > 1)
+ /* parse remaining args */
+ esp32_apptrace_cmd_args_parse(cmd_ctx, cmd_data, &argv[1], argc - 1);
+
+ LOG_USER("App trace params: from %d cores, size %" PRId32 " bytes, stop_tmo %g s, poll period %" PRId32
+ " ms, wait_rst %d, skip %" PRId32 " bytes", cmd_ctx->cores_num,
+ cmd_data->max_len,
+ cmd_ctx->stop_tmo,
+ cmd_data->poll_period,
+ cmd_data->wait4halt,
+ cmd_data->skip_len);
+
+ cmd_ctx->trace_format.hdr_sz = ESP32_APPTRACE_USER_BLOCK_HDR_SZ;
+ cmd_ctx->trace_format.core_id_get = esp32_apptrace_core_id_get;
+ cmd_ctx->trace_format.usr_block_len_get = esp32_apptrace_usr_block_len_get;
+ return ERROR_OK;
+on_error:
+ command_print(cmd, "Not enough args! Need %d trace data destinations!", cmd_ctx->cores_num);
+ cmd_ctx->running = 0;
+ esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+ return res;
+}
+
+static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx)
+{
+ struct esp32_apptrace_cmd_data *cmd_data = cmd_ctx->cmd_priv;
+
+ esp32_apptrace_dest_cleanup(&cmd_data->data_dest, 1);
+ free(cmd_data);
+ cmd_ctx->cmd_priv = NULL;
+ esp32_apptrace_cmd_ctx_cleanup(cmd_ctx);
+ return ERROR_OK;
+}
+
+static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv;
+ uint32_t trace_sz = 0;
+
+ if (cmd_data)
+ trace_sz = ctx->tot_len > cmd_data->skip_len ? ctx->tot_len - cmd_data->skip_len : 0;
+ LOG_USER("Tracing is %s. Size is %" PRId32 " of %" PRId32 " @ %f (%f) KiB/s",
+ !ctx->running ? "STOPPED" : "RUNNING",
+ trace_sz,
+ cmd_data ? cmd_data->max_len : 0,
+ duration_kbps(&ctx->read_time, ctx->tot_len),
+ duration_kbps(&ctx->read_time, ctx->raw_tot_len));
+ LOG_USER("Data: blocks incomplete %" PRId32 ", lost bytes: %" PRId32,
+ ctx->stats.incompl_blocks,
+ ctx->stats.lost_bytes);
+ if (s_time_stats_enable) {
+ LOG_USER("Block read time [%f..%f] ms",
+ 1000 * ctx->stats.min_blk_read_time,
+ 1000 * ctx->stats.max_blk_read_time);
+ LOG_USER("Block proc time [%f..%f] ms",
+ 1000 * ctx->stats.min_blk_proc_time,
+ 1000 * ctx->stats.max_blk_proc_time);
+ }
+}
+
+static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct target *target)
+{
+ LOG_USER("Wait for halt...");
+ while (!openocd_is_shutdown_pending()) {
+ int res = target_poll(target);
+ if (res != ERROR_OK)
+ return res;
+ if (target->state == TARGET_HALTED) {
+ LOG_USER("%s: HALTED", target->cmd_name);
+ break;
+ }
+ alive_sleep(500);
+ }
+ return ERROR_OK;
+}
+
+int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx,
+ struct esp32_apptrace_target_state *targets)
+{
+ int res = ERROR_OK;
+
+ memset(targets, 0, ctx->cores_num * sizeof(struct esp32_apptrace_target_state));
+ /* halt all CPUs */
+ LOG_DEBUG("Halt all targets!");
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ if (!target_was_examined(ctx->cpus[k]))
+ continue;
+ if (ctx->cpus[k]->state == TARGET_HALTED)
+ continue;
+ res = target_halt(ctx->cpus[k]);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to halt target (%d)!", res);
+ return res;
+ }
+ res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to wait halt target %s / %d (%d)!",
+ target_name(ctx->cpus[k]),
+ ctx->cpus[k]->state,
+ res);
+ return res;
+ }
+ }
+ /* read current block statuses from CPUs */
+ LOG_DEBUG("Read current block statuses");
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ uint32_t stat;
+ res = ctx->hw->status_reg_read(ctx->cpus[k], &stat);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read trace status (%d)!", res);
+ return res;
+ }
+ /* check if some CPU stopped inside tracing regs update critical section */
+ if (stat) {
+ if (ctx->hw->leave_trace_crit_section_start) {
+ res = ctx->hw->leave_trace_crit_section_start(ctx->cpus[k]);
+ if (res != ERROR_OK)
+ return res;
+ }
+ uint32_t bp_addr = stat;
+ res = breakpoint_add(ctx->cpus[k], bp_addr, 1, BKPT_HARD);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to set breakpoint (%d)!", res);
+ return res;
+ }
+ while (stat) {
+ /* allow this CPU to leave ERI write critical section */
+ res = target_resume(ctx->cpus[k], 1, 0, 1, 0);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to resume target (%d)!", res);
+ breakpoint_remove(ctx->cpus[k], bp_addr);
+ return res;
+ }
+ /* wait for CPU to be halted on BP */
+ enum target_debug_reason debug_reason = DBG_REASON_UNDEFINED;
+ while (debug_reason != DBG_REASON_BREAKPOINT) {
+ res = target_wait_state(ctx->cpus[k], TARGET_HALTED,
+ ESP32_APPTRACE_TGT_STATE_TMO);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to wait halt on bp (%d)!", res);
+ breakpoint_remove(ctx->cpus[k], bp_addr);
+ return res;
+ }
+ debug_reason = ctx->cpus[k]->debug_reason;
+ }
+ res = ctx->hw->status_reg_read(ctx->cpus[k], &stat);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read trace status (%d)!", res);
+ breakpoint_remove(ctx->cpus[k], bp_addr);
+ return res;
+ }
+ }
+ breakpoint_remove(ctx->cpus[k], bp_addr);
+ if (ctx->hw->leave_trace_crit_section_stop) {
+ res = ctx->hw->leave_trace_crit_section_stop(ctx->cpus[k]);
+ if (res != ERROR_OK)
+ return res;
+ }
+ }
+ res = ctx->hw->data_len_read(ctx->cpus[k], &targets[k].block_id, &targets[k].data_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read trace status (%d)!", res);
+ return res;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx,
+ bool conn,
+ bool resume_target)
+{
+ struct esp32_apptrace_target_state target_to_connect[ESP32_APPTRACE_MAX_CORES_NUM];
+
+ if (conn)
+ LOG_USER("Connect targets...");
+ else
+ LOG_USER("Disconnect targets...");
+
+ int res = esp32_apptrace_safe_halt_targets(ctx, target_to_connect);
+ if (res != ERROR_OK) {
+ command_print(ctx->cmd, "Failed to halt targets (%d)!", res);
+ return res;
+ }
+ if (ctx->cores_num > 1) {
+ /* set block ids to the highest value */
+ uint32_t max_id = 0;
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ if (target_to_connect[k].block_id > max_id)
+ max_id = target_to_connect[k].block_id;
+ }
+ for (unsigned int k = 0; k < ctx->cores_num; k++)
+ target_to_connect[k].block_id = max_id;
+ }
+ for (unsigned int k = 0; k < ctx->cores_num; k++) {
+ /* update host connected status */
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[k],
+ target_to_connect[k].block_id,
+ 0 /*ack target data*/,
+ conn,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ command_print(ctx->cmd, "Failed to read trace status (%d)!", res);
+ return res;
+ }
+ }
+ if (resume_target) {
+ LOG_DEBUG("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) {
+ command_print(ctx->cmd, "Failed to resume target (%d)!", res);
+ return res;
+ }
+ if (ctx->cpus[k]->smp)
+ smp_resumed = true;
+ }
+ }
+ if (conn)
+ LOG_INFO("Targets connected.");
+ else
+ LOG_INFO("Targets disconnected.");
+ return ERROR_OK;
+}
+
+int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target,
+ uint32_t block_id,
+ const uint8_t *data,
+ uint32_t size)
+{
+ struct esp_apptrace_host2target_hdr hdr = { .block_sz = size };
+ uint32_t buf_sz[2] = { sizeof(hdr), size };
+ const uint8_t *bufs[2] = { (const uint8_t *)&hdr, data };
+
+ if (size > hw->usr_block_max_size_get(target)) {
+ LOG_ERROR("Too large user block %" PRId32, size);
+ return ERROR_FAIL;
+ }
+
+ return hw->buffs_write(target,
+ ARRAY_SIZE(buf_sz),
+ buf_sz,
+ bufs,
+ block_id,
+ true /*ack target data*/,
+ true /*host data*/);
+}
+
+static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx *ctx, uint8_t *hdr_buf)
+{
+ uint32_t wr_len = 0;
+ uint32_t usr_len = ctx->trace_format.usr_block_len_get(ctx->target, hdr_buf, &wr_len);
+ if (usr_len != wr_len) {
+ LOG_ERROR("Incomplete block sz %" PRId32 ", wr %" PRId32, usr_len, wr_len);
+ ctx->stats.incompl_blocks++;
+ ctx->stats.lost_bytes += usr_len - wr_len;
+ }
+ return usr_len;
+}
+
+int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx,
+ struct esp32_apptrace_target_state *target_state,
+ uint32_t *fired_target_num)
+{
+ if (fired_target_num)
+ *fired_target_num = UINT32_MAX;
+
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ int res = ctx->hw->data_len_read(ctx->cpus[i], &target_state[i].block_id, &target_state[i].data_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx->cpus[i]));
+ return res;
+ }
+ if (target_state[i].data_len) {
+ LOG_TARGET_DEBUG(ctx->cpus[i], "Block %" PRId32 ", len %" PRId32 " bytes on fired",
+ target_state[i].block_id, target_state[i].data_len);
+ if (fired_target_num)
+ *fired_target_num = i;
+ break;
+ }
+ }
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx,
+ unsigned int core_id,
+ uint8_t *data,
+ uint32_t data_len)
+{
+ struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv;
+
+ LOG_DEBUG("Got block %" PRId32 " bytes [%x %x...%x %x]", data_len, data[12], data[13],
+ data[data_len - 2], data[data_len - 1]);
+ if (ctx->tot_len + data_len > cmd_data->skip_len) {
+ uint32_t wr_idx = 0, wr_chunk_len = data_len;
+ if (ctx->tot_len < cmd_data->skip_len) {
+ wr_chunk_len = (ctx->tot_len + wr_chunk_len) - cmd_data->skip_len;
+ wr_idx = cmd_data->skip_len - ctx->tot_len;
+ }
+ if (ctx->tot_len + wr_chunk_len > cmd_data->max_len)
+ wr_chunk_len -= (ctx->tot_len + wr_chunk_len - cmd_data->skip_len) - cmd_data->max_len;
+ if (wr_chunk_len > 0) {
+ int res = cmd_data->data_dest.write(cmd_data->data_dest.priv, data + wr_idx, wr_chunk_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to write %" PRId32 " bytes to dest 0!", data_len);
+ return res;
+ }
+ }
+ ctx->tot_len += wr_chunk_len;
+ } else {
+ ctx->tot_len += data_len;
+ }
+
+ if (cmd_data->data_dest.log_progress)
+ LOG_USER("%" PRId32 " ", ctx->tot_len);
+ /* check for stop condition */
+ if (ctx->tot_len > cmd_data->skip_len && (ctx->tot_len - cmd_data->skip_len >= cmd_data->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;
+}
+
+static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx,
+ struct esp32_apptrace_block *block)
+{
+ uint32_t processed = 0;
+ uint32_t hdr_sz = ctx->trace_format.hdr_sz;
+
+ LOG_DEBUG("Got block %" PRId32 " bytes", block->data_len);
+ /* process user blocks one by one */
+ while (processed < block->data_len) {
+ LOG_DEBUG("Process usr block %" PRId32 "/%" PRId32, processed, block->data_len);
+ /* process user block */
+ uint32_t usr_len = esp32_apptrace_usr_block_check(ctx, block->data + processed);
+ int core_id = ctx->trace_format.core_id_get(ctx->target, block->data + processed);
+ /* process user data */
+ int res = ctx->process_data(ctx, core_id, block->data + processed + hdr_sz, usr_len);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to process %" PRId32 " bytes!", usr_len);
+ return res;
+ }
+ processed += usr_len + hdr_sz;
+ }
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_data_processor(void *priv)
+{
+ struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv;
+
+ if (!ctx->running)
+ return ERROR_OK;
+
+ struct esp32_apptrace_block *block = esp32_apptrace_ready_block_get(ctx);
+ if (!block)
+ return ERROR_OK;
+
+ int res = esp32_apptrace_handle_trace_block(ctx, block);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
+ return res;
+ }
+ res = esp32_apptrace_block_free(ctx, block);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to free ready block!");
+ return res;
+ }
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ if (!ctx)
+ return ERROR_FAIL;
+
+ unsigned int busy_target_num = 0;
+
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ bool conn = true;
+ int res = ctx->hw->ctrl_reg_read(ctx->cpus[i], NULL, NULL, &conn);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i, res);
+ return res;
+ }
+ if (!conn) {
+ uint32_t stat = 0;
+ LOG_TARGET_WARNING(ctx->cpus[i], "apptrace connection is lost. Re-connect.");
+ res = ctx->hw->status_reg_read(ctx->cpus[i], &stat);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read trace status (%d)!", res);
+ return res;
+ }
+ if (stat) {
+ LOG_TARGET_WARNING(ctx->cpus[i], "in critical state. Retry in next poll");
+ if (++busy_target_num == ctx->cores_num) {
+ LOG_WARNING("No available core");
+ return ERROR_WAIT;
+ }
+ continue;
+ }
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
+ 0,
+ 0,
+ true /*host connected*/,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i, res);
+ return res;
+ }
+ if (ctx->stop_tmo != -1.0) {
+ /* re-start idle time measurement */
+ if (duration_start(&ctx->idle_time) != 0) {
+ LOG_ERROR("Failed to re-start idle time measure!");
+ return ERROR_FAIL;
+ }
+ }
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esp32_apptrace_poll(void *priv)
+{
+ struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv;
+ int res;
+ uint32_t fired_target_num = 0;
+ struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM];
+ struct duration blk_proc_time;
+
+ if (!ctx->running) {
+ if (ctx->auto_clean)
+ ctx->auto_clean(ctx);
+ return ERROR_FAIL;
+ }
+
+ /* Check for connection is alive.For some reason target and therefore host_connected flag
+ * might have been reset */
+ res = esp32_apptrace_check_connection(ctx);
+ if (res != ERROR_OK) {
+ if (res != ERROR_WAIT)
+ ctx->running = 0;
+ return res;
+ }
+
+ /* check for data from target */
+ res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to read data len!");
+ return res;
+ }
+ /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id,
+ * target_state[0].data_len, target_name(ctx->cpus[0])); */
+ if (fired_target_num == UINT32_MAX) {
+ /* no data has been received, but block could be switched due to the data transferred
+ * from host to target */
+ if (ctx->cores_num > 1) {
+ uint32_t max_block_id = 0, min_block_id = ctx->hw->max_block_id;
+ /* find maximum block ID and set the same ID in control reg for both cores
+ * */
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ if (max_block_id < target_state[i].block_id)
+ max_block_id = target_state[i].block_id;
+ if (min_block_id > target_state[i].block_id)
+ min_block_id = target_state[i].block_id;
+ }
+ /* handle block ID overflow */
+ if (max_block_id == ctx->hw->max_block_id && min_block_id == 0)
+ max_block_id = 0;
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ if (max_block_id != target_state[i].block_id) {
+ LOG_TARGET_DEBUG(ctx->cpus[i], "Ack empty block %" PRId32 "!", max_block_id);
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
+ max_block_id,
+ 0 /*all read*/,
+ true /*host connected*/,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack empty data block!");
+ return res;
+ }
+ }
+ }
+ ctx->last_blk_id = max_block_id;
+ }
+ if (ctx->stop_tmo != -1.0) {
+ if (duration_measure(&ctx->idle_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to measure idle time!");
+ return ERROR_FAIL;
+ }
+ if (duration_elapsed(&ctx->idle_time) >= ctx->stop_tmo) {
+ ctx->running = 0;
+ LOG_ERROR("Data timeout!");
+ return ERROR_FAIL;
+ }
+ }
+ return ERROR_OK;/* no data */
+ }
+ /* sanity check */
+ if (target_state[fired_target_num].data_len > ctx->max_trace_block_sz) {
+ ctx->running = 0;
+ LOG_ERROR("Too large block size %" PRId32 "!", target_state[fired_target_num].data_len);
+ return ERROR_FAIL;
+ }
+ if (ctx->tot_len == 0) {
+ if (duration_start(&ctx->read_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to start trace read time measurement!");
+ return ERROR_FAIL;
+ }
+ }
+ struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx);
+ if (!block) {
+ ctx->running = 0;
+ LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to get free block for data!");
+ return ERROR_FAIL;
+ }
+ if (s_time_stats_enable) {
+ /* read block */
+ if (duration_start(&blk_proc_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to start block read time measurement!");
+ return ERROR_FAIL;
+ }
+ }
+ 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,
+ /* do not ack target data in sync mode,
+ esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */
+ ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to read data!");
+ return res;
+ }
+ ctx->last_blk_id = target_state[fired_target_num].block_id;
+ block->data_len = target_state[fired_target_num].data_len;
+ ctx->raw_tot_len += block->data_len;
+ if (s_time_stats_enable) {
+ if (duration_measure(&blk_proc_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to measure block read time!");
+ return ERROR_FAIL;
+ }
+ /* update stats */
+ float brt = duration_elapsed(&blk_proc_time);
+ if (brt > ctx->stats.max_blk_read_time)
+ ctx->stats.max_blk_read_time = brt;
+ if (brt < ctx->stats.min_blk_read_time)
+ ctx->stats.min_blk_read_time = brt;
+
+ if (duration_start(&blk_proc_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to start block proc time measurement!");
+ return ERROR_FAIL;
+ }
+ }
+ /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response
+ * data and will do ack thereafter */
+ if (ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) {
+ for (unsigned int i = 0; i < ctx->cores_num; i++) {
+ if (i == fired_target_num)
+ continue;
+ res = ctx->hw->ctrl_reg_write(ctx->cpus[i],
+ ctx->last_blk_id,
+ 0 /*all read*/,
+ true /*host connected*/,
+ false /*no host data*/);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack data!");
+ return res;
+ }
+ LOG_TARGET_DEBUG(ctx->cpus[i], "Ack block %" PRId32, ctx->last_blk_id);
+ }
+ res = esp32_apptrace_ready_block_put(ctx, block);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to put ready block of data!");
+ return res;
+ }
+ } else {
+ res = esp32_apptrace_handle_trace_block(ctx, block);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len);
+ return res;
+ }
+ res = esp32_apptrace_block_free(ctx, block);
+ if (res != ERROR_OK) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to free ready block!");
+ return res;
+ }
+ }
+ if (ctx->stop_tmo != -1.0) {
+ /* start idle time measurement */
+ if (duration_start(&ctx->idle_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to start idle time measure!");
+ return ERROR_FAIL;
+ }
+ }
+ if (s_time_stats_enable) {
+ if (duration_measure(&blk_proc_time) != 0) {
+ ctx->running = 0;
+ LOG_ERROR("Failed to stop block proc time measure!");
+ return ERROR_FAIL;
+ }
+ /* update stats */
+ float bt = duration_elapsed(&blk_proc_time);
+ if (bt > ctx->stats.max_blk_proc_time)
+ ctx->stats.max_blk_proc_time = bt;
+ if (bt < ctx->stats.min_blk_proc_time)
+ ctx->stats.min_blk_proc_time = bt;
+ }
+ return ERROR_OK;
+}
+
+static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx)
+{
+ if (duration_measure(&ctx->read_time) != 0)
+ LOG_ERROR("Failed to stop trace read time measurement!");
+ int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx);
+ if (res != ERROR_OK)
+ LOG_ERROR("Failed to unregister target timer handler (%d)!", res);
+
+ /* data processor is alive, so wait for all received blocks to be processed */
+ res = esp32_apptrace_wait_tracing_finished(ctx);
+ if (res != ERROR_OK)
+ LOG_ERROR("Failed to wait for pended blocks (%d)!", res);
+ res = esp32_apptrace_connect_targets(ctx, false, ctx->target_state == TARGET_RUNNING);
+ if (res != ERROR_OK)
+ LOG_ERROR("Failed to disconnect targets (%d)!", res);
+ esp32_apptrace_print_stats(ctx);
+ res = esp32_apptrace_cmd_cleanup(ctx);
+ if (res != ERROR_OK)
+ 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)
+{
+ static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx;
+ struct esp32_apptrace_cmd_data *cmd_data;
+ int res = ERROR_FAIL;
+ enum target_state old_state;
+ struct target *target = get_current_target(CMD_CTX);
+
+ if (argc < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ /* command can be invoked on unexamined core, if so find examined one */
+ if (target->smp && !target_was_examined(target)) {
+ struct target_list *head;
+ struct target *curr;
+ LOG_WARNING("Current target '%s' was not examined!", target_name(target));
+ foreach_smp_target(head, target->smp_targets) {
+ curr = head->target;
+ if (target_was_examined(curr)) {
+ target = curr;
+ LOG_WARNING("Run command on target '%s'", target_name(target));
+ break;
+ }
+ }
+ }
+ old_state = target->state;
+
+ if (strcmp(argv[0], "start") == 0) {
+ 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;
+ s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop;
+ if (cmd_data->wait4halt) {
+ res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to wait for halt target (%d)!", res);
+ goto _on_start_error;
+ }
+ }
+ res = esp32_apptrace_connect_targets(&s_at_cmd_ctx, true, old_state == TARGET_RUNNING);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to connect to targets (%d)!", res);
+ goto _on_start_error;
+ }
+ res = target_register_timer_callback(esp32_apptrace_poll,
+ cmd_data->poll_period,
+ TARGET_TIMER_TYPE_PERIODIC,
+ &s_at_cmd_ctx);
+ if (res != ERROR_OK) {
+ command_print(cmd, "Failed to register target timer handler (%d)!", res);
+ goto _on_start_error;
+ }
+ } else if (strcmp(argv[0], "stop") == 0) {
+ if (!s_at_cmd_ctx.running) {
+ command_print(cmd, "Tracing is not running!");
+ return ERROR_FAIL;
+ }
+ esp32_apptrace_cmd_stop(&s_at_cmd_ctx);
+ return ERROR_OK;
+ } else if (strcmp(argv[0], "status") == 0) {
+ if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != 0)
+ LOG_ERROR("Failed to measure trace read time!");
+ esp32_apptrace_print_stats(&s_at_cmd_ctx);
+ return ERROR_OK;
+ } else if (strcmp(argv[0], "dump") == 0) {
+ /* [dump outfile] - post-mortem dump without connection to targets */
+ 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;
+ }
+ s_at_cmd_ctx.stop_tmo = 0.01; /* use small stop tmo */
+ s_at_cmd_ctx.process_data = esp32_apptrace_process_data;
+ /* check for exit signal and command completion */
+ while (!openocd_is_shutdown_pending() && s_at_cmd_ctx.running) {
+ res = esp32_apptrace_poll(&s_at_cmd_ctx);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to poll target for trace data (%d)!", res);
+ break;
+ }
+ /* let registered timer callbacks to run */
+ target_call_timer_callbacks();
+ }
+ if (s_at_cmd_ctx.running) {
+ /* data processor is alive, so wait for all received blocks to be processed */
+ res = esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx);
+ if (res != ERROR_OK)
+ LOG_ERROR("Failed to wait for pended blocks (%d)!", res);
+ }
+ esp32_apptrace_print_stats(&s_at_cmd_ctx);
+ res = esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+ if (res != ERROR_OK)
+ command_print(cmd, "Failed to cleanup cmd ctx (%d)!", res);
+ } else {
+ command_print(cmd, "Invalid action '%s'!", argv[0]);
+ }
+
+ return res;
+
+_on_start_error:
+ s_at_cmd_ctx.running = 0;
+ esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx);
+ return res;
+}
+
+COMMAND_HANDLER(esp32_cmd_apptrace)
+{
+ return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC);
+}
+
+const struct command_registration esp32_apptrace_command_handlers[] = {
+ {
+ .name = "apptrace",
+ .handler = esp32_cmd_apptrace,
+ .mode = COMMAND_EXEC,
+ .help =
+ "App Tracing: application level trace control. Starts, stops or queries tracing process status.",
+ .usage =
+ "[start <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/espressif/esp32_apptrace.h b/src/target/espressif/esp32_apptrace.h
new file mode 100644
index 0000000..3873342
--- /dev/null
+++ b/src/target/espressif/esp32_apptrace.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * ESP32 application trace module *
+ * Copyright (C) 2017-2019 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESP32_APPTRACE_H
+#define OPENOCD_TARGET_ESP32_APPTRACE_H
+
+#include <helper/command.h>
+#include <helper/time_support.h>
+#include <target/target.h>
+
+#define ESP32_APPTRACE_MAX_CORES_NUM 2
+
+struct esp32_apptrace_hw {
+ uint32_t max_block_id;
+ uint32_t (*max_block_size_get)(struct target *target);
+ int (*status_reg_read)(struct target *target, uint32_t *stat);
+ int (*ctrl_reg_write)(struct target *target,
+ uint32_t block_id,
+ uint32_t len,
+ bool conn,
+ bool data);
+ int (*ctrl_reg_read)(struct target *target,
+ uint32_t *block_id,
+ uint32_t *len,
+ bool *conn);
+ int (*data_len_read)(struct target *target,
+ uint32_t *block_id,
+ uint32_t *len);
+ int (*data_read)(struct target *target,
+ uint32_t size,
+ uint8_t *buffer,
+ uint32_t block_id,
+ bool ack);
+ uint32_t (*usr_block_max_size_get)(struct target *target);
+ int (*buffs_write)(struct target *target,
+ uint32_t bufs_num,
+ uint32_t buf_sz[],
+ const uint8_t *bufs[],
+ uint32_t block_id,
+ bool ack,
+ bool data);
+ int (*leave_trace_crit_section_start)(struct target *target);
+ int (*leave_trace_crit_section_stop)(struct target *target);
+};
+
+struct esp_apptrace_host2target_hdr {
+ uint16_t block_sz;
+};
+
+struct esp32_apptrace_dest {
+ void *priv;
+ int (*write)(void *priv, uint8_t *data, int size);
+ int (*clean)(void *priv);
+ bool log_progress;
+};
+
+struct esp32_apptrace_format {
+ uint32_t hdr_sz;
+ int (*core_id_get)(struct target *target, uint8_t *hdr_buf);
+ uint32_t (*usr_block_len_get)(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len);
+};
+
+struct esp32_apptrace_cmd_stats {
+ uint32_t incompl_blocks;
+ uint32_t lost_bytes;
+ float min_blk_read_time;
+ float max_blk_read_time;
+ float min_blk_proc_time;
+ float max_blk_proc_time;
+};
+
+struct esp32_apptrace_cmd_ctx {
+ volatile int running;
+ int mode;
+ /* TODO: use subtargets from target arch info */
+ struct target *cpus[ESP32_APPTRACE_MAX_CORES_NUM];
+ /* TODO: use cores num from target */
+ unsigned int cores_num;
+ const struct esp32_apptrace_hw *hw;
+ enum target_state target_state;
+ uint32_t last_blk_id;
+ struct list_head free_trace_blocks;
+ struct list_head ready_trace_blocks;
+ uint32_t max_trace_block_sz;
+ struct esp32_apptrace_format trace_format;
+ int (*process_data)(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len);
+ void (*auto_clean)(struct esp32_apptrace_cmd_ctx *ctx);
+ uint32_t tot_len;
+ uint32_t raw_tot_len;
+ float stop_tmo;
+ struct esp32_apptrace_cmd_stats stats;
+ struct duration read_time;
+ struct duration idle_time;
+ void *cmd_priv;
+ struct target *target;
+ struct command_invocation *cmd;
+};
+
+struct esp32_apptrace_cmd_data {
+ struct esp32_apptrace_dest data_dest;
+ uint32_t poll_period;
+ uint32_t max_len;
+ uint32_t skip_len;
+ bool wait4halt;
+};
+
+int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode);
+int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx);
+void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx,
+ struct esp32_apptrace_cmd_data *cmd_data,
+ const char **argv,
+ int argc);
+int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests);
+int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests);
+int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target,
+ uint32_t block_id,
+ const uint8_t *data,
+ uint32_t size);
+
+extern const struct command_registration esp32_apptrace_command_handlers[];
+
+#endif /* OPENOCD_TARGET_ESP32_APPTRACE_H */
diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c
index 64fa690..a11d05f 100644
--- a/src/target/espressif/esp32s2.c
+++ b/src/target/espressif/esp32s2.c
@@ -497,6 +497,11 @@ static const struct command_registration esp32s2_command_handlers[] = {
.chain = xtensa_command_handlers,
},
{
+ .name = "esp",
+ .usage = "",
+ .chain = esp32_apptrace_command_handlers,
+ },
+ {
.name = "arm",
.mode = COMMAND_ANY,
.help = "ARM Command Group",
diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c
index 62b22b1..4855678 100644
--- a/src/target/espressif/esp32s3.c
+++ b/src/target/espressif/esp32s3.c
@@ -365,6 +365,11 @@ static const struct command_registration esp32s3_command_handlers[] = {
.chain = esp_xtensa_smp_command_handlers,
},
{
+ .name = "esp",
+ .usage = "",
+ .chain = esp32_apptrace_command_handlers,
+ },
+ {
.name = "esp32",
.usage = "",
.chain = smp_command_handlers,
diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c
index fcc340c..44764ae 100644
--- a/src/target/espressif/esp_xtensa.c
+++ b/src/target/espressif/esp_xtensa.c
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <target/smp.h>
+#include "esp_xtensa_apptrace.h"
#include <target/register.h>
#include "esp_xtensa.h"
#include "esp_semihosting.h"
@@ -25,6 +26,7 @@ int esp_xtensa_init_arch_info(struct target *target,
if (ret != ERROR_OK)
return ret;
esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops;
+ esp_xtensa->apptrace.hw = &esp_xtensa_apptrace_hw;
return ERROR_OK;
}
diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h
index 1ad6c37..8807f0c 100644
--- a/src/target/espressif/esp_xtensa.h
+++ b/src/target/espressif/esp_xtensa.h
@@ -12,10 +12,12 @@
#include <target/xtensa/xtensa.h>
#include "esp_xtensa.h"
#include "esp_semihosting.h"
+#include "esp_xtensa_apptrace.h"
struct esp_xtensa_common {
struct xtensa xtensa; /* must be the first element */
struct esp_semihost_data semihost;
+ struct esp_xtensa_apptrace_info apptrace;
};
static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target)
diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c
new file mode 100644
index 0000000..5741ab0
--- /dev/null
+++ b/src/target/espressif/esp_xtensa_apptrace.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Xtensa application tracing module for OpenOCD *
+ * Copyright (C) 2017 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+/*
+ How it works?
+ https://github.com/espressif/esp-idf/blob/master/components/app_trace/port/xtensa/port.c#L8
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/align.h>
+#include <target/xtensa/xtensa.h>
+#include <target/xtensa/xtensa_debug_module.h>
+#include "esp_xtensa_apptrace.h"
+
+/* TRAX is disabled, so we use its registers for our own purposes
+ * | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 |
+ */
+#define XTENSA_APPTRACE_CTRL_REG XDMREG_DELAYCNT
+#define XTENSA_APPTRACE_BLOCK_ID_MSK 0x7FUL
+#define XTENSA_APPTRACE_BLOCK_ID_MAX XTENSA_APPTRACE_BLOCK_ID_MSK
+/* if non-zero then apptrace code entered the critical section and the value is an address of the
+ * critical section's exit point */
+#define XTENSA_APPTRACE_STAT_REG XDMREG_TRIGGERPC
+
+#define XTENSA_APPTRACE_BLOCK_LEN_MSK 0x7FFFUL
+#define XTENSA_APPTRACE_BLOCK_LEN(_l_) ((_l_) & XTENSA_APPTRACE_BLOCK_LEN_MSK)
+#define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_) ((_v_) & XTENSA_APPTRACE_BLOCK_LEN_MSK)
+#define XTENSA_APPTRACE_BLOCK_ID(_id_) (((_id_) & XTENSA_APPTRACE_BLOCK_ID_MSK) << 15)
+#define XTENSA_APPTRACE_BLOCK_ID_GET(_v_) (((_v_) >> 15) & XTENSA_APPTRACE_BLOCK_ID_MSK)
+#define XTENSA_APPTRACE_HOST_DATA BIT(22)
+#define XTENSA_APPTRACE_HOST_CONNECT BIT(23)
+
+static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target);
+static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target);
+static int esp_xtensa_apptrace_buffs_write(struct target *target,
+ uint32_t bufs_num,
+ uint32_t buf_sz[],
+ const uint8_t *bufs[],
+ uint32_t block_id,
+ bool ack,
+ bool data);
+
+struct esp32_apptrace_hw esp_xtensa_apptrace_hw = {
+ .max_block_id = XTENSA_APPTRACE_BLOCK_ID_MAX,
+ .max_block_size_get = esp_xtensa_apptrace_block_max_size_get,
+ .status_reg_read = esp_xtensa_apptrace_status_reg_read,
+ .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write,
+ .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read,
+ .data_len_read = esp_xtensa_apptrace_data_len_read,
+ .data_read = esp_xtensa_apptrace_data_read,
+ .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get,
+ .buffs_write = esp_xtensa_apptrace_buffs_write,
+ .leave_trace_crit_section_start = esp_xtensa_apptrace_leave_crit_section_start,
+ .leave_trace_crit_section_stop = esp_xtensa_apptrace_leave_crit_section_stop,
+};
+
+uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ struct xtensa_trace_status trace_status;
+ struct xtensa_trace_config trace_config;
+ uint32_t max_trace_block_sz;
+
+ int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read TRAX status (%d)!", res);
+ return 0;
+ }
+
+ max_trace_block_sz = BIT(((trace_status.stat >> 8) & 0x1f) - 2) * 4;
+ res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to read TRAX config (%d)!", res);
+ return 0;
+ }
+ LOG_DEBUG("ctrl=0x%" PRIx32 " memadrstart=0x%" PRIx32 " memadrend=0x%" PRIx32 " traxadr=0x%" PRIx32,
+ trace_config.ctrl,
+ trace_config.memaddr_start,
+ trace_config.memaddr_end,
+ trace_config.addr);
+
+ return max_trace_block_sz;
+}
+
+uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target)
+{
+ return esp_xtensa_apptrace_block_max_size_get(target) - sizeof(struct esp_apptrace_host2target_hdr);
+}
+
+int esp_xtensa_apptrace_data_len_read(struct target *target,
+ uint32_t *block_id,
+ uint32_t *len)
+{
+ return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL);
+}
+
+int esp_xtensa_apptrace_usr_block_write(struct target *target,
+ uint32_t block_id,
+ const uint8_t *data,
+ uint32_t size)
+{
+ return esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, target, block_id, data, size);
+}
+
+static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa,
+ uint32_t size,
+ uint8_t *buffer,
+ uint8_t *unal_bytes)
+{
+ int res = 0;
+ uint32_t rd_sz = ALIGN_UP(size, 4);
+
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - rd_sz) / 4);
+ if (res != ERROR_OK)
+ return res;
+ if (!IS_ALIGNED(size, 4)) {
+ res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes);
+ if (res != ERROR_OK)
+ return res;
+ }
+ for (unsigned int i = size / 4; i != 0; i--) {
+ res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[(i - 1) * 4]);
+ if (res != ERROR_OK)
+ return res;
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_data_normal_read(struct xtensa *xtensa,
+ uint32_t size,
+ uint8_t *buffer,
+ uint8_t *unal_bytes)
+{
+ int res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0);
+ if (res != ERROR_OK)
+ return res;
+ for (unsigned int i = 0; i < size / 4; i++) {
+ res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[i * 4]);
+ if (res != ERROR_OK)
+ return res;
+ }
+ if (!IS_ALIGNED(size, 4)) {
+ res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes);
+ if (res != ERROR_OK)
+ return res;
+ }
+ return ERROR_OK;
+}
+
+int esp_xtensa_apptrace_data_read(struct target *target,
+ uint32_t size,
+ uint8_t *buffer,
+ uint32_t block_id,
+ bool ack)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ int res;
+ uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | XTENSA_APPTRACE_BLOCK_ID(block_id) |
+ XTENSA_APPTRACE_BLOCK_LEN(0);
+ uint8_t unal_bytes[4];
+
+ LOG_DEBUG("Read data on target (%s)", target_name(target));
+ if (xtensa->core_config->trace.reversed_mem_access)
+ res = esp_xtensa_apptrace_data_reverse_read(xtensa, size, buffer, unal_bytes);
+ else
+ res = esp_xtensa_apptrace_data_normal_read(xtensa, size, buffer, unal_bytes);
+ if (res != ERROR_OK)
+ return res;
+ if (ack) {
+ LOG_DEBUG("Ack block %" PRIu32 " target (%s)!", block_id, target_name(target));
+ res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp);
+ if (res != ERROR_OK)
+ return res;
+ }
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to exec JTAG queue!");
+ return res;
+ }
+ if (!IS_ALIGNED(size, 4)) {
+ /* copy the last unaligned bytes */
+ memcpy(buffer + ALIGN_DOWN(size, 4), unal_bytes, size & 0x3UL);
+ }
+ return ERROR_OK;
+}
+
+int esp_xtensa_apptrace_ctrl_reg_write(struct target *target,
+ uint32_t block_id,
+ uint32_t len,
+ bool conn,
+ bool data)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ uint32_t tmp = (conn ? XTENSA_APPTRACE_HOST_CONNECT : 0) |
+ (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) |
+ XTENSA_APPTRACE_BLOCK_LEN(len);
+
+ xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp);
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to exec JTAG queue!");
+ return res;
+ }
+
+ return ERROR_OK;
+}
+
+int esp_xtensa_apptrace_ctrl_reg_read(struct target *target,
+ uint32_t *block_id,
+ uint32_t *len,
+ bool *conn)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ uint8_t tmp[4];
+
+ xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp);
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK)
+ return res;
+ uint32_t val = target_buffer_get_u32(target, tmp);
+ if (block_id)
+ *block_id = XTENSA_APPTRACE_BLOCK_ID_GET(val);
+ if (len)
+ *len = XTENSA_APPTRACE_BLOCK_LEN_GET(val);
+ if (conn)
+ *conn = val & XTENSA_APPTRACE_HOST_CONNECT;
+ return ERROR_OK;
+}
+
+int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ uint8_t tmp[4];
+
+ int res = xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp);
+ if (res != ERROR_OK)
+ return res;
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to exec JTAG queue!");
+ return res;
+ }
+ *stat = buf_get_u32(tmp, 0, 32);
+ return ERROR_OK;
+}
+
+int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+
+ xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_STAT_REG, stat);
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to exec JTAG queue!");
+ return res;
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_swdbg_activate(struct target *target, int enab)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+
+ xtensa_queue_dbg_reg_write(xtensa, enab ? XDMREG_DCRSET : XDMREG_DCRCLR, OCDDCR_DEBUGSWACTIVE);
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("%s: writing DCR failed!", target->cmd_name);
+ return res;
+ }
+
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target)
+{
+ /* TODO: not sure that we need this, but it seems that we fail to leave tracing critical
+ *section w/o this */
+ int res = esp_xtensa_swdbg_activate(target, 1 /*enable*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to activate SW debug (%d)!", res);
+ return res;
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target)
+{
+ int res = esp_xtensa_swdbg_activate(target, 0 /*disable*/);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to activate SW debug (%d)!", res);
+ return res;
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num,
+ uint32_t buf_sz[], const uint8_t *bufs[])
+{
+ int res = ERROR_OK;
+ uint32_t cached_bytes = 0, total_sz = 0;
+ uint8_t cached_data8[sizeof(uint32_t)] = { 0 };
+ uint32_t cached_data32 = 0;
+
+ struct xtensa *xtensa = target_to_xtensa(target);
+
+ for (uint32_t i = 0; i < bufs_num; i++)
+ total_sz += buf_sz[i];
+ if (!IS_ALIGNED(total_sz, 4)) {
+ cached_bytes = sizeof(uint32_t) - (total_sz & 0x3UL);
+ total_sz = ALIGN_UP(total_sz, 4);
+ }
+ xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - total_sz) / 4);
+ for (uint32_t i = bufs_num; i > 0; i--) {
+ uint32_t bsz = buf_sz[i - 1];
+ const uint8_t *cur_buf = &bufs[i - 1][bsz];
+ uint32_t bytes_to_cache;
+ /* if there are cached bytes from the previous buffer, combine them with the last
+ * from the current buffer */
+ if (cached_bytes) {
+ if ((cached_bytes + bsz) < sizeof(uint32_t))
+ bytes_to_cache = bsz;
+ else
+ bytes_to_cache = sizeof(uint32_t) - cached_bytes;
+ memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache],
+ cur_buf - bytes_to_cache,
+ bytes_to_cache);
+ cached_data32 = target_buffer_get_u32(target, cached_data8);
+ cached_bytes += bytes_to_cache;
+ if (cached_bytes < sizeof(uint32_t))
+ continue;
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
+ if (res != ERROR_OK)
+ return res;
+ bsz -= bytes_to_cache;
+ cur_buf -= bytes_to_cache;
+ memset(cached_data8, 0x00, sizeof(cached_data8));
+ cached_bytes = 0;
+ }
+ /* write full dwords */
+ for (unsigned int k = bsz; k >= sizeof(uint32_t); k -= sizeof(uint32_t)) {
+ uint32_t temp = target_buffer_get_u32(target, cur_buf - sizeof(uint32_t));
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp);
+ if (res != ERROR_OK)
+ return res;
+ cur_buf -= sizeof(uint32_t);
+ }
+ /* if there are bytes to be cached (1..3) */
+ bytes_to_cache = bsz & 0x3UL;
+ if (bytes_to_cache > 0) {
+ if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) {
+ /* filling the cache buffer from the end to beginning */
+ uint32_t to_copy = sizeof(uint32_t) - cached_bytes;
+ memcpy(&cached_data8[0], cur_buf - to_copy, to_copy);
+ cached_data32 = target_buffer_get_u32(target, cached_data8);
+ /* write full word of cached bytes */
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
+ if (res != ERROR_OK)
+ return res;
+ /* cache remaining bytes */
+ memset(cached_data8, 0x00, sizeof(cached_data8));
+ cur_buf -= to_copy;
+ to_copy = bytes_to_cache + cached_bytes - sizeof(uint32_t);
+ memcpy(&cached_data8[sizeof(uint32_t) - to_copy], cur_buf - to_copy, to_copy);
+ cached_bytes = to_copy;
+ } else {
+ /* filling the cache buffer from the end to beginning */
+ memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache],
+ cur_buf - bytes_to_cache,
+ bytes_to_cache);
+ cached_bytes += bytes_to_cache;
+ }
+ }
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num,
+ uint32_t buf_sz[], const uint8_t *bufs[])
+{
+ int res = ERROR_OK;
+ uint32_t cached_bytes = 0;
+ uint8_t cached_data8[4] = { 0 };
+ uint32_t cached_data32 = 0;
+
+ struct xtensa *xtensa = target_to_xtensa(target);
+
+ /* | 1 | 2 | 1 | 2 | 4 |.......|
+ * | 4 | 4 | 4 | */
+ xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0);
+ for (unsigned int i = 0; i < bufs_num; i++) {
+ uint32_t bsz = buf_sz[i];
+ const uint8_t *cur_buf = bufs[i];
+ uint32_t bytes_to_cache;
+ /* if there are cached bytes from the previous buffer, combine them with the last
+ * from the current buffer */
+ if (cached_bytes) {
+ if ((cached_bytes + bsz) < sizeof(uint32_t))
+ bytes_to_cache = bsz;
+ else
+ bytes_to_cache = sizeof(uint32_t) - cached_bytes;
+ memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache);
+ cached_bytes += bytes_to_cache;
+ if (cached_bytes < sizeof(uint32_t))
+ continue;
+ cached_data32 = target_buffer_get_u32(target, cached_data8);
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
+ if (res != ERROR_OK)
+ return res;
+ bsz -= bytes_to_cache;
+ cur_buf += bytes_to_cache;
+ memset(cached_data8, 0x00, sizeof(cached_data8));
+ cached_bytes = 0;
+ }
+ /* write full dwords */
+ for (unsigned int k = 0; (k + sizeof(uint32_t)) <= bsz; k += sizeof(uint32_t)) {
+ uint32_t temp = target_buffer_get_u32(target, cur_buf);
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp);
+ if (res != ERROR_OK)
+ return res;
+ cur_buf += sizeof(uint32_t);
+ }
+ /* if there are bytes to be cached (1..3) */
+ bytes_to_cache = bsz & 0x3UL;
+ if (bytes_to_cache > 0) {
+ if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) {
+ memcpy(&cached_data8[0], cur_buf, sizeof(uint32_t) - cached_bytes);
+ cached_data32 = target_buffer_get_u32(target, cached_data8);
+ /* write full word of cached bytes */
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
+ if (res != ERROR_OK)
+ return res;
+ /* cache remaining bytes */
+ memset(cached_data8, 0x00, sizeof(cached_data8));
+ cur_buf += sizeof(uint32_t) - cached_bytes;
+ cached_bytes = bytes_to_cache + cached_bytes - sizeof(uint32_t);
+ memcpy(&cached_data8[0], cur_buf, cached_bytes);
+ } else {
+ memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache);
+ cached_bytes += bytes_to_cache;
+ }
+ }
+ }
+ if (cached_bytes) {
+ /* write remaining cached bytes */
+ cached_data32 = target_buffer_get_u32(target, cached_data8);
+ res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32);
+ if (res != ERROR_OK)
+ return res;
+ }
+ return ERROR_OK;
+}
+
+static int esp_xtensa_apptrace_buffs_write(struct target *target,
+ uint32_t bufs_num,
+ uint32_t buf_sz[],
+ const uint8_t *bufs[],
+ uint32_t block_id,
+ bool ack,
+ bool data)
+{
+ struct xtensa *xtensa = target_to_xtensa(target);
+ int res = ERROR_OK;
+ uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT |
+ (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) |
+ XTENSA_APPTRACE_BLOCK_LEN(0);
+
+ if (xtensa->core_config->trace.reversed_mem_access)
+ res = esp_xtensa_apptrace_queue_reverse_write(target, bufs_num, buf_sz, bufs);
+ else
+ res = esp_xtensa_apptrace_queue_normal_write(target, bufs_num, buf_sz, bufs);
+ if (res != ERROR_OK)
+ return res;
+ if (ack) {
+ LOG_DEBUG("Ack block %" PRId32 " on target (%s)!", block_id, target_name(target));
+ res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp);
+ if (res != ERROR_OK)
+ return res;
+ }
+ xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod);
+ res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Failed to exec JTAG queue!");
+ return res;
+ }
+ return ERROR_OK;
+}
diff --git a/src/target/espressif/esp_xtensa_apptrace.h b/src/target/espressif/esp_xtensa_apptrace.h
new file mode 100644
index 0000000..0a9be73
--- /dev/null
+++ b/src/target/espressif/esp_xtensa_apptrace.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Xtensa application tracing module for OpenOCD *
+ * Copyright (C) 2017 Espressif Systems Ltd. *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H
+#define OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H
+
+#include "esp32_apptrace.h"
+
+struct esp_xtensa_apptrace_info {
+ const struct esp32_apptrace_hw *hw;
+};
+
+extern struct esp32_apptrace_hw esp_xtensa_apptrace_hw;
+
+int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len);
+int esp_xtensa_apptrace_data_read(struct target *target,
+ uint32_t size,
+ uint8_t *buffer,
+ uint32_t block_id,
+ bool ack);
+int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn);
+int esp_xtensa_apptrace_ctrl_reg_write(struct target *target,
+ uint32_t block_id,
+ uint32_t len,
+ bool conn,
+ bool data);
+int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat);
+int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat);
+uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target);
+uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target);
+int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size);
+
+#endif /* OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H */
diff --git a/src/target/etm.c b/src/target/etm.c
index 57417c3..6718875 100644
--- a/src/target/etm.c
+++ b/src/target/etm.c
@@ -1706,7 +1706,7 @@ COMMAND_HANDLER(handle_etm_dump_command)
return ERROR_FAIL;
}
- if (etm_ctx->capture_driver->status == TRACE_IDLE) {
+ if (etm_ctx->capture_driver->status(etm_ctx) == TRACE_IDLE) {
command_print(CMD, "trace capture wasn't enabled, no trace data captured");
return ERROR_OK;
}
diff --git a/src/target/lakemont.c b/src/target/lakemont.c
index 5035cdb..6c0964b 100644
--- a/src/target/lakemont.c
+++ b/src/target/lakemont.c
@@ -73,26 +73,26 @@ static const struct {
const char *feature;
} regs[] = {
/* general purpose registers */
- { EAX, "eax", 0x000000D01D660000, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { ECX, "ecx", 0x000000501D660000, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { EDX, "edx", 0x000000901D660000, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { EBX, "ebx", 0x000000101D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { ESP, "esp", 0x000000E01D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
- { EBP, "ebp", 0x000000601D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
- { ESI, "esi", 0x000000A01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { EDI, "edi", 0x000000201D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { EAX, "eax", 0x000000D01D660000ULL, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { ECX, "ecx", 0x000000501D660000ULL, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { EDX, "edx", 0x000000901D660000ULL, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { EBX, "ebx", 0x000000101D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { ESP, "esp", 0x000000E01D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
+ { EBP, "ebp", 0x000000601D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" },
+ { ESI, "esi", 0x000000A01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { EDI, "edi", 0x000000201D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
/* instruction pointer & flags */
- { EIP, "eip", 0x000000C01D660000, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" },
- { EFLAGS, "eflags", 0x000000401D660000, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { EIP, "eip", 0x000000C01D660000ULL, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" },
+ { EFLAGS, "eflags", 0x000000401D660000ULL, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
/* segment registers */
- { CS, "cs", 0x000000281D660000, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { SS, "ss", 0x000000C81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { DS, "ds", 0x000000481D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { ES, "es", 0x000000A81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { FS, "fs", 0x000000881D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
- { GS, "gs", 0x000000081D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { CS, "cs", 0x000000281D660000ULL, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { SS, "ss", 0x000000C81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { DS, "ds", 0x000000481D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { ES, "es", 0x000000A81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { FS, "fs", 0x000000881D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
+ { GS, "gs", 0x000000081D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
/* floating point unit registers - not accessible via JTAG - here to satisfy GDB */
{ ST0, "st0", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
@@ -113,56 +113,56 @@ static const struct {
{ FOP, "fop", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" },
/* control registers */
- { CR0, "cr0", 0x000000001D660000, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { CR2, "cr2", 0x000000BC1D660000, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { CR3, "cr3", 0x000000801D660000, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { CR4, "cr4", 0x0000002C1D660000, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CR0, "cr0", 0x000000001D660000ULL, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CR2, "cr2", 0x000000BC1D660000ULL, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CR3, "cr3", 0x000000801D660000ULL, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CR4, "cr4", 0x0000002C1D660000ULL, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
/* debug registers */
- { DR0, "dr0", 0x0000007C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DR1, "dr1", 0x000000FC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DR2, "dr2", 0x000000021D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DR3, "dr3", 0x000000821D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DR6, "dr6", 0x000000301D660000, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DR7, "dr7", 0x000000B01D660000, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR0, "dr0", 0x0000007C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR1, "dr1", 0x000000FC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR2, "dr2", 0x000000021D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR3, "dr3", 0x000000821D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR6, "dr6", 0x000000301D660000ULL, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DR7, "dr7", 0x000000B01D660000ULL, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
/* descriptor tables */
- { IDTB, "idtbase", 0x000000581D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { IDTL, "idtlimit", 0x000000D81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { IDTAR, "idtar", 0x000000981D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GDTB, "gdtbase", 0x000000B81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GDTL, "gdtlimit", 0x000000781D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GDTAR, "gdtar", 0x000000381D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { TR, "tr", 0x000000701D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { LDTR, "ldtr", 0x000000F01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { LDTB, "ldbase", 0x000000041D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { LDTL, "ldlimit", 0x000000841D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { LDTAR, "ldtar", 0x000000F81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { IDTB, "idtbase", 0x000000581D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { IDTL, "idtlimit", 0x000000D81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { IDTAR, "idtar", 0x000000981D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GDTB, "gdtbase", 0x000000B81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GDTL, "gdtlimit", 0x000000781D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GDTAR, "gdtar", 0x000000381D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { TR, "tr", 0x000000701D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { LDTR, "ldtr", 0x000000F01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { LDTB, "ldbase", 0x000000041D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { LDTL, "ldlimit", 0x000000841D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { LDTAR, "ldtar", 0x000000F81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
/* segment registers */
- { CSB, "csbase", 0x000000F41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { CSL, "cslimit", 0x0000000C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { CSAR, "csar", 0x000000741D660000, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DSB, "dsbase", 0x000000941D660000, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DSL, "dslimit", 0x000000541D660000, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { DSAR, "dsar", 0x000000141D660000, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { ESB, "esbase", 0x0000004C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { ESL, "eslimit", 0x000000CC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { ESAR, "esar", 0x0000008C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { FSB, "fsbase", 0x000000641D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { FSL, "fslimit", 0x000000E41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { FSAR, "fsar", 0x000000A41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GSB, "gsbase", 0x000000C41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GSL, "gslimit", 0x000000241D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { GSAR, "gsar", 0x000000441D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { SSB, "ssbase", 0x000000341D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { SSL, "sslimit", 0x000000B41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { SSAR, "ssar", 0x000000D41D660000, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { TSSB, "tssbase", 0x000000E81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { TSSL, "tsslimit", 0x000000181D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
- { TSSAR, "tssar", 0x000000681D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CSB, "csbase", 0x000000F41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CSL, "cslimit", 0x0000000C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { CSAR, "csar", 0x000000741D660000ULL, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DSB, "dsbase", 0x000000941D660000ULL, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DSL, "dslimit", 0x000000541D660000ULL, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { DSAR, "dsar", 0x000000141D660000ULL, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { ESB, "esbase", 0x0000004C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { ESL, "eslimit", 0x000000CC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { ESAR, "esar", 0x0000008C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { FSB, "fsbase", 0x000000641D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { FSL, "fslimit", 0x000000E41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { FSAR, "fsar", 0x000000A41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GSB, "gsbase", 0x000000C41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GSL, "gslimit", 0x000000241D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { GSAR, "gsar", 0x000000441D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { SSB, "ssbase", 0x000000341D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { SSL, "sslimit", 0x000000B41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { SSAR, "ssar", 0x000000D41D660000ULL, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { TSSB, "tssbase", 0x000000E81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { TSSL, "tsslimit", 0x000000181D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { TSSAR, "tssar", 0x000000681D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
/* probemode control register */
- { PMCR, "pmcr", 0x000000421D660000, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
+ { PMCR, "pmcr", 0x000000421D660000ULL, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" },
};
static const struct {
@@ -171,36 +171,36 @@ static const struct {
uint64_t op;
} instructions[] = {
/* memory read/write */
- { MEMRDB32, "MEMRDB32", 0x0909090909090851 },
- { MEMRDB16, "MEMRDB16", 0x09090909090851E6 },
- { MEMRDH32, "MEMRDH32", 0x090909090908D166 },
- { MEMRDH16, "MEMRDH16", 0x090909090908D1E6 },
- { MEMRDW32, "MEMRDW32", 0x09090909090908D1 },
- { MEMRDW16, "MEMRDW16", 0x0909090908D1E666 },
- { MEMWRB32, "MEMWRB32", 0x0909090909090811 },
- { MEMWRB16, "MEMWRB16", 0x09090909090811E6 },
- { MEMWRH32, "MEMWRH32", 0x0909090909089166 },
- { MEMWRH16, "MEMWRH16", 0x09090909090891E6 },
- { MEMWRW32, "MEMWRW32", 0x0909090909090891 },
- { MEMWRW16, "MEMWRW16", 0x090909090891E666 },
+ { MEMRDB32, "MEMRDB32", 0x0909090909090851ULL },
+ { MEMRDB16, "MEMRDB16", 0x09090909090851E6ULL },
+ { MEMRDH32, "MEMRDH32", 0x090909090908D166ULL },
+ { MEMRDH16, "MEMRDH16", 0x090909090908D1E6ULL },
+ { MEMRDW32, "MEMRDW32", 0x09090909090908D1ULL },
+ { MEMRDW16, "MEMRDW16", 0x0909090908D1E666ULL },
+ { MEMWRB32, "MEMWRB32", 0x0909090909090811ULL },
+ { MEMWRB16, "MEMWRB16", 0x09090909090811E6ULL },
+ { MEMWRH32, "MEMWRH32", 0x0909090909089166ULL },
+ { MEMWRH16, "MEMWRH16", 0x09090909090891E6ULL },
+ { MEMWRW32, "MEMWRW32", 0x0909090909090891ULL },
+ { MEMWRW16, "MEMWRW16", 0x090909090891E666ULL },
/* IO read/write */
- { IORDB32, "IORDB32", 0x0909090909090937 },
- { IORDB16, "IORDB16", 0x09090909090937E6 },
- { IORDH32, "IORDH32", 0x090909090909B766 },
- { IORDH16, "IORDH16", 0x090909090909B7E6 },
- { IORDW32, "IORDW32", 0x09090909090909B7 },
- { IORDW16, "IORDW16", 0x0909090909B7E666 },
- { IOWRB32, "IOWRB32", 0x0909090909090977 },
- { IOWRB16, "IOWRB16", 0x09090909090977E6 },
- { IOWRH32, "IOWRH32", 0x090909090909F766 },
- { IOWRH16, "IOWRH16", 0x090909090909F7E6 },
- { IOWRW32, "IOWRW32", 0x09090909090909F7 },
- { IOWRW16, "IOWRW16", 0x0909090909F7E666 },
+ { IORDB32, "IORDB32", 0x0909090909090937ULL },
+ { IORDB16, "IORDB16", 0x09090909090937E6ULL },
+ { IORDH32, "IORDH32", 0x090909090909B766ULL },
+ { IORDH16, "IORDH16", 0x090909090909B7E6ULL },
+ { IORDW32, "IORDW32", 0x09090909090909B7ULL },
+ { IORDW16, "IORDW16", 0x0909090909B7E666ULL },
+ { IOWRB32, "IOWRB32", 0x0909090909090977ULL },
+ { IOWRB16, "IOWRB16", 0x09090909090977E6ULL },
+ { IOWRH32, "IOWRH32", 0x090909090909F766ULL },
+ { IOWRH16, "IOWRH16", 0x090909090909F7E6ULL },
+ { IOWRW32, "IOWRW32", 0x09090909090909F7ULL },
+ { IOWRW16, "IOWRW16", 0x0909090909F7E666ULL },
/* lakemont1 core shadow ram access opcodes */
- { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000 },
- { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000 },
- { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000 },
- { WBINVD, "WBINVD", 0x09090909090990F0 },
+ { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000ULL },
+ { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000ULL },
+ { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000ULL },
+ { WBINVD, "WBINVD", 0x09090909090990F0ULL },
};
bool check_not_halted(const struct target *t)
diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h
index 65ff6e6..19d1519 100644
--- a/src/target/mips64_pracc.h
+++ b/src/target/mips64_pracc.h
@@ -29,7 +29,7 @@
#undef LOWER16
#define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF))
#define LOWER16(v) ((uint32_t)(v & 0xFFFF))
-#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000
+#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000ull
#define MIPS64_PRACC_FASTDATA_SIZE 16
#define MIPS64_FASTDATA_HANDLER_SIZE 0x80
diff --git a/src/target/rtt.c b/src/target/rtt.c
index b14c42f..5ce049a 100644
--- a/src/target/rtt.c
+++ b/src/target/rtt.c
@@ -14,6 +14,7 @@
#include <helper/binarybuffer.h>
#include <helper/command.h>
#include <rtt/rtt.h>
+#include <target/rtt.h>
#include "target.h"
diff --git a/src/target/stm8.c b/src/target/stm8.c
index aa934c9..9fd6509 100644
--- a/src/target/stm8.c
+++ b/src/target/stm8.c
@@ -542,12 +542,12 @@ static int stm8_get_core_reg(struct reg *reg)
int retval;
struct stm8_core_reg *stm8_reg = reg->arch_info;
struct target *target = stm8_reg->target;
- struct stm8_common *stm8_target = target_to_stm8(target);
+ struct stm8_common *stm8 = target_to_stm8(target);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- retval = stm8_target->read_core_reg(target, stm8_reg->num);
+ retval = stm8->read_core_reg(target, stm8_reg->num);
return retval;
}
diff --git a/src/target/target.c b/src/target/target.c
index 3a40c04..c592a71 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -31,6 +31,7 @@
#endif
#include <helper/align.h>
+#include <helper/nvp.h>
#include <helper/time_support.h>
#include <jtag/jtag.h>
#include <flash/nor/core.h>
@@ -65,45 +66,6 @@ static int target_get_gdb_fileio_info_default(struct target *target,
static int target_gdb_fileio_end_default(struct target *target, int retcode,
int fileio_errno, bool ctrl_c);
-/* targets */
-extern struct target_type arm7tdmi_target;
-extern struct target_type arm720t_target;
-extern struct target_type arm9tdmi_target;
-extern struct target_type arm920t_target;
-extern struct target_type arm966e_target;
-extern struct target_type arm946e_target;
-extern struct target_type arm926ejs_target;
-extern struct target_type fa526_target;
-extern struct target_type feroceon_target;
-extern struct target_type dragonite_target;
-extern struct target_type xscale_target;
-extern struct target_type xtensa_chip_target;
-extern struct target_type cortexm_target;
-extern struct target_type cortexa_target;
-extern struct target_type aarch64_target;
-extern struct target_type cortexr4_target;
-extern struct target_type arm11_target;
-extern struct target_type ls1_sap_target;
-extern struct target_type mips_m4k_target;
-extern struct target_type mips_mips64_target;
-extern struct target_type avr_target;
-extern struct target_type dsp563xx_target;
-extern struct target_type dsp5680xx_target;
-extern struct target_type testee_target;
-extern struct target_type avr32_ap7k_target;
-extern struct target_type hla_target;
-extern struct target_type esp32_target;
-extern struct target_type esp32s2_target;
-extern struct target_type esp32s3_target;
-extern struct target_type or1k_target;
-extern struct target_type quark_x10xx_target;
-extern struct target_type quark_d20xx_target;
-extern struct target_type stm8_target;
-extern struct target_type riscv_target;
-extern struct target_type mem_ap_target;
-extern struct target_type esirisc_target;
-extern struct target_type arcv2_target;
-
static struct target_type *target_types[] = {
&arm7tdmi_target,
&arm9tdmi_target,
@@ -141,6 +103,7 @@ static struct target_type *target_types[] = {
&esirisc_target,
&arcv2_target,
&aarch64_target,
+ &armv8r_target,
&mips_mips64_target,
NULL,
};
@@ -154,7 +117,12 @@ static LIST_HEAD(target_trace_callback_list);
static const unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL;
static LIST_HEAD(empty_smp_targets);
-static const struct jim_nvp nvp_assert[] = {
+enum nvp_assert {
+ NVP_DEASSERT,
+ NVP_ASSERT,
+};
+
+static const struct nvp nvp_assert[] = {
{ .name = "assert", NVP_ASSERT },
{ .name = "deassert", NVP_DEASSERT },
{ .name = "T", NVP_ASSERT },
@@ -164,7 +132,7 @@ static const struct jim_nvp nvp_assert[] = {
{ .name = NULL, .value = -1 }
};
-static const struct jim_nvp nvp_error_target[] = {
+static const struct nvp nvp_error_target[] = {
{ .value = ERROR_TARGET_INVALID, .name = "err-invalid" },
{ .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" },
{ .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" },
@@ -181,9 +149,9 @@ static const struct jim_nvp nvp_error_target[] = {
static const char *target_strerror_safe(int err)
{
- const struct jim_nvp *n;
+ const struct nvp *n;
- n = jim_nvp_value2name_simple(nvp_error_target, err);
+ n = nvp_value2name(nvp_error_target, err);
if (!n->name)
return "unknown";
else
@@ -252,7 +220,7 @@ static const struct jim_nvp nvp_target_state[] = {
{ .name = NULL, .value = -1 },
};
-static const struct jim_nvp nvp_target_debug_reason[] = {
+static const struct nvp nvp_target_debug_reason[] = {
{ .name = "debug-request", .value = DBG_REASON_DBGRQ },
{ .name = "breakpoint", .value = DBG_REASON_BREAKPOINT },
{ .name = "watchpoint", .value = DBG_REASON_WATCHPOINT },
@@ -273,7 +241,7 @@ static const struct jim_nvp nvp_target_endian[] = {
{ .name = NULL, .value = -1 },
};
-static const struct jim_nvp nvp_reset_modes[] = {
+static const struct nvp nvp_reset_modes[] = {
{ .name = "unknown", .value = RESET_UNKNOWN },
{ .name = "run", .value = RESET_RUN },
{ .name = "halt", .value = RESET_HALT },
@@ -285,7 +253,7 @@ const char *debug_reason_name(struct target *t)
{
const char *cp;
- cp = jim_nvp_value2name_simple(nvp_target_debug_reason,
+ cp = nvp_value2name(nvp_target_debug_reason,
t->debug_reason)->name;
if (!cp) {
LOG_ERROR("Invalid debug reason: %d", (int)(t->debug_reason));
@@ -323,7 +291,7 @@ const char *target_event_name(enum target_event event)
const char *target_reset_mode_name(enum target_reset_mode reset_mode)
{
const char *cp;
- cp = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name;
+ cp = nvp_value2name(nvp_reset_modes, reset_mode)->name;
if (!cp) {
LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode));
cp = "(*BUG*unknown*BUG*)";
@@ -667,8 +635,8 @@ static int target_process_reset(struct command_invocation *cmd, enum target_rese
{
char buf[100];
int retval;
- struct jim_nvp *n;
- n = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode);
+ const struct nvp *n;
+ n = nvp_value2name(nvp_reset_modes, reset_mode);
if (!n->name) {
LOG_ERROR("invalid reset mode");
return ERROR_FAIL;
@@ -1864,7 +1832,7 @@ int target_call_reset_callbacks(struct target *target, enum target_reset_mode re
struct target_reset_callback *callback;
LOG_DEBUG("target reset %i (%s)", reset_mode,
- jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name);
+ nvp_value2name(nvp_reset_modes, reset_mode)->name);
list_for_each_entry(callback, &target_reset_callback_list, list)
callback->callback(target, reset_mode, callback->priv);
@@ -3337,8 +3305,8 @@ COMMAND_HANDLER(handle_reset_command)
enum target_reset_mode reset_mode = RESET_RUN;
if (CMD_ARGC == 1) {
- const struct jim_nvp *n;
- n = jim_nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]);
+ const struct nvp *n;
+ n = nvp_name2value(nvp_reset_modes, CMD_ARGV[0]);
if ((!n->name) || (n->value == RESET_UNKNOWN))
return ERROR_COMMAND_SYNTAX_ERROR;
reset_mode = n->value;
@@ -5752,62 +5720,47 @@ COMMAND_HANDLER(handle_target_halt_gdb)
return target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
}
-static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_poll)
{
- if (argc != 1) {
- Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
- return JIM_ERR;
+ if (CMD_ARGC != 0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target->tap->enabled) {
+ command_print(CMD, "[TAP is disabled]");
+ return ERROR_FAIL;
}
- 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);
- int e;
if (!(target_was_examined(target)))
- e = ERROR_TARGET_NOT_EXAMINED;
- else
- e = target->type->poll(target);
- if (e != ERROR_OK)
- return JIM_ERR;
- return JIM_OK;
+ return ERROR_TARGET_NOT_EXAMINED;
+
+ return target->type->poll(target);
}
-static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_reset)
{
- struct jim_getopt_info goi;
- jim_getopt_setup(&goi, interp, argc - 1, argv + 1);
+ if (CMD_ARGC != 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
- if (goi.argc != 2) {
- Jim_WrongNumArgs(interp, 0, argv,
- "([tT]|[fF]|assert|deassert) BOOL");
- return JIM_ERR;
+ const struct nvp *n = nvp_name2value(nvp_assert, CMD_ARGV[0]);
+ if (!n->name) {
+ nvp_unknown_command_print(CMD, nvp_assert, NULL, CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
- struct jim_nvp *n;
- int e = jim_getopt_nvp(&goi, nvp_assert, &n);
- if (e != JIM_OK) {
- jim_getopt_nvp_unknown(&goi, nvp_assert, 1);
- return e;
- }
/* the halt or not param */
- jim_wide a;
- e = jim_getopt_wide(&goi, &a);
- if (e != JIM_OK)
- return e;
+ int a;
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], a);
- 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);
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target->tap->enabled) {
+ command_print(CMD, "[TAP is disabled]");
+ return ERROR_FAIL;
+ }
if (!target->type->assert_reset || !target->type->deassert_reset) {
- Jim_SetResultFormatted(interp,
- "No target-specific reset for %s",
- target_name(target));
- return JIM_ERR;
+ command_print(CMD, "No target-specific reset for %s", target_name(target));
+ return ERROR_FAIL;
}
if (target->defer_examine)
@@ -5820,25 +5773,22 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* do the assert */
if (n->value == NVP_ASSERT)
- e = target->type->assert_reset(target);
- else
- e = target->type->deassert_reset(target);
- return (e == ERROR_OK) ? JIM_OK : JIM_ERR;
+ return target->type->assert_reset(target);
+ return target->type->deassert_reset(target);
}
-static int jim_target_halt(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+COMMAND_HANDLER(handle_target_halt)
{
- if (argc != 1) {
- Jim_WrongNumArgs(interp, 1, argv, "[no parameters]");
- return JIM_ERR;
+ if (CMD_ARGC != 0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct target *target = get_current_target(CMD_CTX);
+ if (!target->tap->enabled) {
+ command_print(CMD, "[TAP is disabled]");
+ return ERROR_FAIL;
}
- 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);
- int e = target->type->halt(target);
- return (e == ERROR_OK) ? JIM_OK : JIM_ERR;
+
+ return target->type->halt(target);
}
static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -6099,20 +6049,23 @@ static const struct command_registration target_instance_command_handlers[] = {
{
.name = "arp_poll",
.mode = COMMAND_EXEC,
- .jim_handler = jim_target_poll,
+ .handler = handle_target_poll,
.help = "used internally for reset processing",
+ .usage = "",
},
{
.name = "arp_reset",
.mode = COMMAND_EXEC,
- .jim_handler = jim_target_reset,
+ .handler = handle_target_reset,
.help = "used internally for reset processing",
+ .usage = "'assert'|'deassert' halt",
},
{
.name = "arp_halt",
.mode = COMMAND_EXEC,
- .jim_handler = jim_target_halt,
+ .handler = handle_target_halt,
.help = "used internally for reset processing",
+ .usage = "",
},
{
.name = "arp_waitstate",
diff --git a/src/target/target.h b/src/target/target.h
index 8589e17..da4612c 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -60,11 +60,6 @@ enum target_state {
TARGET_UNAVAILABLE = 5
};
-enum nvp_assert {
- NVP_DEASSERT,
- NVP_ASSERT,
-};
-
enum target_reset_mode {
RESET_UNKNOWN = 0,
RESET_RUN = 1, /* reset and let target run */
diff --git a/src/target/target_type.h b/src/target/target_type.h
index 9470803..5186e9c 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -311,4 +311,43 @@ struct target_type {
unsigned int (*data_bits)(struct target *target);
};
+extern struct target_type aarch64_target;
+extern struct target_type arcv2_target;
+extern struct target_type arm11_target;
+extern struct target_type arm720t_target;
+extern struct target_type arm7tdmi_target;
+extern struct target_type arm920t_target;
+extern struct target_type arm926ejs_target;
+extern struct target_type arm946e_target;
+extern struct target_type arm966e_target;
+extern struct target_type arm9tdmi_target;
+extern struct target_type armv8r_target;
+extern struct target_type avr32_ap7k_target;
+extern struct target_type avr_target;
+extern struct target_type cortexa_target;
+extern struct target_type cortexm_target;
+extern struct target_type cortexr4_target;
+extern struct target_type dragonite_target;
+extern struct target_type dsp563xx_target;
+extern struct target_type dsp5680xx_target;
+extern struct target_type esirisc_target;
+extern struct target_type esp32s2_target;
+extern struct target_type esp32s3_target;
+extern struct target_type esp32_target;
+extern struct target_type fa526_target;
+extern struct target_type feroceon_target;
+extern struct target_type hla_target;
+extern struct target_type ls1_sap_target;
+extern struct target_type mem_ap_target;
+extern struct target_type mips_m4k_target;
+extern struct target_type mips_mips64_target;
+extern struct target_type or1k_target;
+extern struct target_type quark_d20xx_target;
+extern struct target_type quark_x10xx_target;
+extern struct target_type riscv_target;
+extern struct target_type stm8_target;
+extern struct target_type testee_target;
+extern struct target_type xscale_target;
+extern struct target_type xtensa_chip_target;
+
#endif /* OPENOCD_TARGET_TARGET_TYPE_H */
diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index 18bdaa0..5880637 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -410,7 +410,7 @@ static int xtensa_core_reg_get(struct reg *reg)
return ERROR_TARGET_NOT_HALTED;
if (!reg->exist) {
if (strncmp(reg->name, "?0x", 3) == 0) {
- unsigned int regnum = strtoul(reg->name + 1, 0, 0);
+ unsigned int regnum = strtoul(reg->name + 1, NULL, 0);
LOG_WARNING("Read unknown register 0x%04x ignored", regnum);
return ERROR_OK;
}
@@ -430,7 +430,7 @@ static int xtensa_core_reg_set(struct reg *reg, uint8_t *buf)
if (!reg->exist) {
if (strncmp(reg->name, "?0x", 3) == 0) {
- unsigned int regnum = strtoul(reg->name + 1, 0, 0);
+ unsigned int regnum = strtoul(reg->name + 1, NULL, 0);
LOG_WARNING("Write unknown register 0x%04x ignored", regnum);
return ERROR_OK;
}
diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg
new file mode 100644
index 0000000..7781bd5
--- /dev/null
+++ b/tcl/board/bemicro_cycloneiii.cfg
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# BeMicro Cyclone III
+
+
+adapter driver ftdi
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+ftdi vid_pid 0x0403 0xa4a0
+reset_config none
+transport select jtag
+
+adapter speed 10000
+
+source [find cpld/altera-cycloneiii.cfg]
+
+#quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf
+
+#openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load 0 cycloneiii_blinker.rbf"
+# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555"
diff --git a/tcl/board/certuspro_evaluation.cfg b/tcl/board/certuspro_evaluation.cfg
new file mode 100644
index 0000000..5ff2a1e
--- /dev/null
+++ b/tcl/board/certuspro_evaluation.cfg
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 10000
+
+source [find fpga/lattice_certuspro.cfg]
diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg
new file mode 100644
index 0000000..427037b
--- /dev/null
+++ b/tcl/board/ecp5_evaluation.cfg
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Lattice ECP5 evaluation Kit
+# https://www.latticesemi.com/view_document?document_id=52479
+#
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 6000
+
+source [find fpga/lattice_ecp5.cfg]
+
+#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load 0 shared_folder/ecp5_blinker_impl1.bit"
+#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0
diff --git a/tcl/board/gatemate_eval.cfg b/tcl/board/gatemate_eval.cfg
new file mode 100644
index 0000000..cc078a0
--- /dev/null
+++ b/tcl/board/gatemate_eval.cfg
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# GateMateTM FPGA Evaluation Board
+# https://www.colognechip.com/programmable-logic/gatemate-evaluation-board/
+#
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0014 0x011b
+reset_config none
+transport select jtag
+adapter speed 6000
+
+source [find fpga/gatemate.cfg]
diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg
new file mode 100644
index 0000000..9496c6f
--- /dev/null
+++ b/tcl/board/gowin_runber.cfg
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Gowin RUNBER FPGA Development Board
+# https://www.seeedstudio.com/Gowin-RUNBER-Development-Board-p-4779.html
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 0
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 6000
+
+source [find fpga/gowin_gw1n.cfg]
+
+
+#openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs"
+#ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0
diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg
new file mode 100644
index 0000000..045d63d
--- /dev/null
+++ b/tcl/board/trion_t20_bga256.cfg
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Trion® T20 BGA256 Development Kit
+# https://www.efinixinc.com/docs/trion20-devkit-ug-v1.5.pdf
+#
+# works after power cycle or pushing sw1.
+# it is because we cannot control CDONE which is connected to ftdi channel 0
+# note from an006: For JTAG programming, T4, T8, T13, and T20 FPGAs use the
+# CRESET_N and SS_N pins in addition to the standard JTAG pins.
+
+adapter driver ftdi
+ftdi vid_pid 0x0403 0x6010
+
+ftdi channel 1
+ftdi layout_init 0x0008 0x008b
+reset_config none
+transport select jtag
+adapter speed 6000
+
+source [find fpga/efinix_trion.cfg]
+
+#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load 0 outflow/trion_blinker.bit"
+#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0
+
diff --git a/tcl/cpld/altera-5m570z-cpld.cfg b/tcl/cpld/altera-5m570z-cpld.cfg
index 5dbd0de..4504a80 100644
--- a/tcl/cpld/altera-5m570z-cpld.cfg
+++ b/tcl/cpld/altera-5m570z-cpld.cfg
@@ -1,8 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# Altera MAXV 5M24OZ/5M570Z CPLD
-# see MAX V Device Handbook
-# Table 6-3: 32-Bit MAX V Device IDCODE
-# Version Part Number Manuf. ID LSB
-# 0000 0010 0000 1010 0111 000 0110 1110 1
-jtag newtap 5m570z tap -expected-id 0x020a60dd -irlen 10
+# file altera-5m570z-cpld.cfg replaced by altera-maxv.cfg
+echo "DEPRECATED: use altera-maxv.cfg instead of deprecated altera-5m570z-cpld.cfg"
+
+#just to be backward compatible:
+#tap will be 5m570z.tap instead of maxv.tap:
+set CHIPNAME 5m570z
+source [find cpld/altera-maxv.cfg]
diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg
index 39c409b..185925a 100644
--- a/tcl/cpld/altera-epm240.cfg
+++ b/tcl/cpld/altera-epm240.cfg
@@ -1,24 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# Altera MAXII EPM240T100C CPLD
+# file altera-epm240.cfg replaced by altera-maxii.cfg
+echo "DEPRECATED: use altera-maxii.cfg instead of deprecated altera-epm240.cfg"
-if { [info exists CHIPNAME] } {
- set _CHIPNAME $CHIPNAME
-} else {
- set _CHIPNAME epm240
-}
-
-# see MAX II Device Handbook
-# Table 3-3: 32-Bit MAX II Device IDCODE
-# Version Part Number Manuf. ID LSB
-# 0000 0010 0000 1010 0001 000 0110 1110 1
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x020a10dd \
- -expected-id 0x020a20dd \
- -expected-id 0x020a30dd \
- -expected-id 0x020a40dd \
- -expected-id 0x020a50dd \
- -expected-id 0x020a60dd
+#just to be backward compatible:
+#tap will be epm240.tap instead of maxii.tap:
+set CHIPNAME epm240
+source [find cpld/altera-maxii.cfg]
# 200ns seems like a good speed
# c.f. Table 5-34: MAX II JTAG Timing Parameters
diff --git a/tcl/cpld/altera-max10.cfg b/tcl/cpld/altera-max10.cfg
new file mode 100644
index 0000000..a2ed00a
--- /dev/null
+++ b/tcl/cpld/altera-max10.cfg
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# see MAX 10 FPGA Device Architecture
+# Table 3-1: IDCODE Information for MAX 10 Devices
+# Intel MAX 10M02 0x31810dd
+# Intel MAX 10M04 0x318a0dd
+# Intel MAX 10M08 0x31820dd
+# Intel MAX 10M16 0x31830dd
+# Intel MAX 10M25 0x31840dd
+# Intel MAX 10M40 0x318d0dd
+# Intel MAX 10M50 0x31850dd
+# Intel MAX 10M02 0x31010dd
+# Intel MAX 10M04 0x310a0dd
+# Intel MAX 10M08 0x31020dd
+# Intel MAX 10M16 0x31030dd
+# Intel MAX 10M25 0x31040dd
+# Intel MAX 10M40 0x310d0dd
+# Intel MAX 10M50 0x31050dd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME max10
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \
+ -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \
+ -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \
+ -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \
+ -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd
diff --git a/tcl/cpld/altera-maxii.cfg b/tcl/cpld/altera-maxii.cfg
new file mode 100644
index 0000000..2dee37f
--- /dev/null
+++ b/tcl/cpld/altera-maxii.cfg
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Altera MAXII CPLD
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME maxii
+}
+
+# see MAX II Device Handbook
+# Table 3-3: 32-Bit MAX II Device IDCODE
+# Version Part Number Manuf. ID LSB
+# 0000 0010 0000 1010 0001 000 0110 1110 1
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x020a10dd \
+ -expected-id 0x020a20dd \
+ -expected-id 0x020a30dd \
+ -expected-id 0x020a40dd \
+ -expected-id 0x020a50dd \
+ -expected-id 0x020a60dd
diff --git a/tcl/cpld/altera-maxv.cfg b/tcl/cpld/altera-maxv.cfg
new file mode 100644
index 0000000..03fad07
--- /dev/null
+++ b/tcl/cpld/altera-maxv.cfg
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Altera MAXV 5M24OZ/5M570Z CPLD
+# see MAX V Device Handbook
+# Table 6-3: 32-Bit MAX V Device IDCODE
+# 5M40Z 5M80Z 5M160Z 5M240Z: 0x020A50DD
+# 5M570Z: 0x020A60DD
+# 5M1270Z: 0x020A30DD
+# 5M1270Z 5M2210Z: 0x020A40DD
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME maxv
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x020A50DD -expected-id 0x020A60DD \
+ -expected-id 0x020A30DD -expected-id 0x020A40DD
diff --git a/tcl/fpga/altera-10m50.cfg b/tcl/fpga/altera-10m50.cfg
index 1937cb4..94228d2 100644
--- a/tcl/fpga/altera-10m50.cfg
+++ b/tcl/fpga/altera-10m50.cfg
@@ -1,24 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# see MAX 10 FPGA Device Architecture
-# Table 3-1: IDCODE Information for MAX 10 Devices
-# Intel MAX 10M02 0x31810dd
-# Intel MAX 10M04 0x318a0dd
-# Intel MAX 10M08 0x31820dd
-# Intel MAX 10M16 0x31830dd
-# Intel MAX 10M25 0x31840dd
-# Intel MAX 10M40 0x318d0dd
-# Intel MAX 10M50 0x31850dd
-# Intel MAX 10M02 0x31010dd
-# Intel MAX 10M04 0x310a0dd
-# Intel MAX 10M08 0x31020dd
-# Intel MAX 10M16 0x31030dd
-# Intel MAX 10M25 0x31040dd
-# Intel MAX 10M40 0x310d0dd
-# Intel MAX 10M50 0x31050dd
+# file altera-10m50.cfg replaced by altera-max10.cfg
+echo "DEPRECATED: use altera-max10.cfg instead of deprecated altera-10m50.cfg"
-jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \
- -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \
- -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \
- -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \
- -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd
+#just to be backward compatible:
+#tap will be 10m50.tap instead of max10.tap:
+set CHIPNAME 10m50
+source [find cpld/altera-max10.cfg]
diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg
new file mode 100644
index 0000000..ae752df
--- /dev/null
+++ b/tcl/fpga/altera-arriaii.cfg
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Intel Arria II FPGA
+# Arria II Device Handbook
+# Table 11–2. 32-Bit IDCODE for Arria II Devices
+
+#GX:
+#EP2AGX45: 0x025120dd
+#EP2AGX65: 0x025020dd
+#EP2AGX95: 0x025130dd
+#EP2AGX125: 0x025030dd
+#EP2AGX190: 0x025140dd
+#EP2AGX260: 0x025040dd
+#EP2AGZ225: 0x024810dd
+#EP2AGZ300: 0x0240a0dd
+#EP2AGZ350: 0x024820dd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME arriaii
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x025120dd -expected-id 0x025040dd \
+ -expected-id 0x025020dd -expected-id 0x024810dd \
+ -expected-id 0x025130dd -expected-id 0x0240a0dd \
+ -expected-id 0x025030dd -expected-id 0x024820dd \
+ -expected-id 0x025140dd
+
+pld device intel $_CHIPNAME.tap arriaii
diff --git a/tcl/fpga/altera-cyclone10.cfg b/tcl/fpga/altera-cyclone10.cfg
new file mode 100644
index 0000000..3a1bc1f
--- /dev/null
+++ b/tcl/fpga/altera-cyclone10.cfg
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Intel Cyclone 10 FPGA
+# see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html
+# and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf
+
+# GX085: 0x02e120dd
+# GX105: 0x02e320dd
+# GX150: 0x02e720dd
+# GX220: 0x02ef20dd
+# 10cl006: 0x020f10dd
+# 10cl010: 0x020f10dd
+# 10cl016: 0x020f20dd
+# 10cl025: 0x020f30dd
+# 10cl040: 0x020f40dd
+# 10cl055: 0x020f50dd
+# 10cl080: 0x020f60dd
+# 10cl120: 0x020f70dd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME cyclone10
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x02e720dd -expected-id 0x02e120dd \
+ -expected-id 0x02ef20dd -expected-id 0x02e320dd \
+ -expected-id 0x020f10dd -expected-id 0x020f20dd \
+ -expected-id 0x020f30dd -expected-id 0x020f40dd \
+ -expected-id 0x020f50dd -expected-id 0x020f60dd \
+ -expected-id 0x020f70dd
+
+pld device intel $_CHIPNAME.tap cyclone10
diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg
new file mode 100644
index 0000000..e143572
--- /dev/null
+++ b/tcl/fpga/altera-cycloneiii.cfg
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Intel Cyclone III FPGA
+# see Cyclone III Device Handbook
+# Table 12-2: Device IDCODE for Cyclone III Device Family
+
+#EP3C5 0x020f10dd
+#EP3C10 0x020f10dd
+#EP3C16 0x020f20dd
+#EP3C25 0x020f30dd
+#EP3C40 0x020f40dd
+#EP3C55 0x020f50dd
+#EP3C80 0x020f60dd
+#EP3C120 0x020f70dd
+#Cyclone III LS
+#EP3CLS70 0x027010dd
+#EP3CLS100 0x027000dd
+#EP3CLS150 0x027030dd
+#EP3CLS200 0x027020dd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME cycloneiii
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x020f10dd -expected-id 0x020f20dd \
+ -expected-id 0x020f30dd -expected-id 0x020f40dd \
+ -expected-id 0x020f50dd -expected-id 0x020f60dd \
+ -expected-id 0x020f70dd -expected-id 0x027010dd \
+ -expected-id 0x027000dd -expected-id 0x027030dd \
+ -expected-id 0x027020dd
+
+pld device intel $_CHIPNAME.tap cycloneiii
diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg
new file mode 100644
index 0000000..59243cf
--- /dev/null
+++ b/tcl/fpga/altera-cycloneiv.cfg
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Intel Cyclone IV FPGA
+# see Cyclone IV Device Handbook
+# Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices
+
+#EP4CE6 0x020f10dd
+#EP4CE10 0x020f10dd
+#EP4CE15 0x020f20dd
+#EP4CE22 0x020f30dd
+#EP4CE30 0x020f40dd
+#EP4CE40 0x020f40dd
+#EP4CE55 0x020f50dd
+#EP4CE75 0x020f60dd
+#EP4CE115 0x020f70dd
+#EP4CGX15 0x028010dd
+#EP4CGX22 0x028120dd
+#EP4CGX30 (3) 0x028020dd
+#EP4CGX30 (4) 0x028230dd
+#EP4CGX50 0x028130dd
+#EP4CGX75 0x028030dd
+#EP4CGX110 0x028140dd
+#EP4CGX150 0x028040dd
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME cycloneiv
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x020f10dd -expected-id 0x020f20dd \
+ -expected-id 0x020f30dd -expected-id 0x020f40dd \
+ -expected-id 0x020f50dd -expected-id 0x020f60dd \
+ -expected-id 0x020f70dd -expected-id 0x028010dd \
+ -expected-id 0x028120dd -expected-id 0x028020dd \
+ -expected-id 0x028230dd -expected-id 0x028130dd \
+ -expected-id 0x028030dd -expected-id 0x028140dd \
+ -expected-id 0x028040dd
+
+pld device intel $_CHIPNAME.tap cycloneiv
diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg
new file mode 100644
index 0000000..1e9c9c4
--- /dev/null
+++ b/tcl/fpga/altera-cyclonev.cfg
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Intel Cyclone 5 FPGA
+# see Cyclone V Device Handbook
+# Table 9-1: IDCODE Information for Cyclone V Devices
+
+#5CEA2 0x02b150dd
+#5CEA4 0x02b050dd
+#5CEA5 0x02b220dd
+#5CEA7 0x02b130dd
+#5CEA9 0x02b140dd
+#5CGXC3 0x02b010dd
+#5CGXC4 0x02b120dd
+#5CGXC5 0x02b020dd
+#5CGXC7 0x02b030dd
+#5CGXC9 0x02b040dd
+#5CGTD5 0x02b020dd
+#5CGTD7 0x02b030dd
+#5CGTD9 0x02b040dd
+#5CSEA2 0x02d110dd
+#5CSEA4 0x02d010dd
+#5CSEA5 0x02d120dd
+#5CSEA6 0x02d020dd
+#5CSXC2 0x02d110dd
+#5CSXC4 0x02d010dd
+#5CSXC5 0x02d120dd
+#5CSXC6 0x02d020dd
+#5CSTD5 0x02d120dd
+#5CSTD6 0x02d020dd
+
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME cyclonev
+}
+
+jtag newtap $_CHIPNAME tap -irlen 10 \
+ -expected-id 0x02b150dd -expected-id 0x02b050dd \
+ -expected-id 0x02b220dd -expected-id 0x02b130dd \
+ -expected-id 0x02b140dd -expected-id 0x02b010dd \
+ -expected-id 0x02b120dd -expected-id 0x02b020dd \
+ -expected-id 0x02b030dd -expected-id 0x02b040dd \
+ -expected-id 0x02d110dd -expected-id 0x02d010dd \
+ -expected-id 0x02d120dd -expected-id 0x02d020dd
+
+pld device intel $_CHIPNAME.tap cyclonev
diff --git a/tcl/fpga/altera-ep3c10.cfg b/tcl/fpga/altera-ep3c10.cfg
index 7c231f9..d7a92d7 100644
--- a/tcl/fpga/altera-ep3c10.cfg
+++ b/tcl/fpga/altera-ep3c10.cfg
@@ -1,6 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# Altera Cyclone III EP3C10
-# see Cyclone III Device Handbook, Volume 1;
-# Table 14–5. 32-Bit Cyclone III Device IDCODE
-jtag newtap ep3c10 tap -expected-id 0x020f10dd -irlen 10
+# file altera-ep3c10.cfg replaced by altera-cycloneiii.cfg
+echo "DEPRECATED: use altera-cycloneiii.cfg instead of deprecated altera-ep3c10.cfg"
+
+#just to be backward compatible:
+#tap will be ep3c10.tap instead of cycloneiii.tap:
+set CHIPNAME ep3c10
+source [find fpga/altera-cycloneiii.cfg]
diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg
new file mode 100644
index 0000000..681b58f
--- /dev/null
+++ b/tcl/fpga/efinix_titanium.cfg
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# efinix titanium
+# https://www.efinixinc.com/docs/an048-jtag-bst-titanium-v1.0.pdf
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME titanium
+}
+
+jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \
+ -expected-id 0x10661A79 \
+ -expected-id 0x00360A79 \
+ -expected-id 0x10660A79 \
+ -expected-id 0x00681A79 \
+ -expected-id 0x00688A79 \
+ -expected-id 0x00682A79 \
+ -expected-id 0x0068CA79 \
+ -expected-id 0x00680A79 \
+ -expected-id 0x00684A79
+
+pld device efinix $_CHIPNAME.tap
diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg
new file mode 100644
index 0000000..ecd2eda
--- /dev/null
+++ b/tcl/fpga/efinix_trion.cfg
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# efinix trion
+# https://www.efinixinc.com/docs/an021-jtag-bst-trion-v1.0.pdf
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME trion
+}
+
+jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \
+ -expected-id 0x00210A79 \
+ -expected-id 0x00240A79 \
+ -expected-id 0x00220A79
+
+pld device efinix $_CHIPNAME.tap
diff --git a/tcl/fpga/gatemate.cfg b/tcl/fpga/gatemate.cfg
new file mode 100644
index 0000000..cc19fd4
--- /dev/null
+++ b/tcl/fpga/gatemate.cfg
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# GateMateTM FPGA
+# https://www.colognechip.com/programmable-logic/gatemate/
+# https://colognechip.com/docs/ds1001-gatemate1-datasheet-latest.pdf
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME gatemate
+}
+
+jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \
+ -expected-id 0x20000001
+
+pld device gatemate $_CHIPNAME.tap
diff --git a/tcl/fpga/gowin_gw1n.cfg b/tcl/fpga/gowin_gw1n.cfg
new file mode 100644
index 0000000..43d66b7
--- /dev/null
+++ b/tcl/fpga/gowin_gw1n.cfg
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Gowin FPGA IDCODEs
+# from JTAG Programming and Configuration Guide
+# http://cdn.gowinsemi.com.cn/TN653E.pdf
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME gw1n
+}
+
+jtag newtap $_CHIPNAME tap -irlen 8 -ignore-version \
+ -expected-id 0x0900281B \
+ -expected-id 0x0900381B \
+ -expected-id 0x0100681B \
+ -expected-id 0x0300081B \
+ -expected-id 0x0300181B \
+ -expected-id 0x0120681B \
+ -expected-id 0x0100381B \
+ -expected-id 0x1100381B \
+ -expected-id 0x0100981B \
+ -expected-id 0x1100581B \
+ -expected-id 0x1100481B \
+ -expected-id 0x0100181B \
+ -expected-id 0x1100181B \
+ -expected-id 0x0100481B
+
+pld device gowin $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_certus.cfg b/tcl/fpga/lattice_certus.cfg
new file mode 100644
index 0000000..95b6e59
--- /dev/null
+++ b/tcl/fpga/lattice_certus.cfg
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $_CHIPNAME
+} else {
+ set _CHIPNAME certus
+}
+
+# Lattice Certus
+#
+# Certus NX LFD2NX-17 0x310f0043
+# Certus NX LFD2NX-40 0x310f1043
+
+
+jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \
+ -expected-id 0x310F1043 -expected-id 0x310F0043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg
new file mode 100644
index 0000000..c15a379
--- /dev/null
+++ b/tcl/fpga/lattice_certuspro.cfg
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $_CHIPNAME
+} else {
+ set _CHIPNAME certuspro
+}
+
+# Lattice CertusPro
+#
+# 0x010f4043 - LFCPNX-100
+# 0x 043 - LFCPNX-50
+
+jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \
+ -expected-id 0x010f4043
+# -expected-id 0x01112043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_ecp2.cfg b/tcl/fpga/lattice_ecp2.cfg
new file mode 100644
index 0000000..a1aa2ef
--- /dev/null
+++ b/tcl/fpga/lattice_ecp2.cfg
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $_CHIPNAME
+} else {
+ set _CHIPNAME ecp2
+}
+
+# Lattice ECP2 family
+# TAP IDs are extracted from BSDL files found on this page:
+# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP2M
+#
+# LFE2M20E: 0x01279043
+# LFE2M35E: 0x0127A043
+# LFE2M50E: 0x0127B043
+# LFE2M70E: 0x0127C043
+# LFE2M100E: 0x0127D043
+# LFEC2_6E: 0x01270043
+# LFEC2_12E: 0x01271043
+# LFEC2_20E: 0x01272043
+# LFEC2_35E: 0x01274043
+# LFEC2_50E: 0x01273043
+# LFEC2_70E: 0x01275043
+
+jtag newtap $_CHIPNAME tap -irlen 8 \
+ -expected-id 0x01279043 -expected-id 0x0127A043 -expected-id 0x0127B043 \
+ -expected-id 0x0127C043 -expected-id 0x0127D043 -expected-id 0x01270043 \
+ -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 \
+ -expected-id 0x01273043 -expected-id 0x01275043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_ecp3.cfg b/tcl/fpga/lattice_ecp3.cfg
new file mode 100644
index 0000000..7cd5706
--- /dev/null
+++ b/tcl/fpga/lattice_ecp3.cfg
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $_CHIPNAME
+} else {
+ set _CHIPNAME ecp3
+}
+
+# Lattice ECP3 family
+# TAP IDs are extracted from BSDL files found on this page:
+# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3
+#
+# LFE3_17: 0x01010043
+# LFE3_35: 0x01012043
+# LFE3_95: 0x01014043 and LFE3_70
+# LFE3_150: 0x01015043
+
+jtag newtap $_CHIPNAME tap -irlen 8 \
+ -expected-id 0x01010043 -expected-id 0x01012043 \
+ -expected-id 0x01014043 -expected-id 0x01015043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/fpga/lattice_ecp5.cfg b/tcl/fpga/lattice_ecp5.cfg
index a94ada7..4144249 100644
--- a/tcl/fpga/lattice_ecp5.cfg
+++ b/tcl/fpga/lattice_ecp5.cfg
@@ -26,3 +26,5 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \
-expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 \
-expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \
-expected-id 0x81113043
+
+pld device lattice $_CHIPNAME.tap
diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg
index 3e44983..8dc0e7a 100644
--- a/tcl/target/renesas_rcar_gen3.cfg
+++ b/tcl/target/renesas_rcar_gen3.cfg
@@ -156,15 +156,20 @@ proc setup_a5x {core_name dbgbase ctibase num boot} {
}
}
-proc setup_cr7 {core_name dbgbase ctibase num boot} {
+proc setup_crx {core_name dbgbase ctibase num boot} {
global _CHIPNAME
global _DAPNAME
for { set _core 0 } { $_core < $num } { incr _core } {
set _TARGETNAME $_CHIPNAME.$core_name
set _CTINAME $_TARGETNAME.cti
cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase
- set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \
- -ap-num 1 -dbgbase $dbgbase"
+ if { $core_name == "r52" } {
+ set _command "target create $_TARGETNAME armv8r -dap $_DAPNAME \
+ -ap-num 1 -dbgbase $dbgbase -cti $_CTINAME"
+ } else {
+ set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \
+ -ap-num 1 -dbgbase $dbgbase"
+ }
if { $boot == 1 } {
set _targets "$_TARGETNAME"
} else {
@@ -177,20 +182,20 @@ proc setup_cr7 {core_name dbgbase ctibase num boot} {
# Organize target list based on the boot core
if { [string equal $_boot_core CA76] } {
setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1
- setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0
+ setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0
} elseif { [string equal $_boot_core CA57] } {
setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1
setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0
- setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0
+ setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0
} elseif { [string equal $_boot_core CA53] } {
setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1
setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0
- setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0
+ setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0
} elseif { [string equal $_boot_core CR52] } {
- setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1
+ setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1
setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0
} else {
- setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1
+ setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1
setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0
setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0
}