Merge branch 'trabucayre:master' into master
This commit is contained in:
commit
8de2ae4562
|
|
@ -118,6 +118,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
#brew update
|
#brew update
|
||||||
brew install --only-dependencies openFPGALoader
|
brew install --only-dependencies openFPGALoader
|
||||||
|
brew install hidapi
|
||||||
|
|
||||||
- name: '🚧 Build tarball'
|
- name: '🚧 Build tarball'
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ option(ENABLE_USB_BLASTERII "enable Altera USB Blaster II support" ${
|
||||||
|
|
||||||
set(BLASTERII_PATH "" CACHE STRING "usbBlasterII firmware directory")
|
set(BLASTERII_PATH "" CACHE STRING "usbBlasterII firmware directory")
|
||||||
set(ISE_PATH "/opt/Xilinx/14.7" CACHE STRING "ise root directory (default: /opt/Xilinx/14.7)")
|
set(ISE_PATH "/opt/Xilinx/14.7" CACHE STRING "ise root directory (default: /opt/Xilinx/14.7)")
|
||||||
|
set(VIVADO_PATH "" CACHE STRING "Vivado root directory (something like /opt/Xilinx/Vivado/VERSION)")
|
||||||
|
|
||||||
# Libgpiod is only available on Linux OS.
|
# Libgpiod is only available on Linux OS.
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
|
@ -64,6 +65,8 @@ else()
|
||||||
set(ENABLE_LIBGPIOD OFF)
|
set(ENABLE_LIBGPIOD OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(ENABLE_XILINX_PLATFORM_CABLE_USB "enable Xilinx Platform Cable USB (XPCU) support" ${ENABLE_CABLE_ALL})
|
||||||
|
|
||||||
# XVC and RemoteBitbang are not available on Windows OS.
|
# XVC and RemoteBitbang are not available on Windows OS.
|
||||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
option(ENABLE_REMOTEBITBANG "enable remote bitbang driver" ${ENABLE_CABLE_ALL})
|
option(ENABLE_REMOTEBITBANG "enable remote bitbang driver" ${ENABLE_CABLE_ALL})
|
||||||
|
|
@ -102,6 +105,11 @@ set(USE_LIBFTDI OFF)
|
||||||
set(USE_LIBUSB OFF)
|
set(USE_LIBUSB OFF)
|
||||||
set(USE_LIBUSB_LL OFF)
|
set(USE_LIBUSB_LL OFF)
|
||||||
|
|
||||||
|
# USB BlasterII and Xilinx Platform Cable USB requires FX2 driver
|
||||||
|
if (ENABLE_XILINX_PLATFORM_CABLE_USB OR ENABLE_USB_BLASTERII)
|
||||||
|
set(USE_FX2_LL ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Only adds libftdi as dependency when a cable
|
# Only adds libftdi as dependency when a cable
|
||||||
# need this library.
|
# need this library.
|
||||||
if (ENABLE_FTDI_BASED_CABLE OR ENABLE_USB_BLASTERI OR ENABLE_XILINX_VIRTUAL_CABLE_SERVER)
|
if (ENABLE_FTDI_BASED_CABLE OR ENABLE_USB_BLASTERI OR ENABLE_XILINX_VIRTUAL_CABLE_SERVER)
|
||||||
|
|
@ -112,7 +120,7 @@ endif(ENABLE_FTDI_BASED_CABLE OR ENABLE_USB_BLASTERI OR ENABLE_XILINX_VIRTUAL_CA
|
||||||
|
|
||||||
# Only adds libusb as dependency when a cable need this library
|
# Only adds libusb as dependency when a cable need this library
|
||||||
if (ENABLE_DFU OR ENABLE_ANLOGIC_CABLE OR ENABLE_CH347 OR ENABLE_DIRTYJTAG
|
if (ENABLE_DFU OR ENABLE_ANLOGIC_CABLE OR ENABLE_CH347 OR ENABLE_DIRTYJTAG
|
||||||
OR ENABLE_ESP_USB OR ENABLE_JLINK OR ENABLE_GOWIN_GWU2X OR ENABLE_USB_BLASTERII OR ENABLE_USB_SCAN)
|
OR ENABLE_ESP_USB OR ENABLE_JLINK OR ENABLE_GOWIN_GWU2X OR USE_FX2_LL OR ENABLE_USB_SCAN)
|
||||||
set(USE_LIBUSB ON)
|
set(USE_LIBUSB ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -120,11 +128,6 @@ if (ENABLE_USB_SCAN OR ENABLE_GOWIN_GWU2X)
|
||||||
set(USE_LIBUSB_LL ON)
|
set(USE_LIBUSB_LL ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Only enable fx2_ll when cable using it
|
|
||||||
if (ENABLE_USB_BLASTERII)
|
|
||||||
set(USE_FX2_LL ON)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Cross-compilation support
|
# Cross-compilation support
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
@ -179,28 +182,23 @@ include(GNUInstallDirs)
|
||||||
add_definitions(-DDATA_DIR=\"${CMAKE_INSTALL_FULL_DATAROOTDIR}\")
|
add_definitions(-DDATA_DIR=\"${CMAKE_INSTALL_FULL_DATAROOTDIR}\")
|
||||||
|
|
||||||
add_definitions(-DISE_DIR=\"${ISE_PATH}\")
|
add_definitions(-DISE_DIR=\"${ISE_PATH}\")
|
||||||
|
add_definitions(-DVIVADO_DIR=\"${VIVADO_PATH}\")
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# Dependencies check/search
|
# Dependencies check/search
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
if (USE_LIBFTDI)
|
|
||||||
# Try to find the LibFTDI1 with cmake
|
|
||||||
find_package(LibFTDI1 QUIET)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (USE_PKGCONFIG)
|
if (USE_PKGCONFIG)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
# Backward compat when the libftdi is not found
|
# Backward compat when the libftdi is not found
|
||||||
# by using cmake
|
# by using cmake
|
||||||
if (USE_LIBFTDI)
|
if (USE_LIBFTDI)
|
||||||
if (NOT LIBFTDI_FOUND)
|
|
||||||
pkg_check_modules(LIBFTDI REQUIRED libftdi1)
|
pkg_check_modules(LIBFTDI REQUIRED libftdi1)
|
||||||
string(REPLACE "." ";" VERSION_LIST ${LIBFTDI_VERSION})
|
string(REPLACE "." ";" VERSION_LIST ${LIBFTDI_VERSION})
|
||||||
list(GET VERSION_LIST 0 LIBFTDI_VERSION_MAJOR)
|
list(GET VERSION_LIST 0 LIBFTDI_VERSION_MAJOR)
|
||||||
list(GET VERSION_LIST 1 LIBFTDI_VERSION_MINOR)
|
list(GET VERSION_LIST 1 LIBFTDI_VERSION_MINOR)
|
||||||
endif()
|
string(REGEX REPLACE "[^0-9].*" "" LIBFTDI_VERSION_MINOR "${LIBFTDI_VERSION_MINOR}")
|
||||||
else()
|
else()
|
||||||
set(LIBFTDI_LIBRARY_DIRS "")
|
set(LIBFTDI_LIBRARY_DIRS "")
|
||||||
set(LIBFTDI_INCLUDE_DIRS "")
|
set(LIBFTDI_INCLUDE_DIRS "")
|
||||||
|
|
@ -590,6 +588,12 @@ list (APPEND OPENFPGALOADER_HEADERS src/svf_jtag.hpp)
|
||||||
add_definitions(-DENABLE_SVF_JTAG)
|
add_definitions(-DENABLE_SVF_JTAG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Xilinx Platform Cable USB
|
||||||
|
if (ENABLE_XILINX_PLATFORM_CABLE_USB)
|
||||||
|
list(APPEND OPENFPGALOADER_SOURCE src/xilinxPlatformCableUSB.cpp)
|
||||||
|
list(APPEND OPENFPGALOADER_HEADERS src/xilinxPlatformCableUSB.hpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Xilinx Virtual Cable
|
# Xilinx Virtual Cable
|
||||||
if (ENABLE_XILINX_VIRTUAL_CABLE_CLIENT)
|
if (ENABLE_XILINX_VIRTUAL_CABLE_CLIENT)
|
||||||
list (APPEND OPENFPGALOADER_SOURCE src/xvc_client.cpp)
|
list (APPEND OPENFPGALOADER_SOURCE src/xvc_client.cpp)
|
||||||
|
|
@ -772,6 +776,13 @@ else()
|
||||||
message("Remote bitbang client support disabled")
|
message("Remote bitbang client support disabled")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_XILINX_PLATFORM_CABLE_USB)
|
||||||
|
add_definitions(-DENABLE_XILINX_PLATFORM_CABLE_USB=1)
|
||||||
|
message("Xilinx Platform Cable USB (XPCU) support enabled")
|
||||||
|
else()
|
||||||
|
message("Xilinx Platform Cable USB (XCPU) support disabled")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ENABLE_XILINX_VIRTUAL_CABLE_CLIENT)
|
if (ENABLE_XILINX_VIRTUAL_CABLE_CLIENT)
|
||||||
add_definitions(-DENABLE_XVC_CLIENT=1)
|
add_definitions(-DENABLE_XVC_CLIENT=1)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-pthread ${CMAKE_EXE_LINKER_FLAGS}")
|
set(CMAKE_EXE_LINKER_FLAGS "-pthread ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
|
|
@ -799,6 +810,7 @@ if (ZLIB_FOUND)
|
||||||
add_definitions(-DHAS_ZLIB=1)
|
add_definitions(-DHAS_ZLIB=1)
|
||||||
else()
|
else()
|
||||||
message("zlib library not found: can't flash intel/altera devices")
|
message("zlib library not found: can't flash intel/altera devices")
|
||||||
|
message("or reads compressed bitstreams")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LINK_CMAKE_THREADS)
|
if (LINK_CMAKE_THREADS)
|
||||||
|
|
@ -813,7 +825,6 @@ if (USE_LIBFTDI)
|
||||||
add_definitions(-DFTDI_VERSION=${FTDI_VAL})
|
add_definitions(-DFTDI_VERSION=${FTDI_VAL})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
install(TARGETS openFPGALoader DESTINATION bin)
|
install(TARGETS openFPGALoader DESTINATION bin)
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,8 @@ openFPGALoader -- a program to flash FPGA
|
||||||
non volatile memory (default: 0)
|
non volatile memory (default: 0)
|
||||||
--pins arg pin config TDI:TDO:TCK:TMS or
|
--pins arg pin config TDI:TDO:TCK:TMS or
|
||||||
MOSI:MISO:SCK:CS[:HOLDN:WPN]
|
MOSI:MISO:SCK:CS[:HOLDN:WPN]
|
||||||
--probe-firmware arg firmware for JTAG probe (usbBlasterII)
|
--probe-firmware arg firmware for JTAG probe
|
||||||
|
(usbBlasterII/xilinxPlatformCableUsb)
|
||||||
--protect-flash arg protect SPI flash area
|
--protect-flash arg protect SPI flash area
|
||||||
--quiet Produce quiet output (no progress bar)
|
--quiet Produce quiet output (no progress bar)
|
||||||
-r, --reset reset FPGA after operations
|
-r, --reset reset FPGA after operations
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,13 @@
|
||||||
Memory: OK
|
Memory: OK
|
||||||
Flash: NT
|
Flash: NT
|
||||||
|
|
||||||
|
- ID: axc3000
|
||||||
|
Description: Arrow AXC3000
|
||||||
|
URL: https://www.arrow.com/de/products/axc3000/trenz-electronic-gmbh.html
|
||||||
|
FPGA: Altera Agilex 3 A3CY100BM16AE7S
|
||||||
|
Memory: OK
|
||||||
|
Flash: NT
|
||||||
|
|
||||||
- ID: axe5000
|
- ID: axe5000
|
||||||
Description: A5EC008BM16AE6S FPGA Starter Kit
|
Description: A5EC008BM16AE6S FPGA Starter Kit
|
||||||
URL: https://www.arrow.com/en/products/axe5000/trenz-electronic-gmbh.html
|
URL: https://www.arrow.com/en/products/axe5000/trenz-electronic-gmbh.html
|
||||||
|
|
@ -751,6 +758,13 @@
|
||||||
Memory: OK
|
Memory: OK
|
||||||
Flash: NT
|
Flash: NT
|
||||||
|
|
||||||
|
- ID: sp701
|
||||||
|
Description: Xilinx SP701
|
||||||
|
URL: https://www.amd.com/en/products/adaptive-socs-and-fpgas/evaluation-boards/sp701.html
|
||||||
|
FPGA: Spartan 7 xc7s100-2-fgga676
|
||||||
|
Memory: OK
|
||||||
|
Flash: OK
|
||||||
|
|
||||||
- ID: spartanEdgeAccelBoard
|
- ID: spartanEdgeAccelBoard
|
||||||
Description: SeeedStudio Spartan Edge Accelerator Board
|
Description: SeeedStudio Spartan Edge Accelerator Board
|
||||||
URL: http://wiki.seeedstudio.com/Spartan-Edge-Accelerator-Board
|
URL: http://wiki.seeedstudio.com/Spartan-Edge-Accelerator-Board
|
||||||
|
|
@ -855,6 +869,13 @@
|
||||||
Memory: OK
|
Memory: OK
|
||||||
Flash: IF
|
Flash: IF
|
||||||
|
|
||||||
|
- ID: brs-100-gw1nr9
|
||||||
|
Description: BrisbaneSilicon BRS-100-GW1NR9
|
||||||
|
URL: https://brisbanesilicon.com.au/brs-100-gw1nr9/
|
||||||
|
FPGA: littleBee GW1NR-9C
|
||||||
|
Memory: OK
|
||||||
|
Flash: IF/EF
|
||||||
|
|
||||||
- ID: trion_t20_bga256_jtag
|
- ID: trion_t20_bga256_jtag
|
||||||
Description: Efinix Trion T20 BGA256 Dev Kit
|
Description: Efinix Trion T20 BGA256 Dev Kit
|
||||||
URL: https://www.efinixinc.com/products-devkits-triont20.html
|
URL: https://www.efinixinc.com/products-devkits-triont20.html
|
||||||
|
|
|
||||||
150
doc/cable.yml
150
doc/cable.yml
|
|
@ -33,6 +33,13 @@ bus_blaster_b:
|
||||||
URL: http://dangerousprototypes.com/docs/Bus_Blaster
|
URL: http://dangerousprototypes.com/docs/Bus_Blaster
|
||||||
|
|
||||||
|
|
||||||
|
ch347:
|
||||||
|
|
||||||
|
- Name: CH347
|
||||||
|
Description: CH347 is a USB HS bus converter with UART, I2C, SPI and JTAG interfaces
|
||||||
|
URL: https://github.com/wuxx/USB-HS-Bridge
|
||||||
|
|
||||||
|
|
||||||
ch347_jtag:
|
ch347_jtag:
|
||||||
|
|
||||||
- Name: ch347 JTAG adapter
|
- Name: ch347 JTAG adapter
|
||||||
|
|
@ -54,33 +61,6 @@ cmsisdap:
|
||||||
URL: https://os.mbed.com/docs/mbed-os/v6.11/debug-test/daplink.html
|
URL: https://os.mbed.com/docs/mbed-os/v6.11/debug-test/daplink.html
|
||||||
|
|
||||||
|
|
||||||
gatemate_pgm:
|
|
||||||
|
|
||||||
- Name: gatemate pgm
|
|
||||||
Description: Cologne Chip GateMate FPGA Programmer. FT232H-based JTAG/SPI programmer cable
|
|
||||||
URL: https://colognechip.com/programmable-logic/gatemate/
|
|
||||||
|
|
||||||
|
|
||||||
gatemate_evb_jtag:
|
|
||||||
- Name: gatemate evb JTAG
|
|
||||||
Description: Cologne Chip GateMate JTAG programmer
|
|
||||||
URL: https://colognechip.com/programmable-logic/gatemate/
|
|
||||||
|
|
||||||
|
|
||||||
gatemate_evb_spi:
|
|
||||||
|
|
||||||
- Name: gatemate evb spi
|
|
||||||
Description: Cologne Chip GateMate SPI programmer
|
|
||||||
URL: https://colognechip.com/programmable-logic/gatemate/
|
|
||||||
|
|
||||||
|
|
||||||
gwu2x:
|
|
||||||
|
|
||||||
- Name: gwu2x
|
|
||||||
Description: Gowin GWUX2X
|
|
||||||
URL: https://www.gowinsemi.com/en/product/detail/55/
|
|
||||||
|
|
||||||
|
|
||||||
dfu:
|
dfu:
|
||||||
|
|
||||||
- Name: DFU interface
|
- Name: DFU interface
|
||||||
|
|
@ -94,7 +74,7 @@ digilent:
|
||||||
Description: FT2232 JTAG / UART cable
|
Description: FT2232 JTAG / UART cable
|
||||||
|
|
||||||
|
|
||||||
diglent_b:
|
digilent_b:
|
||||||
|
|
||||||
- Name: digilent cable
|
- Name: digilent cable
|
||||||
Description: digilent FT2232 JTAG / UART cable (interface B)
|
Description: digilent FT2232 JTAG / UART cable (interface B)
|
||||||
|
|
@ -108,12 +88,14 @@ digilent_hs2:
|
||||||
|
|
||||||
|
|
||||||
digilent_hs3:
|
digilent_hs3:
|
||||||
|
|
||||||
- Name: digilent hs3
|
- Name: digilent hs3
|
||||||
Description: JTAG programmer cable from digilent
|
Description: JTAG programmer cable from digilent
|
||||||
URL: https://digilent.com/shop/jtag-hs3-programming-cable/
|
URL: https://digilent.com/shop/jtag-hs3-programming-cable/
|
||||||
|
|
||||||
|
|
||||||
dirtyJtag:
|
dirtyJtag:
|
||||||
|
|
||||||
- Name: dirty Jtag
|
- Name: dirty Jtag
|
||||||
Description: JTAG probe firmware for STM32F1
|
Description: JTAG probe firmware for STM32F1
|
||||||
URL: https://github.com/jeanthom/DirtyJTAG
|
URL: https://github.com/jeanthom/DirtyJTAG
|
||||||
|
|
@ -121,16 +103,17 @@ dirtyJtag:
|
||||||
New version `dirtyjtag2 <https://github.com/jeanthom/DirtyJTAG/tree/dirtyjtag2>`__ is also supported
|
New version `dirtyjtag2 <https://github.com/jeanthom/DirtyJTAG/tree/dirtyjtag2>`__ is also supported
|
||||||
|
|
||||||
|
|
||||||
efinix_spi_ft4232:
|
ecpix5-debug:
|
||||||
|
|
||||||
- Name: efinix SPI (ft4232)
|
- Name: ecpix5-debug
|
||||||
Description: efinix SPI interface (FTDI4232 interface A)
|
Description: LambdaConcept ECPIX5 (45k/85k) UART/JTAG interface
|
||||||
|
URL: https://shop.lambdaconcept.com/home/46-ecpix-5.html
|
||||||
|
|
||||||
|
|
||||||
efinix_jtag_ft4232:
|
efinix_jtag_ft2232:
|
||||||
|
|
||||||
- Name: efinix JTAG (ft4232)
|
- Name: efinix JTAG (ft2232)
|
||||||
Description: efinix JTAG interface (FTDI4232 interface B)
|
Description: efinix JTAG interface (FTDI2232 interface B)
|
||||||
|
|
||||||
|
|
||||||
efinix_spi_ft2232:
|
efinix_spi_ft2232:
|
||||||
|
|
@ -139,10 +122,16 @@ efinix_spi_ft2232:
|
||||||
Description: efinix SPI interface (FTDI2232 interface A)
|
Description: efinix SPI interface (FTDI2232 interface A)
|
||||||
|
|
||||||
|
|
||||||
efinix_jtag_ft2232:
|
efinix_jtag_ft4232:
|
||||||
|
|
||||||
- Name: efinix JTAG (ft2232)
|
- Name: efinix JTAG (ft4232)
|
||||||
Description: efinix JTAG interface (FTDI2232 interface B)
|
Description: efinix JTAG interface (FTDI4232 interface B)
|
||||||
|
|
||||||
|
|
||||||
|
efinix_spi_ft4232:
|
||||||
|
|
||||||
|
- Name: efinix SPI (ft4232)
|
||||||
|
Description: efinix SPI interface (FTDI4232 interface A)
|
||||||
|
|
||||||
|
|
||||||
ft2232:
|
ft2232:
|
||||||
|
|
@ -196,23 +185,54 @@ ft4232:
|
||||||
Description: quad interface programmer cable. MPSSE capable.
|
Description: quad interface programmer cable. MPSSE capable.
|
||||||
URL: https://ftdichip.com/products/ft4232h-56q/
|
URL: https://ftdichip.com/products/ft4232h-56q/
|
||||||
|
|
||||||
|
|
||||||
ft4232hp:
|
ft4232hp:
|
||||||
|
|
||||||
- Name: FT4232HP (interface A)
|
- Name: FT4232HP (interface A)
|
||||||
Description: quad interface programmer cable. MPSSE capable. High Speed USB Bridge with Type-C/PD3.0 Controller
|
Description: quad interface programmer cable. MPSSE capable. High Speed USB Bridge with Type-C/PD3.0 Controller
|
||||||
URL: https://ftdichip.com/wp-content/uploads/2023/02/DS_FT4233HP.pdf
|
URL: https://ftdichip.com/wp-content/uploads/2023/02/DS_FT4233HP.pdf
|
||||||
|
|
||||||
|
|
||||||
ft4232hp_b:
|
ft4232hp_b:
|
||||||
|
|
||||||
- Name: FT4232HP (interface B)
|
- Name: FT4232HP (interface B)
|
||||||
Description: quad interface programmer cable. MPSSE capable. High Speed USB Bridge with Type-C/PD3.0 Controller
|
Description: quad interface programmer cable. MPSSE capable. High Speed USB Bridge with Type-C/PD3.0 Controller
|
||||||
URL: https://ftdichip.com/wp-content/uploads/2023/02/DS_FT4233HP.pdf
|
URL: https://ftdichip.com/wp-content/uploads/2023/02/DS_FT4233HP.pdf
|
||||||
|
|
||||||
ecpix5-debug:
|
|
||||||
|
|
||||||
- Name: ecpix5-debug
|
gatemate_pgm:
|
||||||
Description: LambdaConcept ECPIX5 (45k/85k) UART/JTAG interface
|
|
||||||
URL: https://shop.lambdaconcept.com/home/46-ecpix-5.html
|
- Name: gatemate pgm
|
||||||
|
Description: Cologne Chip GateMate FPGA Programmer. FT232H-based JTAG/SPI programmer cable
|
||||||
|
URL: https://colognechip.com/programmable-logic/gatemate/
|
||||||
|
|
||||||
|
|
||||||
|
gatemate_evb_jtag:
|
||||||
|
|
||||||
|
- Name: gatemate evb JTAG
|
||||||
|
Description: Cologne Chip GateMate JTAG programmer
|
||||||
|
URL: https://colognechip.com/programmable-logic/gatemate/
|
||||||
|
|
||||||
|
|
||||||
|
gatemate_evb_spi:
|
||||||
|
|
||||||
|
- Name: gatemate evb spi
|
||||||
|
Description: Cologne Chip GateMate SPI programmer
|
||||||
|
URL: https://colognechip.com/programmable-logic/gatemate/
|
||||||
|
|
||||||
|
|
||||||
|
gwu2x:
|
||||||
|
|
||||||
|
- Name: gwu2x
|
||||||
|
Description: Gowin GWUX2X
|
||||||
|
URL: https://www.gowinsemi.com/en/product/detail/55/
|
||||||
|
|
||||||
|
|
||||||
|
jetson-nano-gpio:
|
||||||
|
|
||||||
|
- Name: Bitbang GPIO
|
||||||
|
Description: Bitbang GPIO pins on Jetson Nano Linux host. Use /dev/mem to have a faster clock.
|
||||||
|
URL: https://github.com/jwatte/jetson-gpio-example
|
||||||
|
|
||||||
|
|
||||||
jlink:
|
jlink:
|
||||||
|
|
@ -235,6 +255,13 @@ jtag-smt2-nc:
|
||||||
URL: https://digilent.com/shop/jtag-smt2-nc-surface-mount-programming-module
|
URL: https://digilent.com/shop/jtag-smt2-nc-surface-mount-programming-module
|
||||||
|
|
||||||
|
|
||||||
|
libgpiod:
|
||||||
|
|
||||||
|
- Name: Bitbang GPIO
|
||||||
|
Description: Bitbang GPIO pins on Linux host.
|
||||||
|
URL: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
|
||||||
|
|
||||||
|
|
||||||
lpc-link2:
|
lpc-link2:
|
||||||
|
|
||||||
- Name: lpc-link2
|
- Name: lpc-link2
|
||||||
|
|
@ -247,6 +274,7 @@ numato:
|
||||||
- Name: numato
|
- Name: numato
|
||||||
Description: Embedded cable for Numato Systems Mimas-A7 board
|
Description: Embedded cable for Numato Systems Mimas-A7 board
|
||||||
|
|
||||||
|
|
||||||
orbtrace:
|
orbtrace:
|
||||||
|
|
||||||
- Name: orbtrace interface
|
- Name: orbtrace interface
|
||||||
|
|
@ -261,13 +289,6 @@ papilio:
|
||||||
URL: https://papilio.cc/
|
URL: https://papilio.cc/
|
||||||
|
|
||||||
|
|
||||||
steppenprobe:
|
|
||||||
|
|
||||||
- Name: steppenprobe
|
|
||||||
Description: Open Source Hardware JTAG/SWD/UART/SWO interface board based on FTDI FT2232H
|
|
||||||
URL: https://github.com/diegoherranz/steppenprobe
|
|
||||||
|
|
||||||
|
|
||||||
remote-bitgang:
|
remote-bitgang:
|
||||||
|
|
||||||
- Name: OpenOCD remote bitbang
|
- Name: OpenOCD remote bitbang
|
||||||
|
|
@ -275,6 +296,13 @@ remote-bitgang:
|
||||||
URL: https://github.com/openocd-org/openocd/blob/master/doc/manual/jtag/drivers/remote_bitbang.txt
|
URL: https://github.com/openocd-org/openocd/blob/master/doc/manual/jtag/drivers/remote_bitbang.txt
|
||||||
|
|
||||||
|
|
||||||
|
steppenprobe:
|
||||||
|
|
||||||
|
- Name: steppenprobe
|
||||||
|
Description: Open Source Hardware JTAG/SWD/UART/SWO interface board based on FTDI FT2232H
|
||||||
|
URL: https://github.com/diegoherranz/steppenprobe
|
||||||
|
|
||||||
|
|
||||||
tigard:
|
tigard:
|
||||||
|
|
||||||
- Name: tigard
|
- Name: tigard
|
||||||
|
|
@ -302,6 +330,13 @@ usb-blasterIII:
|
||||||
URL: https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_usb_blstr_ii_cable.pdf
|
URL: https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_usb_blstr_ii_cable.pdf
|
||||||
|
|
||||||
|
|
||||||
|
xilinxPlatformCableUsb:
|
||||||
|
|
||||||
|
- Name: Xilinx Platform Cable USB (XPCU)
|
||||||
|
Description: Xilinx Platform Cable USB (XPCU) from AMD/Xilinx
|
||||||
|
URL: https://www.amd.com/en/products/adaptive-socs-and-fpgas/board-accessories/hw-usb-ii-g.html
|
||||||
|
|
||||||
|
|
||||||
xvc-client:
|
xvc-client:
|
||||||
|
|
||||||
- Name: Xilinx Virtual Cable
|
- Name: Xilinx Virtual Cable
|
||||||
|
|
@ -314,22 +349,3 @@ xvc-server:
|
||||||
- Name: Xilinx Virtual Cable (server side)
|
- Name: Xilinx Virtual Cable (server side)
|
||||||
Description: Xilinx Virtual Cable (XVC) is a TCP/IP-based protocol that acts like a JTAG cable.
|
Description: Xilinx Virtual Cable (XVC) is a TCP/IP-based protocol that acts like a JTAG cable.
|
||||||
URL: https://github.com/Xilinx/XilinxVirtualCable
|
URL: https://github.com/Xilinx/XilinxVirtualCable
|
||||||
|
|
||||||
|
|
||||||
libgpiod:
|
|
||||||
|
|
||||||
- Name: Bitbang GPIO
|
|
||||||
Description: Bitbang GPIO pins on Linux host.
|
|
||||||
URL: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/
|
|
||||||
|
|
||||||
jetson-nano-gpio:
|
|
||||||
|
|
||||||
- Name: Bitbang GPIO
|
|
||||||
Description: Bitbang GPIO pins on Jetson Nano Linux host. Use /dev/mem to have a faster clock.
|
|
||||||
URL: https://github.com/jwatte/jetson-gpio-example
|
|
||||||
|
|
||||||
ch347:
|
|
||||||
|
|
||||||
- Name: CH347
|
|
||||||
Description: CH347 is a USB HS bus converter with UART, I2C, SPI and JTAG interfaces
|
|
||||||
URL: https://github.com/wuxx/USB-HS-Bridge
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ GOWIN GW1N
|
||||||
* Sipeed Tang Nano 4K
|
* Sipeed Tang Nano 4K
|
||||||
* Honeycomb
|
* Honeycomb
|
||||||
* RUNBER
|
* RUNBER
|
||||||
|
* BrisbaneSilicon BRS-100-GW1NR9
|
||||||
|
|
||||||
``.fs`` file is the default format generated by *Gowin IDE*, so nothing special must be done to generates this file.
|
``.fs`` file is the default format generated by *Gowin IDE*, so nothing special must be done to generates this file.
|
||||||
|
|
||||||
|
|
@ -37,12 +38,13 @@ where ``BOARD_NAME`` is:
|
||||||
* ``tangnano20k``
|
* ``tangnano20k``
|
||||||
* ``tangprimer20k``
|
* ``tangprimer20k``
|
||||||
* ``runber``
|
* ``runber``
|
||||||
|
* ``brs-100-gw1nr9``
|
||||||
|
|
||||||
Flash
|
Flash
|
||||||
-----
|
-----
|
||||||
|
|
||||||
.. ATTENTION::
|
.. ATTENTION::
|
||||||
Only with Trenz TEC0117 and runber.
|
Only with Trenz TEC0117, runber and brs-100-gw1nr9.
|
||||||
|
|
||||||
with ``-f``, file load:
|
with ``-f``, file load:
|
||||||
|
|
||||||
|
|
@ -54,6 +56,7 @@ where ``BOARD_NAME`` is:
|
||||||
|
|
||||||
* ``tec0117``
|
* ``tec0117``
|
||||||
* ``runber``
|
* ``runber``
|
||||||
|
* ``brs-100-gw1nr9``
|
||||||
|
|
||||||
It's possible to flash external SPI Flash (connected to MSPI) in bscan mode by using ``--external-flash`` instead of
|
It's possible to flash external SPI Flash (connected to MSPI) in bscan mode by using ``--external-flash`` instead of
|
||||||
``-f``.
|
``-f``.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ url="https://github.com/trabucayre/openFPGALoader"
|
||||||
license=('Apache-2.0')
|
license=('Apache-2.0')
|
||||||
depends=(
|
depends=(
|
||||||
"${MINGW_PACKAGE_PREFIX}-libftdi"
|
"${MINGW_PACKAGE_PREFIX}-libftdi"
|
||||||
|
"${MINGW_PACKAGE_PREFIX}-hidapi"
|
||||||
"${MINGW_PACKAGE_PREFIX}-zlib"
|
"${MINGW_PACKAGE_PREFIX}-zlib"
|
||||||
)
|
)
|
||||||
makedepends=(
|
makedepends=(
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
set parts [lindex $argv 0]
|
|
||||||
|
|
||||||
set project_name "spiOverJtag"
|
|
||||||
|
|
||||||
set build_path tmp_${parts}
|
|
||||||
file delete -force $build_path
|
|
||||||
|
|
||||||
# Project creation
|
|
||||||
set grade [dict create \
|
|
||||||
xc7a15tfgg484 -1 \
|
|
||||||
xc7a25tcpg238 -1 \
|
|
||||||
xc7a25tcsg325 -1 \
|
|
||||||
xc7a35tcpg236 -1 \
|
|
||||||
xc7a35tcsg324 -1 \
|
|
||||||
xc7a35tftg256 -1 \
|
|
||||||
xc7a50tcpg236 -2 \
|
|
||||||
xc7a50tcsg325 -2 \
|
|
||||||
xc7a75tfgg484 -2 \
|
|
||||||
xc7a100tfgg484 -2 \
|
|
||||||
xc7a200tsbg484 -1 \
|
|
||||||
xc7k70tfbg676 -1 \
|
|
||||||
xc7k160tffg676 -1 \
|
|
||||||
xc7k325tffg676 -1 \
|
|
||||||
xc7k325tffg900 -2 \
|
|
||||||
xc7s25csga225 -1 \
|
|
||||||
xc7s50csga324 -1 \
|
|
||||||
]
|
|
||||||
|
|
||||||
set pkg_name [dict create \
|
|
||||||
xc7a25tcpg238 xc7a_cpg238 \
|
|
||||||
xc7a25tcsg325 xc7a_csg325 \
|
|
||||||
xc7a35tcpg236 xc7a_cpg236 \
|
|
||||||
xc7a35tcsg324 xc7a_csg324 \
|
|
||||||
xc7a35tftg256 xc7a_ftg256 \
|
|
||||||
xc7a50tcpg236 xc7a_cpg236 \
|
|
||||||
xc7a50tcsg325 xc7a_csg325 \
|
|
||||||
xc7a15tfgg484 xc7a_fgg484 \
|
|
||||||
xc7a75tfgg484 xc7a_fgg484 \
|
|
||||||
xc7a100tfgg484 xc7a_fgg484 \
|
|
||||||
xc7a200tsbg484 xc7a_sbg484 \
|
|
||||||
xc7a200tfbg484 xc7a_fbg484 \
|
|
||||||
xc7k70tfbg676 xc7k_fbg676 \
|
|
||||||
xc7k160tffg676 xc7k_ffg676 \
|
|
||||||
xc7k325tffg676 xc7k_ffg676 \
|
|
||||||
xc7k325tffg900 xc7k_ffg900 \
|
|
||||||
xc7s25csga225 xc7s_csga225 \
|
|
||||||
xc7s50csga324 xc7s_csga324 \
|
|
||||||
]
|
|
||||||
|
|
||||||
set curr_grade [dict get $grade $parts]
|
|
||||||
set curr_pins [dict get $pkg_name $parts]
|
|
||||||
|
|
||||||
create_project $project_name $build_path -part ${parts}${curr_grade}
|
|
||||||
|
|
||||||
add_files -norecurse xilinx_spiOverJtag.vhd
|
|
||||||
add_files -norecurse -fileset constrs_1 constr_${curr_pins}.xdc
|
|
||||||
|
|
||||||
set_property VERILOG_DEFINE {TOOL_VIVADO} [current_fileset]
|
|
||||||
|
|
||||||
# set the current synth run
|
|
||||||
current_run -synthesis [get_runs synth_1]
|
|
||||||
reset_run synth_1
|
|
||||||
|
|
||||||
set obj [get_runs impl_1]
|
|
||||||
set_property AUTO_INCREMENTAL_CHECKPOINT 1 [get_runs impl_1]
|
|
||||||
|
|
||||||
set_property "needs_refresh" "1" $obj
|
|
||||||
|
|
||||||
# set the current impl run
|
|
||||||
current_run -implementation [get_runs impl_1]
|
|
||||||
|
|
||||||
puts "INFO: Project created: $project_name"
|
|
||||||
|
|
||||||
launch_runs synth_1 -jobs 4
|
|
||||||
wait_on_run synth_1
|
|
||||||
## do implementation
|
|
||||||
launch_runs impl_1 -jobs 4
|
|
||||||
wait_on_run impl_1
|
|
||||||
## make bit file
|
|
||||||
launch_runs impl_1 -jobs 4 -to_step write_bitstream
|
|
||||||
wait_on_run impl_1
|
|
||||||
exit
|
|
||||||
|
|
@ -236,6 +236,7 @@ static std::map <std::string, target_board_t> board_list = {
|
||||||
JTAG_BOARD("spartanEdgeAccelBoard", "", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("spartanEdgeAccelBoard", "", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("spec45", "xc6slx45tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("spec45", "xc6slx45tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("spec150", "xc6slx150tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("spec150", "xc6slx150tfgg484", "", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
|
JTAG_BOARD("sp701", "xc7s100fgga676", "digilent_ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("stlv7325", "xc7k325tffg676", "ft4232", SPI_FLASH, 0, 0, CABLE_MHZ(3)),
|
JTAG_BOARD("stlv7325", "xc7k325tffg676", "ft4232", SPI_FLASH, 0, 0, CABLE_MHZ(3)),
|
||||||
JTAG_BOARD("tangconsole", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("tangconsole", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("tangnano", "", "ch552_jtag", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("tangnano", "", "ch552_jtag", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
|
|
@ -249,6 +250,7 @@ static std::map <std::string, target_board_t> board_list = {
|
||||||
JTAG_BOARD("te0712_8", "xc7a200tfbg484", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
JTAG_BOARD("te0712_8", "xc7a200tfbg484", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||||
JTAG_BOARD("tec0117", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("tec0117", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("tec0330", "xc7vx330tffg1157", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
JTAG_BOARD("tec0330", "xc7vx330tffg1157", "", SPI_FLASH, 0, 0, CABLE_MHZ(15)),
|
||||||
|
JTAG_BOARD("brs-100-gw1nr9", "gw1nr-lv9qn88pc7/i6", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
SPI_BOARD("titanium_ti60_f225","efinix", "titanium", "efinix_spi_ft4232",
|
SPI_BOARD("titanium_ti60_f225","efinix", "titanium", "efinix_spi_ft4232",
|
||||||
DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
DBUS4, DBUS5, DBUS7, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
|
||||||
JTAG_BOARD("titanium_ti60_f225_jtag", "ti60f225","efinix_jtag_ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
JTAG_BOARD("titanium_ti60_f225_jtag", "ti60f225","efinix_jtag_ft4232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ enum communication_type {
|
||||||
MODE_CH347, /*! CH347 JTAG mode */
|
MODE_CH347, /*! CH347 JTAG mode */
|
||||||
MODE_GWU2X, /*! Gowin GWU2X JTAG mode */
|
MODE_GWU2X, /*! Gowin GWU2X JTAG mode */
|
||||||
MODE_ESP, /*! esp32c3, esp32s3 */
|
MODE_ESP, /*! esp32c3, esp32s3 */
|
||||||
|
MODE_XPCU, /*! Xilinx Platform Cable USB (XPCU) */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -99,6 +100,7 @@ static std::map <std::string, cable_t> cable_list = {
|
||||||
{"dfu", CABLE_DEF(MODE_DFU, 0, 0 )},
|
{"dfu", CABLE_DEF(MODE_DFU, 0, 0 )},
|
||||||
{"digilent", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0xe8, 0xeb, 0x00, 0x60)},
|
{"digilent", FTDI_SER(0x0403, 0x6010, FTDI_INTF_A, 0xe8, 0xeb, 0x00, 0x60)},
|
||||||
{"digilent_b", FTDI_SER(0x0403, 0x6010, FTDI_INTF_B, 0xe8, 0xeb, 0x00, 0x60)},
|
{"digilent_b", FTDI_SER(0x0403, 0x6010, FTDI_INTF_B, 0xe8, 0xeb, 0x00, 0x60)},
|
||||||
|
{"digilent_ft4232", FTDI_SER(0x0403, 0x6011, FTDI_INTF_A, 0x08, 0x2B, 0x08, 0x0B)},
|
||||||
{"digilent_hs2", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0xe8, 0xeb, 0x00, 0x60)},
|
{"digilent_hs2", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0xe8, 0xeb, 0x00, 0x60)},
|
||||||
{"digilent_hs3", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0x88, 0x8B, 0x20, 0x30)},
|
{"digilent_hs3", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0x88, 0x8B, 0x20, 0x30)},
|
||||||
{"digilent_ad", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0x08, 0x0B, 0x80, 0x80)},
|
{"digilent_ad", FTDI_SER(0x0403, 0x6014, FTDI_INTF_A, 0x08, 0x0B, 0x80, 0x80)},
|
||||||
|
|
@ -136,6 +138,7 @@ static std::map <std::string, cable_t> cable_list = {
|
||||||
{"usb-blasterII", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6810 )},
|
{"usb-blasterII", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6810 )},
|
||||||
{"usb-blasterII_1", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6010 )},
|
{"usb-blasterII_1", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6010 )},
|
||||||
{"usb-blasterIII", FTDI_SER(0x09fb, 0x6022, FTDI_INTF_A, 0x08, 0x3B, 0x58, 0xb0)},
|
{"usb-blasterIII", FTDI_SER(0x09fb, 0x6022, FTDI_INTF_A, 0x08, 0x3B, 0x58, 0xb0)},
|
||||||
|
{"xilinxPlatformCableUsb", CABLE_DEF(MODE_XPCU, 0x03fd, 0x0013)},
|
||||||
{"xvc-client", CABLE_DEF(MODE_XVC_CLIENT, 0x0000, 0x0000 )},
|
{"xvc-client", CABLE_DEF(MODE_XVC_CLIENT, 0x0000, 0x0000 )},
|
||||||
#ifdef ENABLE_LIBGPIOD
|
#ifdef ENABLE_LIBGPIOD
|
||||||
{"libgpiod", CABLE_DEF(MODE_LIBGPIOD_BITBANG, 0, 0x0000 )},
|
{"libgpiod", CABLE_DEF(MODE_LIBGPIOD_BITBANG, 0, 0x0000 )},
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,14 @@ void Efinix::program(unsigned int offset, bool unprotect_flash)
|
||||||
throw std::runtime_error("device mismatch: " + device + " != " + target);
|
throw std::runtime_error("device mismatch: " + device + " != " + target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::map<std::string, std::string> hdr = bit->getHeader();
|
||||||
|
if(hdr.find("mode") != hdr.end()) {
|
||||||
std::string mode = bit->getHeaderVal("mode");
|
std::string mode = bit->getHeaderVal("mode");
|
||||||
if (mode.find("passive") != std::string::npos) {
|
if (mode.find("passive") != std::string::npos) {
|
||||||
delete bit;
|
delete bit;
|
||||||
throw std::runtime_error("passive mode not supported for flash");
|
throw std::runtime_error("passive mode not supported for flash");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (std::runtime_error& e) {
|
} catch (std::runtime_error& e) {
|
||||||
throw;
|
throw;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
||||||
|
|
@ -245,13 +245,17 @@ static uint16_t esp_usb_target_chip_id = 0; /* not applicable for FPGA, they hav
|
||||||
|
|
||||||
/* end copy from openocd */
|
/* end copy from openocd */
|
||||||
|
|
||||||
esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid = ESPUSBJTAG_VID, int pid = ESPUSBJTAG_PID):
|
esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose,
|
||||||
|
int vid = ESPUSBJTAG_VID, int pid = ESPUSBJTAG_PID,
|
||||||
|
uint8_t bus_addr = 0, uint8_t dev_addr = 0,
|
||||||
|
const std::string &serial = ""):
|
||||||
_verbose(verbose > 1),
|
_verbose(verbose > 1),
|
||||||
dev_handle(NULL), usb_ctx(NULL), _tdi(0), _tms(0),
|
dev_handle(NULL), usb_ctx(NULL), _tdi(0), _tms(0),
|
||||||
/* Default for emard firmware. */
|
/* Default for emard firmware. */
|
||||||
_esp_usb_jtag_caps(0x2000), _write_ep(0x02),
|
_esp_usb_jtag_caps(0x2000), _write_ep(0x02),
|
||||||
_vid(ESPUSBJTAG_VID), _pid(ESPUSBJTAG_PID)
|
_vid(ESPUSBJTAG_VID), _pid(ESPUSBJTAG_PID)
|
||||||
{
|
{
|
||||||
|
libusb_device **devs = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
char mess[256];
|
char mess[256];
|
||||||
|
|
||||||
|
|
@ -260,18 +264,61 @@ esp_usb_jtag::esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid = ESPUSBJTAG_
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
ssize_t cnt = libusb_get_device_list(usb_ctx, &devs);
|
||||||
_vid, _pid);
|
if (cnt < 0) {
|
||||||
if (!dev_handle) {
|
std::cerr << "esp_usb_jtag: libusb_get_device_list failed: "
|
||||||
_esp_usb_jtag_caps = 0x030A;
|
<< libusb_error_name(static_cast<int>(cnt)) << std::endl;
|
||||||
_write_ep = 0x03;
|
libusb_exit(usb_ctx);
|
||||||
_pid = 0x1002;
|
throw std::exception();
|
||||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
|
||||||
_vid, _pid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ssize_t i = 0; i < cnt; i++) {
|
||||||
|
libusb_device *dev = devs[i];
|
||||||
|
struct libusb_device_descriptor desc;
|
||||||
|
if (libusb_get_device_descriptor(dev, &desc) < 0)
|
||||||
|
continue;
|
||||||
|
if (desc.idVendor != vid || desc.idProduct != pid)
|
||||||
|
continue;
|
||||||
|
/* bus/device filter (only when both are user-supplied) */
|
||||||
|
if (bus_addr != 0 && dev_addr != 0 &&
|
||||||
|
(libusb_get_bus_number(dev) != bus_addr ||
|
||||||
|
libusb_get_device_address(dev) != dev_addr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* serial filter */
|
||||||
|
if (!serial.empty()) {
|
||||||
|
libusb_device_handle *probe = NULL;
|
||||||
|
if (libusb_open(dev, &probe) < 0)
|
||||||
|
continue;
|
||||||
|
unsigned char raw[256] = {0};
|
||||||
|
int n = 0;
|
||||||
|
if (desc.iSerialNumber)
|
||||||
|
n = libusb_get_string_descriptor_ascii(probe,
|
||||||
|
desc.iSerialNumber, raw, sizeof(raw));
|
||||||
|
libusb_close(probe);
|
||||||
|
if (n <= 0)
|
||||||
|
continue;
|
||||||
|
const std::string found(reinterpret_cast<char *>(raw), n);
|
||||||
|
|
||||||
|
if (found.find(serial) == std::string::npos)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (libusb_open(dev, &dev_handle) == 0)
|
||||||
|
break;
|
||||||
|
dev_handle = NULL;
|
||||||
|
}
|
||||||
|
libusb_free_device_list(devs, 1);
|
||||||
|
|
||||||
if (!dev_handle) {
|
if (!dev_handle) {
|
||||||
snprintf(mess, 256, "fails to open esp_usb_jtag device");
|
std::cerr << "fails to open esp_usb_jtag device vid:pid 0x"
|
||||||
printError(mess);
|
<< std::hex << vid << ":0x" << pid;
|
||||||
|
if (bus_addr || dev_addr)
|
||||||
|
std::cerr << " bus:dev " << std::dec << static_cast<int>(bus_addr)
|
||||||
|
<< ":" << static_cast<int>(dev_addr);
|
||||||
|
if (!serial.empty())
|
||||||
|
std::cerr << " serial '" << serial << "'";
|
||||||
|
std::cerr << std::endl;
|
||||||
libusb_exit(usb_ctx);
|
libusb_exit(usb_ctx);
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "jtagInterface.hpp"
|
#include "jtagInterface.hpp"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -23,7 +25,9 @@
|
||||||
|
|
||||||
class esp_usb_jtag : public JtagInterface {
|
class esp_usb_jtag : public JtagInterface {
|
||||||
public:
|
public:
|
||||||
esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid);
|
esp_usb_jtag(uint32_t clkHZ, int8_t verbose, int vid, int pid,
|
||||||
|
uint8_t bus_addr, uint8_t dev_addr,
|
||||||
|
const std::string &serial);
|
||||||
virtual ~esp_usb_jtag();
|
virtual ~esp_usb_jtag();
|
||||||
|
|
||||||
int setClkFreq(uint32_t clkHZ) override;
|
int setClkFreq(uint32_t clkHZ) override;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#include "display.hpp"
|
#include "display.hpp"
|
||||||
#include "fx2_ll.hpp"
|
#include "fx2_ll.hpp"
|
||||||
#include "ihexParser.hpp"
|
#include "ihexParser.hpp"
|
||||||
|
#include "progressBar.hpp"
|
||||||
|
|
||||||
#define FX2_FIRM_LOAD 0xA0
|
#define FX2_FIRM_LOAD 0xA0
|
||||||
#define FX2_GCR_CPUCS 0xe600
|
#define FX2_GCR_CPUCS 0xe600
|
||||||
|
|
@ -42,27 +42,36 @@ FX2_ll::FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
|
||||||
throw std::runtime_error("claim interface failed");
|
throw std::runtime_error("claim interface failed");
|
||||||
}
|
}
|
||||||
/* load firmware */
|
/* load firmware */
|
||||||
load_firmware(firmware_path);
|
if (!load_firmware(firmware_path)) {
|
||||||
|
libusb_close(dev_handle);
|
||||||
|
libusb_exit(usb_ctx);
|
||||||
|
throw std::runtime_error("fx2 firmware load failed");
|
||||||
|
}
|
||||||
close();
|
close();
|
||||||
reenum = true;
|
reenum = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to open an already init device
|
/* try to open an already init device
|
||||||
* since fx2 may be not immediately ready
|
* since fx2 may be not immediatly ready
|
||||||
* retry with a delay
|
* retry with a delay
|
||||||
*/
|
*/
|
||||||
|
ProgressBar progress("Waiting reload", 100, 50, false);
|
||||||
int timeout = 100;
|
int timeout = 100;
|
||||||
do {
|
do {
|
||||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||||
vid, pid);
|
vid, pid);
|
||||||
timeout--;
|
timeout--;
|
||||||
|
progress.display(100-timeout);
|
||||||
if (!dev_handle)
|
if (!dev_handle)
|
||||||
sleep(1);
|
sleep(1);
|
||||||
} while (!dev_handle && timeout > 0 && reenum);
|
} while (!dev_handle && timeout > 0 && reenum);
|
||||||
|
|
||||||
if (!dev_handle)
|
if (!dev_handle) {
|
||||||
|
progress.fail();
|
||||||
throw std::runtime_error("FX2: fail to open device");
|
throw std::runtime_error("FX2: fail to open device");
|
||||||
|
}
|
||||||
|
progress.done();
|
||||||
|
|
||||||
ret = libusb_claim_interface(dev_handle, 0);
|
ret = libusb_claim_interface(dev_handle, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
@ -72,6 +81,18 @@ FX2_ll::FX2_ll(uint16_t uninit_vid, uint16_t uninit_pid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FX2_ll::set_interface_alt_setting(const int if_num, const int alt_setting)
|
||||||
|
{
|
||||||
|
const int ret = libusb_set_interface_alt_setting(dev_handle, if_num,
|
||||||
|
alt_setting);
|
||||||
|
if (ret && ret != LIBUSB_ERROR_NOT_FOUND) {
|
||||||
|
printWarn("unable to select alternate interface 1: "
|
||||||
|
+ std::string(libusb_error_name(ret)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* destructor: close current device and
|
/* destructor: close current device and
|
||||||
* destroy context
|
* destroy context
|
||||||
*/
|
*/
|
||||||
|
|
@ -134,11 +155,11 @@ int FX2_ll::read(uint8_t endpoint, uint8_t *buff, uint16_t len)
|
||||||
/* write len data using control
|
/* write len data using control
|
||||||
*/
|
*/
|
||||||
int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
|
int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||||
uint8_t *buff, uint16_t len)
|
uint8_t *buff, uint16_t len, uint16_t wIndex)
|
||||||
{
|
{
|
||||||
int ret = libusb_control_transfer(dev_handle,
|
int ret = libusb_control_transfer(dev_handle,
|
||||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
|
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
|
||||||
bRequest, wValue, 0x0000, buff, len, 100);
|
bRequest, wValue, wIndex, buff, len, 100);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printError("Unable to send control request: "
|
printError("Unable to send control request: "
|
||||||
+ std::string(libusb_error_name(ret)));
|
+ std::string(libusb_error_name(ret)));
|
||||||
|
|
@ -150,11 +171,11 @@ int FX2_ll::write_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||||
/* read len data using control
|
/* read len data using control
|
||||||
*/
|
*/
|
||||||
int FX2_ll::read_ctrl(uint8_t bRequest, uint16_t wValue,
|
int FX2_ll::read_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||||
uint8_t *buff, uint16_t len)
|
uint8_t *buff, uint16_t len, uint16_t wIndex)
|
||||||
{
|
{
|
||||||
int ret = libusb_control_transfer(dev_handle,
|
int ret = libusb_control_transfer(dev_handle,
|
||||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
|
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
|
||||||
bRequest, wValue, 0x0000, buff, len, 100);
|
bRequest, wValue, wIndex, buff, len, 100);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printError("Unable to read control request: "
|
printError("Unable to read control request: "
|
||||||
+ std::string(libusb_error_name(ret)));
|
+ std::string(libusb_error_name(ret)));
|
||||||
|
|
@ -177,6 +198,7 @@ bool FX2_ll::load_firmware(std::string firmware_path)
|
||||||
return false;
|
return false;
|
||||||
/* load */
|
/* load */
|
||||||
std::vector<IhexParser::data_line_t> data = ihex.getDataArray();
|
std::vector<IhexParser::data_line_t> data = ihex.getDataArray();
|
||||||
|
ProgressBar progress("Loading firmware", data.size(), 50, false);
|
||||||
for (size_t i = 0; i < data.size(); i++) {
|
for (size_t i = 0; i < data.size(); i++) {
|
||||||
IhexParser::data_line_t data_line = data[i];
|
IhexParser::data_line_t data_line = data[i];
|
||||||
|
|
||||||
|
|
@ -186,14 +208,16 @@ bool FX2_ll::load_firmware(std::string firmware_path)
|
||||||
while (toSend > 0) {
|
while (toSend > 0) {
|
||||||
uint16_t xfer_len = (toSend > 64) ? 64: toSend;
|
uint16_t xfer_len = (toSend > 64) ? 64: toSend;
|
||||||
if (!write_ctrl(FX2_FIRM_LOAD, addr, tx_buff, xfer_len)) {
|
if (!write_ctrl(FX2_FIRM_LOAD, addr, tx_buff, xfer_len)) {
|
||||||
printError("load firmware failed\n");
|
progress.fail();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
toSend -= xfer_len;
|
toSend -= xfer_len;
|
||||||
tx_buff += xfer_len;
|
tx_buff += xfer_len;
|
||||||
addr += xfer_len;
|
addr += xfer_len;
|
||||||
}
|
}
|
||||||
|
progress.display(i);
|
||||||
}
|
}
|
||||||
|
progress.done();
|
||||||
|
|
||||||
/* unset reset */
|
/* unset reset */
|
||||||
if (!reset(0))
|
if (!reset(0))
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
* Copyright (c) 2021-2026 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SRC_FX2_LL_HPP_
|
#ifndef SRC_FX2_LL_HPP_
|
||||||
|
|
@ -31,6 +31,14 @@ class FX2_ll {
|
||||||
uint16_t vid, uint16_t pid, const std::string &firmware_path);
|
uint16_t vid, uint16_t pid, const std::string &firmware_path);
|
||||||
~FX2_ll();
|
~FX2_ll();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief libusb_set_interface_alt_setting wrapper
|
||||||
|
* \param[in] if_num: Interface number
|
||||||
|
* \param[in] alt_setting: alternate setting
|
||||||
|
* \return true on success
|
||||||
|
*/
|
||||||
|
bool set_interface_alt_setting(const int if_num, const int alt_setting);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief bulk write
|
* \brief bulk write
|
||||||
* \param[in] endpoint: endpoint to use
|
* \param[in] endpoint: endpoint to use
|
||||||
|
|
@ -53,20 +61,22 @@ class FX2_ll {
|
||||||
* \param[in] wValue
|
* \param[in] wValue
|
||||||
* \param[in] buff: buffer to write
|
* \param[in] buff: buffer to write
|
||||||
* \param[in] len: buffer length
|
* \param[in] len: buffer length
|
||||||
|
* \param[in] wIndex: the index field for the setup packet
|
||||||
* \return false when transfer fails, true otherwise
|
* \return false when transfer fails, true otherwise
|
||||||
*/
|
*/
|
||||||
int write_ctrl(uint8_t bRequest, uint16_t wValue,
|
int write_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||||
uint8_t *buff, uint16_t len);
|
uint8_t *buff, uint16_t len, uint16_t wIndex=0x0000);
|
||||||
/*!
|
/*!
|
||||||
* \brief control write
|
* \brief control write
|
||||||
* \param[in] bRequest
|
* \param[in] bRequest
|
||||||
* \param[in] wValue
|
* \param[in] wValue
|
||||||
* \param[in] buff: buffer to write
|
* \param[in] buff: buffer to write
|
||||||
* \param[in] len: buffer length
|
* \param[in] len: buffer length
|
||||||
|
* \param[in] wIndex: the index field for the setup packet
|
||||||
* \return false when transfer fails, true otherwise
|
* \return false when transfer fails, true otherwise
|
||||||
*/
|
*/
|
||||||
int read_ctrl(uint8_t bRequest, uint16_t wValue,
|
int read_ctrl(uint8_t bRequest, uint16_t wValue,
|
||||||
uint8_t *buff, uint16_t len);
|
uint8_t *buff, uint16_t len, uint16_t wIndex=0x0000);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*!
|
/*!
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ void Gowin::checkCRC()
|
||||||
* is used, try to compare with this value
|
* is used, try to compare with this value
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
std::string hdr = _fs->getHeaderVal("checkSum");
|
std::string hdr = _fs->getHeaderVal("CheckSum");
|
||||||
if (!hdr.empty()) {
|
if (!hdr.empty()) {
|
||||||
if (ucode == strtol(hdr.c_str(), NULL, 16))
|
if (ucode == strtol(hdr.c_str(), NULL, 16))
|
||||||
goto success;
|
goto success;
|
||||||
|
|
|
||||||
15
src/jtag.cpp
15
src/jtag.cpp
|
|
@ -58,6 +58,9 @@
|
||||||
#ifdef ENABLE_XVC_CLIENT
|
#ifdef ENABLE_XVC_CLIENT
|
||||||
#include "xvc_client.hpp"
|
#include "xvc_client.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_XILINX_PLATFORM_CABLE_USB
|
||||||
|
#include "xilinxPlatformCableUSB.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
@ -162,7 +165,8 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
|
||||||
break;
|
break;
|
||||||
case MODE_ESP:
|
case MODE_ESP:
|
||||||
#ifdef ENABLE_ESP_USB
|
#ifdef ENABLE_ESP_USB
|
||||||
_jtag = new esp_usb_jtag(clkHZ, verbose, 0x303a, 0x1001);
|
_jtag = new esp_usb_jtag(clkHZ, verbose, 0x303a, 0x1001,
|
||||||
|
cable.bus_addr, cable.device_addr, serial);
|
||||||
#else
|
#else
|
||||||
std::cerr << "Jtag: support for esp32s3 cable was not enabled at compile time" << std::endl;
|
std::cerr << "Jtag: support for esp32s3 cable was not enabled at compile time" << std::endl;
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
|
@ -206,6 +210,15 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
|
||||||
case MODE_REMOTEBITBANG:
|
case MODE_REMOTEBITBANG:
|
||||||
_jtag = new RemoteBitbang_client(ip_adr, port, verbose);
|
_jtag = new RemoteBitbang_client(ip_adr, port, verbose);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
|
case MODE_XPCU:
|
||||||
|
#ifdef ENABLE_XILINX_PLATFORM_CABLE_USB
|
||||||
|
_jtag = new XilinxPlatformCableUSB(0x03fd, 0x0013, clkHZ,
|
||||||
|
firmware_path, verbose);
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
printError("Jtag: support for Xilinx Platform Cable USB (XPCU) was not enabled at compile time");
|
||||||
|
throw std::exception();
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
std::cerr << "Jtag: unknown cable type" << std::endl;
|
std::cerr << "Jtag: unknown cable type" << std::endl;
|
||||||
|
|
|
||||||
43
src/main.cpp
43
src/main.cpp
|
|
@ -79,7 +79,7 @@ struct arguments {
|
||||||
std::string secondary_bit_file;
|
std::string secondary_bit_file;
|
||||||
std::string device;
|
std::string device;
|
||||||
std::string cable;
|
std::string cable;
|
||||||
std::string ftdi_serial;
|
std::string usb_serial_num;
|
||||||
int ftdi_channel;
|
int ftdi_channel;
|
||||||
int status_pin;
|
int status_pin;
|
||||||
uint32_t freq;
|
uint32_t freq;
|
||||||
|
|
@ -264,13 +264,6 @@ int main(int argc, char **argv)
|
||||||
cable.config.interface = mapping[args.ftdi_channel];
|
cable.config.interface = mapping[args.ftdi_channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.ftdi_serial.empty()) {
|
|
||||||
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG){
|
|
||||||
printError("Error: FTDI serial param is for FTDI cables.");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.status_pin != -1) {
|
if (args.status_pin != -1) {
|
||||||
if (cable.type != MODE_FTDI_SERIAL){
|
if (cable.type != MODE_FTDI_SERIAL){
|
||||||
printError("Error: FTDI status pin is for FTDI MPSSE cables.");
|
printError("Error: FTDI status pin is for FTDI MPSSE cables.");
|
||||||
|
|
@ -279,6 +272,14 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!args.usb_serial_num.empty()) {
|
||||||
|
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG &&
|
||||||
|
cable.type != MODE_ESP){
|
||||||
|
printError("Error: usb-serial-num param is for FTDI and esp32s3 cables.");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (args.vid != 0) {
|
if (args.vid != 0) {
|
||||||
printInfo("Cable VID overridden");
|
printInfo("Cable VID overridden");
|
||||||
cable.vid = args.vid;
|
cable.vid = args.vid;
|
||||||
|
|
@ -389,7 +390,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
Jtag *jtag;
|
Jtag *jtag;
|
||||||
try {
|
try {
|
||||||
jtag = new Jtag(cable, &pins_config, args.device, args.ftdi_serial,
|
jtag = new Jtag(cable, &pins_config, args.device, args.usb_serial_num,
|
||||||
args.freq, args.verbose, args.ip_adr, args.port,
|
args.freq, args.verbose, args.ip_adr, args.port,
|
||||||
args.invert_read_edge, args.probe_firmware,
|
args.invert_read_edge, args.probe_firmware,
|
||||||
args.user_misc_devs);
|
args.user_misc_devs);
|
||||||
|
|
@ -667,7 +668,7 @@ int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
||||||
try {
|
try {
|
||||||
XVC_server *xvc = NULL;
|
XVC_server *xvc = NULL;
|
||||||
xvc = new XVC_server(args.port, cable, pins_config, args.device,
|
xvc = new XVC_server(args.port, cable, pins_config, args.device,
|
||||||
args.ftdi_serial, args.freq, args.verbose, args.ip_adr,
|
args.usb_serial_num, args.freq, args.verbose, args.ip_adr,
|
||||||
args.invert_read_edge, args.probe_firmware);
|
args.invert_read_edge, args.probe_firmware);
|
||||||
/* create connection */
|
/* create connection */
|
||||||
xvc->open_connection();
|
xvc->open_connection();
|
||||||
|
|
@ -889,6 +890,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
jtag_pins_conf_t *pins_config)
|
jtag_pins_conf_t *pins_config)
|
||||||
{
|
{
|
||||||
std::string freqo;
|
std::string freqo;
|
||||||
|
std::string ftdi_serial;
|
||||||
std::vector<std::string> pins, bus_dev_num;
|
std::vector<std::string> pins, bus_dev_num;
|
||||||
bool verbose = false, quiet = false;
|
bool verbose = false, quiet = false;
|
||||||
int8_t verbose_level = -2;
|
int8_t verbose_level = -2;
|
||||||
|
|
@ -927,8 +929,10 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
("busdev-num",
|
("busdev-num",
|
||||||
"select a probe by it bus and device number (bus_num:device_addr)",
|
"select a probe by it bus and device number (bus_num:device_addr)",
|
||||||
cxxopts::value<std::vector<std::string>>(bus_dev_num))
|
cxxopts::value<std::vector<std::string>>(bus_dev_num))
|
||||||
("ftdi-serial", "FTDI chip serial number",
|
("usb-serial-num", "USB iSerial (FTDI chip serial number or ESP32 iSerialNumber substring)",
|
||||||
cxxopts::value<std::string>(args->ftdi_serial))
|
cxxopts::value<std::string>(args->usb_serial_num))
|
||||||
|
("ftdi-serial", "FTDI chip serial number (Deprecated)",
|
||||||
|
cxxopts::value<std::string>(ftdi_serial))
|
||||||
("ftdi-channel",
|
("ftdi-channel",
|
||||||
"FTDI chip channel number (channels 0-3 map to A-D)",
|
"FTDI chip channel number (channels 0-3 map to A-D)",
|
||||||
cxxopts::value<int>(args->ftdi_channel))
|
cxxopts::value<int>(args->ftdi_channel))
|
||||||
|
|
@ -982,7 +986,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
cxxopts::value<unsigned int>(args->offset))
|
cxxopts::value<unsigned int>(args->offset))
|
||||||
("pins", "pin config TDI:TDO:TCK:TMS or MOSI:MISO:SCK:CS[:HOLDN:WPN]",
|
("pins", "pin config TDI:TDO:TCK:TMS or MOSI:MISO:SCK:CS[:HOLDN:WPN]",
|
||||||
cxxopts::value<std::vector<std::string>>(pins))
|
cxxopts::value<std::vector<std::string>>(pins))
|
||||||
("probe-firmware", "firmware for JTAG probe (usbBlasterII)",
|
("probe-firmware", "firmware for JTAG probe (usbBlasterII/xilinxPlatformCableUsb)",
|
||||||
cxxopts::value<std::string>(args->probe_firmware))
|
cxxopts::value<std::string>(args->probe_firmware))
|
||||||
("protect-flash", "protect SPI flash area",
|
("protect-flash", "protect SPI flash area",
|
||||||
cxxopts::value<uint32_t>(args->protect_flash))
|
cxxopts::value<uint32_t>(args->protect_flash))
|
||||||
|
|
@ -1027,7 +1031,8 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
cxxopts::value<std::string>(args->read_register))
|
cxxopts::value<std::string>(args->read_register))
|
||||||
("user-flash", "User flash file (Gowin LittleBee FPGA only)",
|
("user-flash", "User flash file (Gowin LittleBee FPGA only)",
|
||||||
cxxopts::value<std::string>(args->user_flash))
|
cxxopts::value<std::string>(args->user_flash))
|
||||||
("V,Version", "Print program version");
|
("V,version", "Print program version")
|
||||||
|
("Version", "Print program version (Deprecated)");
|
||||||
|
|
||||||
options.parse_positional({"bitstream"});
|
options.parse_positional({"bitstream"});
|
||||||
auto result = options.parse(argc, argv);
|
auto result = options.parse(argc, argv);
|
||||||
|
|
@ -1055,7 +1060,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
args->verbose = verbose_level;
|
args->verbose = verbose_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.count("Version")) {
|
if (result.count("Version") || result.count("version")) {
|
||||||
std::cout << "openFPGALoader " << VERSION << std::endl;
|
std::cout << "openFPGALoader " << VERSION << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -1133,6 +1138,14 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.count("ftdi-serial")) {
|
||||||
|
if (result.count("usb-serial-num")) {
|
||||||
|
printError("Error: ftdi-serial and usb-serial-num can't be used at the same time.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
args->usb_serial_num = ftdi_serial;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.count("busdev-num")) {
|
if (result.count("busdev-num")) {
|
||||||
if (bus_dev_num.size() != 2) {
|
if (bus_dev_num.size() != 2) {
|
||||||
printError("Error: busdev-num must be xx:yy");
|
printError("Error: busdev-num must be xx:yy");
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,7 @@ static std::map <uint32_t, fpga_model> fpga_list = {
|
||||||
{0x02e050dd, {"altera", "arria 10", "SX660", 10}},
|
{0x02e050dd, {"altera", "arria 10", "SX660", 10}},
|
||||||
|
|
||||||
/* Altera Agilex 3 */
|
/* Altera Agilex 3 */
|
||||||
|
{0x4361b0dd, {"altera", "agilex 3", "A3CY100", 10}},
|
||||||
{0x436db0dd, {"altera", "agilex 3", "A3CZ135", 10}},
|
{0x436db0dd, {"altera", "agilex 3", "A3CZ135", 10}},
|
||||||
|
|
||||||
/* Altera Agilex 5 */
|
/* Altera Agilex 5 */
|
||||||
|
|
|
||||||
|
|
@ -76,25 +76,27 @@ RemoteBitbang_client::~RemoteBitbang_client()
|
||||||
}
|
}
|
||||||
|
|
||||||
int RemoteBitbang_client::writeTMS(const uint8_t *tms, uint32_t len,
|
int RemoteBitbang_client::writeTMS(const uint8_t *tms, uint32_t len,
|
||||||
bool flush_buffer, __attribute__((unused)) const uint8_t tdi)
|
bool flush_buffer, const uint8_t tdi)
|
||||||
{
|
{
|
||||||
// empty buffer
|
// empty buffer
|
||||||
// if asked flush
|
// if asked flush
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return ((flush_buffer) ? flush() : 0);
|
return ((flush_buffer) ? flush() : 0);
|
||||||
|
|
||||||
|
_last_tdi = (tdi) ? TDI_BIT : 0;
|
||||||
|
|
||||||
uint8_t base_v = '0' + _last_tdi;
|
uint8_t base_v = '0' + _last_tdi;
|
||||||
for (uint32_t pos = 0; pos < len; pos++) {
|
for (uint32_t pos = 0; pos < len; pos++) {
|
||||||
// buffer full -> write
|
// buffer full -> write
|
||||||
if (_num_bytes == _buffer_size)
|
if ((_num_bytes + 2) >= _buffer_size)
|
||||||
ll_write(NULL);
|
flush();
|
||||||
_last_tms = (tms[pos >> 3] & (1 << (pos & 0x07))) ? TMS_BIT : 0;
|
_last_tms = (tms[pos >> 3] & (1 << (pos & 0x07))) ? TMS_BIT : 0;
|
||||||
_xfer_buf[_num_bytes++] = base_v + _last_tms;
|
_xfer_buf[_num_bytes++] = base_v + _last_tms;
|
||||||
_xfer_buf[_num_bytes++] = base_v + _last_tms + TCK_BIT;
|
_xfer_buf[_num_bytes++] = base_v + _last_tms + TCK_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush where it's asked or if the buffer is full
|
// flush where it's asked or if the buffer is full
|
||||||
if (flush_buffer || _num_bytes == _buffer_size * 8)
|
if (flush_buffer || _num_bytes == _buffer_size)
|
||||||
return flush();
|
return flush();
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
@ -107,9 +109,11 @@ int RemoteBitbang_client::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len,
|
||||||
|
|
||||||
uint8_t base_v = '0' + _last_tms;
|
uint8_t base_v = '0' + _last_tms;
|
||||||
for (uint32_t pos = 0; pos < len; pos++) {
|
for (uint32_t pos = 0; pos < len; pos++) {
|
||||||
if (_num_bytes == _buffer_size)
|
const uint32_t pos_byte = (pos >> 3);
|
||||||
ll_write(NULL); // NULL because _num_bytes is always 0 when read
|
const uint32_t pos_bit = (1 << (pos & 0x07));
|
||||||
_last_tdi = (tx[pos >> 3] & (1 << (pos & 0x07))) ? TDI_BIT : 0;
|
if ((_num_bytes + 2) >= _buffer_size)
|
||||||
|
flush();
|
||||||
|
_last_tdi = (tx[pos_byte] & pos_bit) ? TDI_BIT : 0;
|
||||||
if (end && pos == len - 1) {
|
if (end && pos == len - 1) {
|
||||||
_last_tms = TMS_BIT;
|
_last_tms = TMS_BIT;
|
||||||
base_v = '0' + _last_tms;
|
base_v = '0' + _last_tms;
|
||||||
|
|
@ -120,9 +124,9 @@ int RemoteBitbang_client::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len,
|
||||||
uint8_t tdo;
|
uint8_t tdo;
|
||||||
ll_write(&tdo);
|
ll_write(&tdo);
|
||||||
if (tdo == '1')
|
if (tdo == '1')
|
||||||
rx[pos >> 3] |= (1 << (pos & 0x07));
|
rx[pos_byte] |= pos_bit;
|
||||||
else
|
else
|
||||||
rx[pos >> 3] &= ~(1 << (pos & 0x07));
|
rx[pos_byte] &= ~pos_bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,30 +134,23 @@ int RemoteBitbang_client::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle clk with constant TDI and TMS.
|
// toggle clk with constant TDI and TMS.
|
||||||
int RemoteBitbang_client::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
int RemoteBitbang_client::toggleClk([[maybe_unused]] uint8_t tms,
|
||||||
|
[[maybe_unused]] uint8_t tdi, uint32_t clk_len)
|
||||||
{
|
{
|
||||||
// nothing to do
|
// nothing to do
|
||||||
if (clk_len == 0)
|
if (clk_len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (_num_bytes != 0)
|
|
||||||
flush();
|
|
||||||
|
|
||||||
_last_tms = tms;
|
const uint8_t val = (_last_tms | _last_tdi);
|
||||||
_last_tdi = tdi;
|
|
||||||
uint8_t val = (_last_tms | _last_tdi);
|
|
||||||
|
|
||||||
// flush buffer before starting
|
|
||||||
if (_num_bytes != 0)
|
|
||||||
flush();
|
|
||||||
|
|
||||||
for (uint32_t len = 0; len < clk_len; len++) {
|
for (uint32_t len = 0; len < clk_len; len++) {
|
||||||
if (len == _num_bytes)
|
if ((_num_bytes + 2) >= _buffer_size)
|
||||||
ll_write(NULL);
|
flush();
|
||||||
_xfer_buf[_num_bytes++] = '0' + val;
|
_xfer_buf[_num_bytes++] = '0' + val;
|
||||||
_xfer_buf[_num_bytes++] = '0' + (val | TCK_BIT);
|
_xfer_buf[_num_bytes++] = '0' + (val | TCK_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ll_write(NULL);
|
flush();
|
||||||
|
|
||||||
return clk_len;
|
return clk_len;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ UsbBlaster::UsbBlaster(const cable_t &cable, const std::string &firmware_path,
|
||||||
#else
|
#else
|
||||||
throw std::runtime_error("usb-blasterI: Not build");
|
throw std::runtime_error("usb-blasterI: Not build");
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_USB_BLASTERII
|
|
||||||
else if (cable.pid == 0x6810 || cable.pid == 0x6010)
|
else if (cable.pid == 0x6810 || cable.pid == 0x6010)
|
||||||
|
#ifdef ENABLE_USB_BLASTERII
|
||||||
ll_driver = new UsbBlasterII(firmware_path);
|
ll_driver = new UsbBlasterII(firmware_path);
|
||||||
#else
|
#else
|
||||||
throw std::runtime_error("usb-blasterII: Not build");
|
throw std::runtime_error("usb-blasterII: Not build");
|
||||||
|
|
@ -459,7 +459,7 @@ UsbBlasterII::UsbBlasterII(const std::string &firmware_path)
|
||||||
else
|
else
|
||||||
fpath = firmware_path;
|
fpath = firmware_path;
|
||||||
fx2 = new FX2_ll(0x09fb, 0x6810, 0x09fb, 0x6010, fpath);
|
fx2 = new FX2_ll(0x09fb, 0x6810, 0x09fb, 0x6010, fpath);
|
||||||
if (!fx2->read_ctrl(0x94, 0, buf, 5)) {
|
if (!fx2->read_ctrl(0x94, 0, buf, 5, 0x0000)) {
|
||||||
throw std::runtime_error("Unable to read firmware version.");
|
throw std::runtime_error("Unable to read firmware version.");
|
||||||
}
|
}
|
||||||
printInfo("USB-Blaster II firmware version: " + std::string((char *)buf));
|
printInfo("USB-Blaster II firmware version: " + std::string((char *)buf));
|
||||||
|
|
|
||||||
|
|
@ -659,7 +659,6 @@ void Xilinx::program(unsigned int offset, bool unprotect_flash)
|
||||||
/* Check for BPI flash boards */
|
/* Check for BPI flash boards */
|
||||||
if (_is_bpi_board) {
|
if (_is_bpi_board) {
|
||||||
program_bpi(bit, offset);
|
program_bpi(bit, offset);
|
||||||
reset();
|
|
||||||
} else {
|
} else {
|
||||||
if (_flash_chips & PRIMARY_FLASH) {
|
if (_flash_chips & PRIMARY_FLASH) {
|
||||||
select_flash_chip(PRIMARY_FLASH);
|
select_flash_chip(PRIMARY_FLASH);
|
||||||
|
|
@ -669,8 +668,6 @@ void Xilinx::program(unsigned int offset, bool unprotect_flash)
|
||||||
select_flash_chip(SECONDARY_FLASH);
|
select_flash_chip(SECONDARY_FLASH);
|
||||||
program_spi(secondary_bit, _secondary_file_extension, offset, unprotect_flash);
|
program_spi(secondary_bit, _secondary_file_extension, offset, unprotect_flash);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_fpga_family == SPARTAN3_FAMILY)
|
if (_fpga_family == SPARTAN3_FAMILY)
|
||||||
|
|
@ -810,6 +807,9 @@ void Xilinx::program_bpi(ConfigBitstreamParser *bit, unsigned int offset)
|
||||||
throw std::runtime_error("BPI flash programming failed");
|
throw std::runtime_error("BPI flash programming failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the board if skip_reset is not set */
|
||||||
|
post_flash_access();
|
||||||
|
|
||||||
printInfo("BPI flash programming complete");
|
printInfo("BPI flash programming complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1277,6 +1277,18 @@ bool Xilinx::dumpFlash(uint32_t base_addr, uint32_t len)
|
||||||
|
|
||||||
bool Xilinx::detect_flash()
|
bool Xilinx::detect_flash()
|
||||||
{
|
{
|
||||||
|
if (_is_bpi_board) {
|
||||||
|
if (!_bpi_flash) {
|
||||||
|
if (!load_bpi_bridge())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!_bpi_flash->detect()) {
|
||||||
|
printError("BPI flash detection failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return post_flash_access();
|
||||||
|
}
|
||||||
|
|
||||||
if (_flash_chips & PRIMARY_FLASH) {
|
if (_flash_chips & PRIMARY_FLASH) {
|
||||||
select_flash_chip(PRIMARY_FLASH);
|
select_flash_chip(PRIMARY_FLASH);
|
||||||
if (!FlashInterface::detect_flash())
|
if (!FlashInterface::detect_flash())
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,378 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2026 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "fx2_ll.hpp"
|
||||||
|
#include "xilinxPlatformCableUSB.hpp"
|
||||||
|
|
||||||
|
#define XPCU_BREQUEST 0xB0
|
||||||
|
#define XPCU_INITIALIZED_VID 0x03fd
|
||||||
|
#define XPCU_INITIALIZED_PID 0x0008
|
||||||
|
#define XPCU_CMD_DISABLE 0x10
|
||||||
|
#define XPCU_CMD_ENABLE 0x18
|
||||||
|
#define XPCU_CMD_SET_SPEED 0x28
|
||||||
|
#define XPCU_CMD_STATUS 0x38
|
||||||
|
#define XPCU_CMD_RETURN_CONSTANT 0x40
|
||||||
|
#define XPCU_CMD_GET_VERSION 0x50
|
||||||
|
#define XPCU_CMD_GPIO_TRANSFER 0xA6
|
||||||
|
#define XPCU_EP_JTAG_OUT 0x02
|
||||||
|
#define XPCU_EP_JTAG_IN 0x86
|
||||||
|
#define XPCU_STATUS_CONNECTED 0x40
|
||||||
|
#define XPCU_SPEED_CLASS_ENABLE 0x10
|
||||||
|
#define XPCU_VERSION_CPLD 0x01
|
||||||
|
#define XPCU_VERSION_CONST1 0x02
|
||||||
|
#define XPCU_VERSION_CONST2 0x03
|
||||||
|
|
||||||
|
#define TCK_OFFSET 0
|
||||||
|
#define TDO_OFFSET 4
|
||||||
|
#define TDI_OFFSET 0
|
||||||
|
#define TMS_OFFSET 4
|
||||||
|
|
||||||
|
#define TCK_IDX (1 << TCK_OFFSET)
|
||||||
|
#define TDO_IDX (1 << TDO_OFFSET)
|
||||||
|
#define TDI_IDX (1 << TDI_OFFSET)
|
||||||
|
#define TMS_IDX (1 << TMS_OFFSET)
|
||||||
|
|
||||||
|
XilinxPlatformCableUSB::XilinxPlatformCableUSB(const uint16_t vid,
|
||||||
|
const uint16_t pid,
|
||||||
|
uint32_t clkHz,
|
||||||
|
const std::string &firmware_path,
|
||||||
|
int8_t verbose): _verbose(verbose), _nb_bit(0), _nb_tdo_bit(0),
|
||||||
|
_curr_tms(0), _curr_tdi(0), _buffer_size(4096),
|
||||||
|
_buffer_bit_size((_buffer_size / 2 * 4) - 1)
|
||||||
|
{
|
||||||
|
std::string firmware_file;
|
||||||
|
/* firmare path must be known:
|
||||||
|
* 1/ provided by user
|
||||||
|
* 2/ from Vivado install directory
|
||||||
|
* 3/ from ISE install directory
|
||||||
|
*/
|
||||||
|
if (firmware_path.empty() && strlen(ISE_DIR) == 0 && strlen(VIVADO_DIR) == 0) {
|
||||||
|
printError("missing FX2 firmware");
|
||||||
|
printError("use --probe-firmware with something");
|
||||||
|
printError("like /opt/Xilinx/14.7/ISE_DS/ISE/bin/lin64/xusb_xp2.hex for ISE");
|
||||||
|
printError("or /opt/Xilinx/Vivado/VERSION/data/xicom/xusb_xp2.hex for Vivado");
|
||||||
|
printError("Or use -DISE_DIR=/opt/Xilinx/14.7 / -DVIVADO_DIR=/opt/Xilinx/Vivado/VERSION at build time");
|
||||||
|
throw std::runtime_error("xilinxPlatformCableUSB: missing firmware");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract firmware according to possibilities */
|
||||||
|
if (!firmware_path.empty())
|
||||||
|
firmware_file = firmware_path;
|
||||||
|
else if (strlen(VIVADO_DIR) > 0)
|
||||||
|
firmware_file = VIVADO_DIR "/data/xicom/xusb_xp2.hex";
|
||||||
|
else if (strlen(ISE_DIR) > 0)
|
||||||
|
firmware_file = ISE_DIR "/ISE_DS/ISE/bin/lin64/xusb_xp2.hex";
|
||||||
|
|
||||||
|
try {
|
||||||
|
fx2 = std::make_unique<FX2_ll>(vid, pid, XPCU_INITIALIZED_VID,
|
||||||
|
XPCU_INITIALIZED_PID, firmware_file);
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
printError(e.what());
|
||||||
|
throw std::runtime_error("lowlevel init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
fx2->set_interface_alt_setting(0, 1);
|
||||||
|
|
||||||
|
displayCableVersion();
|
||||||
|
|
||||||
|
/* Write GPIO bit */
|
||||||
|
fx2->write_ctrl(XPCU_BREQUEST, 0x030, nullptr, 0, (1 << 3));
|
||||||
|
|
||||||
|
if (!enableDevice(true))
|
||||||
|
throw std::runtime_error("Unable to enable device");
|
||||||
|
|
||||||
|
uint8_t buf[1];
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_STATUS, buf, 1))
|
||||||
|
throw std::runtime_error("Unable to read status.");
|
||||||
|
|
||||||
|
char mess[64];
|
||||||
|
snprintf(mess, sizeof(mess), "status %02x connected: %s",
|
||||||
|
buf[0], (buf[0] & XPCU_STATUS_CONNECTED) ? "yes" : "no");
|
||||||
|
printInfo(mess);
|
||||||
|
|
||||||
|
_in_buf = std::make_unique<uint8_t[]>(_buffer_size);
|
||||||
|
|
||||||
|
setClkFreq(clkHz);
|
||||||
|
}
|
||||||
|
|
||||||
|
XilinxPlatformCableUSB::~XilinxPlatformCableUSB()
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
enableDevice(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::setClkFreq(uint32_t clkHz)
|
||||||
|
{
|
||||||
|
/* speed table: index Hz; bit 4 must always be set in the speed class */
|
||||||
|
static constexpr uint32_t speeds[] = {12000000, 6000000, 3000000, 1500000, 750000};
|
||||||
|
uint8_t speed = 4; /* default: slowest */
|
||||||
|
for (uint8_t i = 0; i < sizeof(speeds) / sizeof(speeds[0]); i++) {
|
||||||
|
if (speeds[i] <= clkHz) {
|
||||||
|
speed = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fx2->write_ctrl(XPCU_BREQUEST, XPCU_CMD_SET_SPEED, nullptr, 0,
|
||||||
|
speed | XPCU_SPEED_CLASS_ENABLE)) {
|
||||||
|
printError("setClkFreq: failed to set speed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
_clkHZ = speeds[speed];
|
||||||
|
printInfo("Jtag frequency : requested " + std::to_string(clkHz) +
|
||||||
|
" Hz -> real " + std::to_string(_clkHZ) + " Hz");
|
||||||
|
return _clkHZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::writeTMS(const uint8_t *tms, uint32_t len,
|
||||||
|
bool flush_buffer, const uint8_t tdi)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return flush_buffer ? flush() : 0;
|
||||||
|
|
||||||
|
_curr_tdi = tdi ? 1 : 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
|
_curr_tms = (tms[i >> 3] >> (i & 0x07)) & 0x01;
|
||||||
|
if (storeBit(_curr_tdi, _curr_tms, 1, 0)) {
|
||||||
|
if (write(nullptr, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flush_buffer) {
|
||||||
|
ret = flush();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (rx && _nb_bit != 0) {
|
||||||
|
if (write(nullptr, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rx_offset = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
|
bool last_bit = (i == len - 1 && end);
|
||||||
|
_curr_tdi = tx ? (0x01 & ((tx[i >> 3]) >> (i & 0x07))) : 0;
|
||||||
|
|
||||||
|
if (last_bit)
|
||||||
|
_curr_tms = 1;
|
||||||
|
|
||||||
|
if (storeBit(_curr_tdi, _curr_tms, 1, rx ? 1 : 0)) {
|
||||||
|
uint32_t bits = _nb_tdo_bit;
|
||||||
|
if (write(rx, rx_offset) < 0)
|
||||||
|
return -1;
|
||||||
|
rx_offset += bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_nb_bit != 0 && (end || rx)) {
|
||||||
|
if (write(rx, rx_offset) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::toggleClk([[maybe_unused]] uint8_t tms,
|
||||||
|
[[maybe_unused]] uint8_t tdi, uint32_t clk_len)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < clk_len; i++) {
|
||||||
|
if (storeBit(_curr_tdi, _curr_tms, 1, 0)) {
|
||||||
|
if (write(nullptr, 0) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush buffer if not empty */
|
||||||
|
if (_nb_bit != 0) {
|
||||||
|
if (flush() < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clk_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::flush()
|
||||||
|
{
|
||||||
|
return write(nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TMS 1st nibble, TDI 2nd nibble, TDO 3rd nibble, TCK 4th nibble
|
||||||
|
* byte n byte n+1
|
||||||
|
* [7:4 3:0] [7:4 3:0]
|
||||||
|
* TMS TDI TDO TCK
|
||||||
|
*/
|
||||||
|
bool XilinxPlatformCableUSB::storeBit(uint8_t tdi, uint8_t tms,
|
||||||
|
uint8_t tck, uint8_t tdo) noexcept
|
||||||
|
{
|
||||||
|
const uint32_t buf_pos = (_nb_bit >> 2) << 1;
|
||||||
|
const uint8_t bit_pos = _nb_bit & 0x03;
|
||||||
|
|
||||||
|
if (bit_pos == 0)
|
||||||
|
_in_buf[buf_pos] = _in_buf[buf_pos + 1] = 0;
|
||||||
|
|
||||||
|
if (tms)
|
||||||
|
_in_buf[buf_pos] |= (TMS_IDX << bit_pos);
|
||||||
|
if (tdi)
|
||||||
|
_in_buf[buf_pos] |= (TDI_IDX << bit_pos);
|
||||||
|
if (tdo)
|
||||||
|
_in_buf[buf_pos + 1] |= (TDO_IDX << bit_pos);
|
||||||
|
if (tck)
|
||||||
|
_in_buf[buf_pos + 1] |= (TCK_IDX << bit_pos);
|
||||||
|
|
||||||
|
_nb_bit++;
|
||||||
|
if (tdo)
|
||||||
|
_nb_tdo_bit++;
|
||||||
|
|
||||||
|
return _nb_bit >= _buffer_bit_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute how many bytes EP6 will return for nb_bit TDO bits.
|
||||||
|
* The device uses a shift-register encoding: a 16-bit register that grows
|
||||||
|
* to 32-bit after 16 bits, then a new register starts every 32 bits.
|
||||||
|
*/
|
||||||
|
uint32_t XilinxPlatformCableUSB::rxBufSize(uint32_t nb_bit) noexcept
|
||||||
|
{
|
||||||
|
const uint32_t full_groups = nb_bit / 32;
|
||||||
|
const uint32_t rem = nb_bit & 31u;
|
||||||
|
return full_groups * 4 + (rem == 0 ? 0 : (rem > 16 ? 4 : 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
int XilinxPlatformCableUSB::write(uint8_t *rx, uint32_t rx_offset)
|
||||||
|
{
|
||||||
|
if (_nb_bit == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* N ops: N/4 pairs of 2 bytes each (round up to complete pair) */
|
||||||
|
uint32_t xfer_tx = (_nb_bit >> 1) & ~0x01u;
|
||||||
|
xfer_tx += ((_nb_bit & 0x03) != 0) ? 2 : 0;
|
||||||
|
|
||||||
|
/* count is 0-indexed per protocol spec */
|
||||||
|
if (!fx2->write_ctrl(XPCU_BREQUEST, XPCU_CMD_GPIO_TRANSFER, nullptr, 0,
|
||||||
|
_nb_bit - 1)) {
|
||||||
|
printError("Fails to write GPIO transfer control message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fx2->write(XPCU_EP_JTAG_OUT, _in_buf.get(), xfer_tx) != (int)xfer_tx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (rx) {
|
||||||
|
if (_nb_tdo_bit != _nb_bit) {
|
||||||
|
printError("Unable to decode mixed TDO/non-TDO transfer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t xfer_rx = rxBufSize(_nb_tdo_bit);
|
||||||
|
std::vector<uint8_t> rx_buf(xfer_rx);
|
||||||
|
if (fx2->read(XPCU_EP_JTAG_IN, rx_buf.data(), xfer_rx) != (int)xfer_rx)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Decode shift-register encoded TDO bits into rx.
|
||||||
|
* Each group of up to 32 bits occupies a 16 or 32-bit little-endian
|
||||||
|
* shift register: bit_k is at position (reg_size - group + k).
|
||||||
|
*/
|
||||||
|
uint32_t buf_off = 0;
|
||||||
|
uint32_t remaining = _nb_tdo_bit;
|
||||||
|
uint32_t bit_idx = 0;
|
||||||
|
while (remaining > 0) {
|
||||||
|
const uint32_t group = (remaining > 32) ? 32 : remaining;
|
||||||
|
const uint32_t reg_size = (group > 16) ? 32 : 16;
|
||||||
|
const uint32_t shift = reg_size - group;
|
||||||
|
uint32_t reg = 0;
|
||||||
|
for (uint32_t b = 0; b < reg_size / 8; b++)
|
||||||
|
reg |= (uint32_t)rx_buf[buf_off + b] << (b * 8);
|
||||||
|
const uint32_t base = rx_offset + bit_idx;
|
||||||
|
if ((base & 7u) == 0 && (group & 7u) == 0) {
|
||||||
|
uint8_t *out = rx + (base >> 3);
|
||||||
|
for (uint32_t b = 0; b < group / 8; b++)
|
||||||
|
out[b] = static_cast<uint8_t>((reg >> (shift + b * 8)) & 0xFF);
|
||||||
|
} else {
|
||||||
|
for (uint32_t k = 0; k < group; k++) {
|
||||||
|
const uint32_t out_bit = base + k;
|
||||||
|
if ((reg >> (shift + k)) & 1)
|
||||||
|
rx[out_bit >> 3] |= (1 << (out_bit & 7));
|
||||||
|
else
|
||||||
|
rx[out_bit >> 3] &= ~(1 << (out_bit & 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf_off += reg_size / 8;
|
||||||
|
bit_idx += group;
|
||||||
|
remaining -= group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_nb_bit = 0;
|
||||||
|
_nb_tdo_bit = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XilinxPlatformCableUSB::enableDevice(bool enable)
|
||||||
|
{
|
||||||
|
if (!fx2->write_ctrl(XPCU_BREQUEST,
|
||||||
|
(enable ? XPCU_CMD_ENABLE : XPCU_CMD_DISABLE), nullptr, 0)) {
|
||||||
|
char mess[64];
|
||||||
|
snprintf(mess, sizeof(mess), "Unable to %s device",
|
||||||
|
(enable ? "enable" : "disable"));
|
||||||
|
printError(mess);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XilinxPlatformCableUSB::displayCableVersion()
|
||||||
|
{
|
||||||
|
uint8_t buf[2];
|
||||||
|
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_RETURN_CONSTANT, buf, 2))
|
||||||
|
throw std::runtime_error("Unable to read constant.");
|
||||||
|
const uint16_t const0 = ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
|
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_GET_VERSION, buf, 2))
|
||||||
|
throw std::runtime_error("Unable to read firmware version.");
|
||||||
|
const uint16_t fx2_firmware = ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
|
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_GET_VERSION, buf, 2,
|
||||||
|
XPCU_VERSION_CPLD))
|
||||||
|
throw std::runtime_error("Unable to read CPLD version.");
|
||||||
|
const uint16_t cpld_firmware = ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
|
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_GET_VERSION, buf, 2,
|
||||||
|
XPCU_VERSION_CONST1))
|
||||||
|
throw std::runtime_error("Unable to read const 1.");
|
||||||
|
const uint16_t const1 = ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
|
|
||||||
|
if (!fx2->read_ctrl(XPCU_BREQUEST, XPCU_CMD_GET_VERSION, buf, 2,
|
||||||
|
XPCU_VERSION_CONST2))
|
||||||
|
throw std::runtime_error("Unable to read const 2.");
|
||||||
|
const uint16_t const2 = ((uint16_t)buf[0] << 8) | buf[1];
|
||||||
|
|
||||||
|
printf("FX2 version: %04x\n", fx2_firmware);
|
||||||
|
printf("CPLD version: %04x\n", cpld_firmware);
|
||||||
|
printf("Const0 version: %04x\n", const0);
|
||||||
|
printf("Const1 version: %04x\n", const1);
|
||||||
|
printf("Const2 version: %04x\n", const2);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2026 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_XILINXPLATFORMCABLEUSB_HPP_
|
||||||
|
#define SRC_XILINXPLATFORMCABLEUSB_HPP_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "fx2_ll.hpp"
|
||||||
|
#include "jtagInterface.hpp"
|
||||||
|
|
||||||
|
#define XPCU_DEFAULT_VID 0x03fd
|
||||||
|
#define XPCU_DEFAULT_PID 0x0013
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file xilinxPlatformCableUSB.hpp
|
||||||
|
* \class XilinxPlatformCableUSB
|
||||||
|
* \brief concrete class between jtag implementation and Xilinx USB Cable probe
|
||||||
|
* \author Gwenhael Goavec-Merou
|
||||||
|
*/
|
||||||
|
class XilinxPlatformCableUSB : public JtagInterface {
|
||||||
|
public:
|
||||||
|
XilinxPlatformCableUSB(const uint16_t vid = XPCU_DEFAULT_VID,
|
||||||
|
const uint16_t pid = XPCU_DEFAULT_PID,
|
||||||
|
uint32_t clkHz = 750000,
|
||||||
|
const std::string &firmware_path = "",
|
||||||
|
int8_t verbose = 0);
|
||||||
|
~XilinxPlatformCableUSB() override;
|
||||||
|
|
||||||
|
int setClkFreq(uint32_t clkHz) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief drive TMS to move in JTAG state machine
|
||||||
|
* \param tms serie of TMS state
|
||||||
|
* \param len number of TMS state
|
||||||
|
* \param flush_buffer force flushing the buffer
|
||||||
|
* \param tdi TDI constant value
|
||||||
|
* \return number of state written
|
||||||
|
*/
|
||||||
|
int writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer,
|
||||||
|
const uint8_t tdi = 1) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief send TDI bits (mainly in shift DR/IR state)
|
||||||
|
* \param tx array of TDI values (used to write)
|
||||||
|
* \param rx array of TDO values (used when read)
|
||||||
|
* \param len number of bit to send/receive
|
||||||
|
* \param end in JTAG state machine last bit and tms are set in same time
|
||||||
|
* \return number of bit written and/or read
|
||||||
|
*/
|
||||||
|
int writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief toggle clock with static tms and tdi
|
||||||
|
* \param tms state of tms signal
|
||||||
|
* \param tdi state of tdi signal
|
||||||
|
* \param clk_len number of clock cycle
|
||||||
|
* \return number of clock cycle send
|
||||||
|
*/
|
||||||
|
int toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief return internal buffer size (in byte).
|
||||||
|
* \return _buffer_size
|
||||||
|
*/
|
||||||
|
int get_buffer_size() override { return static_cast<int>(_buffer_size); }
|
||||||
|
|
||||||
|
bool isFull() override { return _nb_bit >= _buffer_bit_size; }
|
||||||
|
|
||||||
|
int flush() override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief display fx2 & CPLD firmwares version
|
||||||
|
*/
|
||||||
|
void displayCableVersion();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief enable device output
|
||||||
|
* \param[in] enable: enable or disable device
|
||||||
|
* \return true when transfer success, false otherwise
|
||||||
|
*/
|
||||||
|
bool enableDevice(bool enable);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* \brief pack one JTAG bit into the internal buffer
|
||||||
|
* \return true when buffer is full, false otherwise
|
||||||
|
*/
|
||||||
|
bool storeBit(uint8_t tdi, uint8_t tms, uint8_t tck, uint8_t tdo) noexcept;
|
||||||
|
int write(uint8_t *rx, uint32_t rx_offset = 0);
|
||||||
|
static uint32_t rxBufSize(uint32_t nb_bit) noexcept;
|
||||||
|
|
||||||
|
int8_t _verbose;
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]> _in_buf;
|
||||||
|
uint32_t _nb_bit;
|
||||||
|
uint32_t _nb_tdo_bit;
|
||||||
|
uint8_t _curr_tms;
|
||||||
|
uint8_t _curr_tdi;
|
||||||
|
uint32_t _buffer_size;
|
||||||
|
uint32_t _buffer_bit_size;
|
||||||
|
std::unique_ptr<FX2_ll> fx2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SRC_XILINXPLATFORMCABLEUSB_HPP_
|
||||||
Loading…
Reference in New Issue