diff --git a/contrib/loaders/flash/rsl10/rom_launcher.S b/contrib/loaders/flash/rsl10/rom_launcher.S index 70f000e72..aafedfb46 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 eb9f92f35..7e9eb2036 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 [ [ [ [ []]]]]) +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://} - Save trace logs into file. +@item @code{tcp://:} - 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://) +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 02e5c09a2..ce79e1382 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 a874cc890..4e84f10fb 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 2c578d1b4..f8b59b357 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 fb6d98b56..b1cb8f110 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 6b9437390..62127530f 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 416f07778..36298f19d 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 fdd610f5f..c590081fc 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 67533fc1e..24c432cba 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 931f79421..889a811e3 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 bd3363b97..a0e135fea 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 d9b9695df..5e2935d02 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(®_params[0]); if (retval != ERROR_OK) { diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 0b04ce4b7..a0c6e0c81 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 b0d118bdb..6c18c7b28 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 d92c4b8b1..5f0ac9b8f 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 3a78952ef..972686e3f 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 77ea4c40d..c9fc1bffa 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 89e59ae47..dcf59d380 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 235bec858..945b890b3 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 d422561bc..62d24a9b2 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 ""; return jep106[bank][id]; diff --git a/src/helper/options.c b/src/helper/options.c index 327c418d0..05cde6709 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 5e12021ff..2e9f6155e 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 7db3c7b15..a37272084 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 08daa004b..ba9ee5e34 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 635d9a5ff..879ca3c84 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -19,7 +19,7 @@ #include -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 393fc7e85..c3e841d37 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 816b2d05e..1d73af4e5 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< #include #include +#include #if IS_CYGWIN == 1 #include @@ -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 9f2fdde9f..fad91dde2 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 c353aef40..ad980bf23 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 4073d066e..d26a51048 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 c933b3e1c..65f7494bd 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 5b051c1ff..ee629542b 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 ee254d66a..a5f5fd3ac 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 ca52559d1..3e3621873 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 0c0f24ee2..5d41656b4 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 7898e9d9b..9223be23f 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 47d06f1d8..55692b10e 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 b3cbc48b4..934b60352 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; - - /* 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; - } - - endstate = TAP_IDLE; - - /* validate arguments as numbers */ - e = JIM_OK; - for (i = 2; i < argc; i += 2) { - long bits; - const char *cp; - - e = Jim_GetLong(interp, args[i], &bits); - /* If valid - try next arg */ - if (e == JIM_OK) - continue; - - /* Not valid.. are we at the end? */ - if (((i + 2) != argc)) { - /* nope, then error */ - return e; - } - - /* it could be: "-endstate FOO" - * e.g. DRPAUSE so we can issue more instructions - * before entering RUN/IDLE and executing them. - */ - - /* 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; - } - } - - /* 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; - - num_fields = (argc-2)/2; - if (num_fields <= 0) { - Jim_SetResultString(interp, "drscan: no scan fields supplied", -1); - return JIM_ERR; - } - 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); - + 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; + 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(str, len, t, bits, 0); + str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0); fields[field_count].in_value = t; field_count++; } + return ERROR_OK; +} + +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 + */ + + if (CMD_ARGC < 3 || (CMD_ARGC % 2) != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + 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; + } + + if (tap->bypass) { + command_print(CMD, "Can't execute as the selected tap is in BYPASS"); + return ERROR_FAIL; + } + + 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; + } + + if (!scan_is_safe(endstate)) + LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name); + + CMD_ARGC -= 2; + } + + 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 14786afbf..69e457c96 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 000000000..1309c1b27 --- /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 000000000..51defc5ca --- /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 000000000..b1c2833d5 --- /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 000000000..5f3e9e97b --- /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 000000000..2e1009baa --- /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 000000000..7b0c86b4a --- /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 000000000..f08439476 --- /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 + +#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 000000000..43b3f02d1 --- /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 +#include +#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 000000000..467b79937 --- /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 +#include +#include +#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 000000000..119a5695d --- /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 +#include +#include +#include + +#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 000000000..4ab5f63c0 --- /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 +#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 000000000..9a76a4ec3 --- /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 +#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 000000000..562b17d0a --- /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 +#include +#include + +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 000000000..33f1b347f --- /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 000000000..8d66ac4c4 --- /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 e2e0ef413..7dd2cec18 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -10,16 +10,18 @@ #endif #include "pld.h" +#include #include #include #include -/* 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 a7cd20f64..322b96ec6 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 000000000..0c3b92e7e --- /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 +#include + + +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 000000000..583ff76e9 --- /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 +#include + +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 98fd58adb..3c174ae59 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(); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + xilinx_free_bit_file(&bit_file); + return retval; + } - jtag_add_tlr(); - - 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 792b3375b..e4cc52ef9 100644 --- a/src/pld/xilinx_bit.c +++ b/src/pld/xilinx_bit.c @@ -13,7 +13,6 @@ #include "pld.h" #include -#include #include 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 68fe8a14c..20378274e 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 f9edabc2b..7517ec7a9 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 c3870b75d..b4f6a1fd7 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 f36288da4..1ec76746c 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 45e98299c..aa239387a 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 755d0510e..69d0f5755 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 3c33032e9..5a16b3a3b 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 #include 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 805330f25..3bacfaefd 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 ff71a8e63..ffed263a9 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -19,6 +19,7 @@ #include "register.h" #include #include +#include #include #include @@ -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 54aa08634..f5aa21109 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 f40beb847..d1eefe5b3 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 3db9c62a5..d9688be13 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 +#include #include 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 88e9bb299..8e55014f9 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 #include #include @@ -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 22445067a..866f33152 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 8367a3881..c1759ed77 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 63055cf18..74bbe50bd 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -440,6 +440,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 = "", diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c new file mode 100644 index 000000000..291503e53 --- /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 +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifndef _WIN32 +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#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 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump ]", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/espressif/esp32_apptrace.h b/src/target/espressif/esp32_apptrace.h new file mode 100644 index 000000000..387334222 --- /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 +#include +#include + +#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 64fa69057..a11d05f0f 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -496,6 +496,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, diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 62b22b135..485567836 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -364,6 +364,11 @@ static const struct command_registration esp32s3_command_handlers[] = { .usage = "", .chain = esp_xtensa_smp_command_handlers, }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, { .name = "esp32", .usage = "", diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index fcc340c82..44764aeca 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -12,6 +12,7 @@ #include #include #include +#include "esp_xtensa_apptrace.h" #include #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 1ad6c377f..8807f0c32 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -12,10 +12,12 @@ #include #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 000000000..5741ab030 --- /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 +#include +#include +#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 000000000..0a9be731f --- /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 57417c3fa..6718875ee 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 5035cdb54..6c0964bfa 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 65ff6e6ac..19d151946 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 b14c42f91..5ce049ae1 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "target.h" diff --git a/src/target/stm8.c b/src/target/stm8.c index aa934c9bc..9fd65091c 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 3a40c04c8..c592a7105 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -31,6 +31,7 @@ #endif #include +#include #include #include #include @@ -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; - } - 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); + 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; + } - 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 8589e17e8..da4612c15 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 947080381..5186e9c19 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 18bdaa00e..5880637f4 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 000000000..7781bd5c7 --- /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 000000000..5ff2a1e32 --- /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 000000000..427037b71 --- /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 000000000..cc078a0e3 --- /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 000000000..9496c6f00 --- /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 000000000..045d63de3 --- /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 5dbd0deee..4504a8064 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 39c409bc3..185925a16 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 000000000..a2ed00ac8 --- /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 000000000..2dee37f41 --- /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 000000000..03fad076f --- /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 1937cb4b6..94228d26f 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 000000000..ae752dfb1 --- /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 000000000..3a1bc1f65 --- /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 000000000..e14357245 --- /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 000000000..59243cfd0 --- /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 000000000..1e9c9c405 --- /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 7c231f942..d7a92d748 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 000000000..681b58fc8 --- /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 000000000..ecd2edad4 --- /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 000000000..cc19fd4c2 --- /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 000000000..43d66b70e --- /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 000000000..95b6e59d8 --- /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 000000000..c15a379ae --- /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 000000000..a1aa2eff1 --- /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 000000000..7cd570649 --- /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 a94ada740..41442492e 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 3e449832f..8dc0e7a0d 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 }