Merge branch 'trabucayre:master' into master
This commit is contained in:
commit
8de2ae4562
|
|
@ -118,6 +118,7 @@ jobs:
|
|||
run: |
|
||||
#brew update
|
||||
brew install --only-dependencies openFPGALoader
|
||||
brew install hidapi
|
||||
|
||||
- name: '🚧 Build tarball'
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ option(ENABLE_USB_BLASTERII "enable Altera USB Blaster II support" ${
|
|||
|
||||
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(VIVADO_PATH "" CACHE STRING "Vivado root directory (something like /opt/Xilinx/Vivado/VERSION)")
|
||||
|
||||
# Libgpiod is only available on Linux OS.
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
|
@ -64,6 +65,8 @@ else()
|
|||
set(ENABLE_LIBGPIOD OFF)
|
||||
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.
|
||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
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_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
|
||||
# need this library.
|
||||
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
|
||||
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)
|
||||
endif()
|
||||
|
||||
|
|
@ -120,11 +128,6 @@ if (ENABLE_USB_SCAN OR ENABLE_GOWIN_GWU2X)
|
|||
set(USE_LIBUSB_LL ON)
|
||||
endif()
|
||||
|
||||
# Only enable fx2_ll when cable using it
|
||||
if (ENABLE_USB_BLASTERII)
|
||||
set(USE_FX2_LL ON)
|
||||
endif()
|
||||
|
||||
####################################################################################################
|
||||
# Cross-compilation support
|
||||
####################################################################################################
|
||||
|
|
@ -179,28 +182,23 @@ include(GNUInstallDirs)
|
|||
add_definitions(-DDATA_DIR=\"${CMAKE_INSTALL_FULL_DATAROOTDIR}\")
|
||||
|
||||
add_definitions(-DISE_DIR=\"${ISE_PATH}\")
|
||||
add_definitions(-DVIVADO_DIR=\"${VIVADO_PATH}\")
|
||||
|
||||
####################################################################################################
|
||||
# Dependencies check/search
|
||||
####################################################################################################
|
||||
|
||||
if (USE_LIBFTDI)
|
||||
# Try to find the LibFTDI1 with cmake
|
||||
find_package(LibFTDI1 QUIET)
|
||||
endif()
|
||||
|
||||
if (USE_PKGCONFIG)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# Backward compat when the libftdi is not found
|
||||
# by using cmake
|
||||
if (USE_LIBFTDI)
|
||||
if (NOT LIBFTDI_FOUND)
|
||||
pkg_check_modules(LIBFTDI REQUIRED libftdi1)
|
||||
string(REPLACE "." ";" VERSION_LIST ${LIBFTDI_VERSION})
|
||||
list(GET VERSION_LIST 0 LIBFTDI_VERSION_MAJOR)
|
||||
list(GET VERSION_LIST 1 LIBFTDI_VERSION_MINOR)
|
||||
endif()
|
||||
pkg_check_modules(LIBFTDI REQUIRED libftdi1)
|
||||
string(REPLACE "." ";" VERSION_LIST ${LIBFTDI_VERSION})
|
||||
list(GET VERSION_LIST 0 LIBFTDI_VERSION_MAJOR)
|
||||
list(GET VERSION_LIST 1 LIBFTDI_VERSION_MINOR)
|
||||
string(REGEX REPLACE "[^0-9].*" "" LIBFTDI_VERSION_MINOR "${LIBFTDI_VERSION_MINOR}")
|
||||
else()
|
||||
set(LIBFTDI_LIBRARY_DIRS "")
|
||||
set(LIBFTDI_INCLUDE_DIRS "")
|
||||
|
|
@ -590,6 +588,12 @@ list (APPEND OPENFPGALOADER_HEADERS src/svf_jtag.hpp)
|
|||
add_definitions(-DENABLE_SVF_JTAG)
|
||||
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
|
||||
if (ENABLE_XILINX_VIRTUAL_CABLE_CLIENT)
|
||||
list (APPEND OPENFPGALOADER_SOURCE src/xvc_client.cpp)
|
||||
|
|
@ -772,6 +776,13 @@ else()
|
|||
message("Remote bitbang client support disabled")
|
||||
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)
|
||||
add_definitions(-DENABLE_XVC_CLIENT=1)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-pthread ${CMAKE_EXE_LINKER_FLAGS}")
|
||||
|
|
@ -799,6 +810,7 @@ if (ZLIB_FOUND)
|
|||
add_definitions(-DHAS_ZLIB=1)
|
||||
else()
|
||||
message("zlib library not found: can't flash intel/altera devices")
|
||||
message("or reads compressed bitstreams")
|
||||
endif()
|
||||
|
||||
if (LINK_CMAKE_THREADS)
|
||||
|
|
@ -813,7 +825,6 @@ if (USE_LIBFTDI)
|
|||
add_definitions(-DFTDI_VERSION=${FTDI_VAL})
|
||||
endif()
|
||||
|
||||
|
||||
install(TARGETS openFPGALoader DESTINATION bin)
|
||||
|
||||
####################################################################################################
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ openFPGALoader -- a program to flash FPGA
|
|||
non volatile memory (default: 0)
|
||||
--pins arg pin config TDI:TDO:TCK:TMS or
|
||||
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
|
||||
--quiet Produce quiet output (no progress bar)
|
||||
-r, --reset reset FPGA after operations
|
||||
|
|
|
|||
|
|
@ -34,6 +34,13 @@
|
|||
Memory: OK
|
||||
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
|
||||
Description: A5EC008BM16AE6S FPGA Starter Kit
|
||||
URL: https://www.arrow.com/en/products/axe5000/trenz-electronic-gmbh.html
|
||||
|
|
@ -380,8 +387,8 @@
|
|||
Memory: OK
|
||||
Flash: OK
|
||||
Constraints:
|
||||
- ECPIX-5-45F
|
||||
- ECPIX-5-85F
|
||||
- ECPIX-5-45F
|
||||
- ECPIX-5-85F
|
||||
|
||||
- ID: ecpix5_r03
|
||||
Description: LambdaConcept ECPIX-5 (FT4232)
|
||||
|
|
@ -390,8 +397,8 @@
|
|||
Memory: OK
|
||||
Flash: OK
|
||||
Constraints:
|
||||
- ECPIX-5-45F
|
||||
- ECPIX-5-85F
|
||||
- ECPIX-5-45F
|
||||
- ECPIX-5-85F
|
||||
|
||||
- ID: fireant
|
||||
Description: Fireant Trion T8
|
||||
|
|
@ -451,8 +458,8 @@
|
|||
Memory: NA
|
||||
Flash: OK
|
||||
Constraints:
|
||||
- iCEBreaker-bitsy-v0
|
||||
- iCEBreaker-bitsy-v1
|
||||
- iCEBreaker-bitsy-v0
|
||||
- iCEBreaker-bitsy-v1
|
||||
|
||||
- ID: ice40_generic
|
||||
Description: icestick
|
||||
|
|
@ -751,6 +758,13 @@
|
|||
Memory: OK
|
||||
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
|
||||
Description: SeeedStudio Spartan Edge Accelerator Board
|
||||
URL: http://wiki.seeedstudio.com/Spartan-Edge-Accelerator-Board
|
||||
|
|
@ -855,6 +869,13 @@
|
|||
Memory: OK
|
||||
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
|
||||
Description: Efinix Trion T20 BGA256 Dev Kit
|
||||
URL: https://www.efinixinc.com/products-devkits-triont20.html
|
||||
|
|
@ -904,10 +925,10 @@
|
|||
Memory: OK
|
||||
Flash: OK
|
||||
Constraints:
|
||||
- ULX3S-12F
|
||||
- ULX3S-25F
|
||||
- ULX3S-45F
|
||||
- ULX3S-85F
|
||||
- ULX3S-12F
|
||||
- ULX3S-25F
|
||||
- ULX3S-45F
|
||||
- ULX3S-85F
|
||||
|
||||
- ID: ulx3s_dfu
|
||||
Description: Radiona ULX3S DFU mode
|
||||
|
|
|
|||
150
doc/cable.yml
150
doc/cable.yml
|
|
@ -33,6 +33,13 @@ bus_blaster_b:
|
|||
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:
|
||||
|
||||
- Name: ch347 JTAG adapter
|
||||
|
|
@ -54,33 +61,6 @@ cmsisdap:
|
|||
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:
|
||||
|
||||
- Name: DFU interface
|
||||
|
|
@ -94,7 +74,7 @@ digilent:
|
|||
Description: FT2232 JTAG / UART cable
|
||||
|
||||
|
||||
diglent_b:
|
||||
digilent_b:
|
||||
|
||||
- Name: digilent cable
|
||||
Description: digilent FT2232 JTAG / UART cable (interface B)
|
||||
|
|
@ -108,12 +88,14 @@ digilent_hs2:
|
|||
|
||||
|
||||
digilent_hs3:
|
||||
|
||||
- Name: digilent hs3
|
||||
Description: JTAG programmer cable from digilent
|
||||
URL: https://digilent.com/shop/jtag-hs3-programming-cable/
|
||||
|
||||
|
||||
dirtyJtag:
|
||||
|
||||
- Name: dirty Jtag
|
||||
Description: JTAG probe firmware for STM32F1
|
||||
URL: https://github.com/jeanthom/DirtyJTAG
|
||||
|
|
@ -121,16 +103,17 @@ dirtyJtag:
|
|||
New version `dirtyjtag2 <https://github.com/jeanthom/DirtyJTAG/tree/dirtyjtag2>`__ is also supported
|
||||
|
||||
|
||||
efinix_spi_ft4232:
|
||||
ecpix5-debug:
|
||||
|
||||
- Name: efinix SPI (ft4232)
|
||||
Description: efinix SPI interface (FTDI4232 interface A)
|
||||
- Name: ecpix5-debug
|
||||
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)
|
||||
Description: efinix JTAG interface (FTDI4232 interface B)
|
||||
- Name: efinix JTAG (ft2232)
|
||||
Description: efinix JTAG interface (FTDI2232 interface B)
|
||||
|
||||
|
||||
efinix_spi_ft2232:
|
||||
|
|
@ -139,10 +122,16 @@ efinix_spi_ft2232:
|
|||
Description: efinix SPI interface (FTDI2232 interface A)
|
||||
|
||||
|
||||
efinix_jtag_ft2232:
|
||||
efinix_jtag_ft4232:
|
||||
|
||||
- Name: efinix JTAG (ft2232)
|
||||
Description: efinix JTAG interface (FTDI2232 interface B)
|
||||
- Name: efinix JTAG (ft4232)
|
||||
Description: efinix JTAG interface (FTDI4232 interface B)
|
||||
|
||||
|
||||
efinix_spi_ft4232:
|
||||
|
||||
- Name: efinix SPI (ft4232)
|
||||
Description: efinix SPI interface (FTDI4232 interface A)
|
||||
|
||||
|
||||
ft2232:
|
||||
|
|
@ -196,23 +185,54 @@ ft4232:
|
|||
Description: quad interface programmer cable. MPSSE capable.
|
||||
URL: https://ftdichip.com/products/ft4232h-56q/
|
||||
|
||||
|
||||
ft4232hp:
|
||||
|
||||
- Name: FT4232HP (interface A)
|
||||
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
|
||||
|
||||
|
||||
ft4232hp_b:
|
||||
|
||||
- Name: FT4232HP (interface B)
|
||||
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
|
||||
|
||||
ecpix5-debug:
|
||||
|
||||
- Name: ecpix5-debug
|
||||
Description: LambdaConcept ECPIX5 (45k/85k) UART/JTAG interface
|
||||
URL: https://shop.lambdaconcept.com/home/46-ecpix-5.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/
|
||||
|
||||
|
||||
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:
|
||||
|
|
@ -235,6 +255,13 @@ jtag-smt2-nc:
|
|||
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:
|
||||
|
||||
- Name: lpc-link2
|
||||
|
|
@ -247,6 +274,7 @@ numato:
|
|||
- Name: numato
|
||||
Description: Embedded cable for Numato Systems Mimas-A7 board
|
||||
|
||||
|
||||
orbtrace:
|
||||
|
||||
- Name: orbtrace interface
|
||||
|
|
@ -261,13 +289,6 @@ papilio:
|
|||
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:
|
||||
|
||||
- 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
|
||||
|
||||
|
||||
steppenprobe:
|
||||
|
||||
- Name: steppenprobe
|
||||
Description: Open Source Hardware JTAG/SWD/UART/SWO interface board based on FTDI FT2232H
|
||||
URL: https://github.com/diegoherranz/steppenprobe
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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:
|
||||
|
||||
- Name: Xilinx Virtual Cable
|
||||
|
|
@ -314,22 +349,3 @@ xvc-server:
|
|||
- Name: Xilinx Virtual Cable (server side)
|
||||
Description: Xilinx Virtual Cable (XVC) is a TCP/IP-based protocol that acts like a JTAG cable.
|
||||
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
|
||||
* Honeycomb
|
||||
* 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.
|
||||
|
||||
|
|
@ -37,12 +38,13 @@ where ``BOARD_NAME`` is:
|
|||
* ``tangnano20k``
|
||||
* ``tangprimer20k``
|
||||
* ``runber``
|
||||
* ``brs-100-gw1nr9``
|
||||
|
||||
Flash
|
||||
-----
|
||||
|
||||
.. ATTENTION::
|
||||
Only with Trenz TEC0117 and runber.
|
||||
Only with Trenz TEC0117, runber and brs-100-gw1nr9.
|
||||
|
||||
with ``-f``, file load:
|
||||
|
||||
|
|
@ -54,6 +56,7 @@ where ``BOARD_NAME`` is:
|
|||
|
||||
* ``tec0117``
|
||||
* ``runber``
|
||||
* ``brs-100-gw1nr9``
|
||||
|
||||
It's possible to flash external SPI Flash (connected to MSPI) in bscan mode by using ``--external-flash`` instead of
|
||||
``-f``.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ url="https://github.com/trabucayre/openFPGALoader"
|
|||
license=('Apache-2.0')
|
||||
depends=(
|
||||
"${MINGW_PACKAGE_PREFIX}-libftdi"
|
||||
"${MINGW_PACKAGE_PREFIX}-hidapi"
|
||||
"${MINGW_PACKAGE_PREFIX}-zlib"
|
||||
)
|
||||
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("spec45", "xc6slx45tfgg484", "", 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("tangconsole", "", "ft2232", 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("tec0117", "", "ft2232", SPI_FLASH, 0, 0, CABLE_DEFAULT),
|
||||
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",
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ enum communication_type {
|
|||
MODE_CH347, /*! CH347 JTAG mode */
|
||||
MODE_GWU2X, /*! Gowin GWU2X JTAG mode */
|
||||
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 )},
|
||||
{"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_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_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)},
|
||||
|
|
@ -136,6 +138,7 @@ static std::map <std::string, cable_t> cable_list = {
|
|||
{"usb-blasterII", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6810 )},
|
||||
{"usb-blasterII_1", CABLE_DEF(MODE_USBBLASTER, 0x09Fb, 0x6010 )},
|
||||
{"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 )},
|
||||
#ifdef ENABLE_LIBGPIOD
|
||||
{"libgpiod", CABLE_DEF(MODE_LIBGPIOD_BITBANG, 0, 0x0000 )},
|
||||
|
|
|
|||
|
|
@ -218,10 +218,13 @@ void Efinix::program(unsigned int offset, bool unprotect_flash)
|
|||
throw std::runtime_error("device mismatch: " + device + " != " + target);
|
||||
}
|
||||
}
|
||||
std::string mode = bit->getHeaderVal("mode");
|
||||
if (mode.find("passive") != std::string::npos) {
|
||||
delete bit;
|
||||
throw std::runtime_error("passive mode not supported for flash");
|
||||
std::map<std::string, std::string> hdr = bit->getHeader();
|
||||
if(hdr.find("mode") != hdr.end()) {
|
||||
std::string mode = bit->getHeaderVal("mode");
|
||||
if (mode.find("passive") != std::string::npos) {
|
||||
delete bit;
|
||||
throw std::runtime_error("passive mode not supported for flash");
|
||||
}
|
||||
}
|
||||
} catch (std::runtime_error& e) {
|
||||
throw;
|
||||
|
|
|
|||
|
|
@ -245,13 +245,17 @@ static uint16_t esp_usb_target_chip_id = 0; /* not applicable for FPGA, they hav
|
|||
|
||||
/* 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),
|
||||
dev_handle(NULL), usb_ctx(NULL), _tdi(0), _tms(0),
|
||||
/* Default for emard firmware. */
|
||||
_esp_usb_jtag_caps(0x2000), _write_ep(0x02),
|
||||
_vid(ESPUSBJTAG_VID), _pid(ESPUSBJTAG_PID)
|
||||
{
|
||||
libusb_device **devs = NULL;
|
||||
int ret;
|
||||
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();
|
||||
}
|
||||
|
||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||
_vid, _pid);
|
||||
if (!dev_handle) {
|
||||
_esp_usb_jtag_caps = 0x030A;
|
||||
_write_ep = 0x03;
|
||||
_pid = 0x1002;
|
||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||
_vid, _pid);
|
||||
ssize_t cnt = libusb_get_device_list(usb_ctx, &devs);
|
||||
if (cnt < 0) {
|
||||
std::cerr << "esp_usb_jtag: libusb_get_device_list failed: "
|
||||
<< libusb_error_name(static_cast<int>(cnt)) << std::endl;
|
||||
libusb_exit(usb_ctx);
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
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) {
|
||||
snprintf(mess, 256, "fails to open esp_usb_jtag device");
|
||||
printError(mess);
|
||||
std::cerr << "fails to open esp_usb_jtag device vid:pid 0x"
|
||||
<< 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);
|
||||
throw std::exception();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "jtagInterface.hpp"
|
||||
|
||||
/*!
|
||||
|
|
@ -23,7 +25,9 @@
|
|||
|
||||
class esp_usb_jtag : public JtagInterface {
|
||||
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();
|
||||
|
||||
int setClkFreq(uint32_t clkHZ) override;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include "display.hpp"
|
||||
#include "fx2_ll.hpp"
|
||||
#include "ihexParser.hpp"
|
||||
|
||||
#include "progressBar.hpp"
|
||||
|
||||
#define FX2_FIRM_LOAD 0xA0
|
||||
#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");
|
||||
}
|
||||
/* 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();
|
||||
reenum = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
ProgressBar progress("Waiting reload", 100, 50, false);
|
||||
int timeout = 100;
|
||||
do {
|
||||
dev_handle = libusb_open_device_with_vid_pid(usb_ctx,
|
||||
vid, pid);
|
||||
timeout--;
|
||||
progress.display(100-timeout);
|
||||
if (!dev_handle)
|
||||
sleep(1);
|
||||
} while (!dev_handle && timeout > 0 && reenum);
|
||||
|
||||
if (!dev_handle)
|
||||
if (!dev_handle) {
|
||||
progress.fail();
|
||||
throw std::runtime_error("FX2: fail to open device");
|
||||
}
|
||||
progress.done();
|
||||
|
||||
ret = libusb_claim_interface(dev_handle, 0);
|
||||
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
|
||||
* destroy context
|
||||
*/
|
||||
|
|
@ -134,11 +155,11 @@ int FX2_ll::read(uint8_t endpoint, uint8_t *buff, uint16_t len)
|
|||
/* write len data using control
|
||||
*/
|
||||
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,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
|
||||
bRequest, wValue, 0x0000, buff, len, 100);
|
||||
bRequest, wValue, wIndex, buff, len, 100);
|
||||
if (ret < 0) {
|
||||
printError("Unable to send control request: "
|
||||
+ 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
|
||||
*/
|
||||
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,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
|
||||
bRequest, wValue, 0x0000, buff, len, 100);
|
||||
bRequest, wValue, wIndex, buff, len, 100);
|
||||
if (ret < 0) {
|
||||
printError("Unable to read control request: "
|
||||
+ std::string(libusb_error_name(ret)));
|
||||
|
|
@ -177,6 +198,7 @@ bool FX2_ll::load_firmware(std::string firmware_path)
|
|||
return false;
|
||||
/* load */
|
||||
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++) {
|
||||
IhexParser::data_line_t data_line = data[i];
|
||||
|
||||
|
|
@ -186,14 +208,16 @@ bool FX2_ll::load_firmware(std::string firmware_path)
|
|||
while (toSend > 0) {
|
||||
uint16_t xfer_len = (toSend > 64) ? 64: toSend;
|
||||
if (!write_ctrl(FX2_FIRM_LOAD, addr, tx_buff, xfer_len)) {
|
||||
printError("load firmware failed\n");
|
||||
progress.fail();
|
||||
return false;
|
||||
}
|
||||
toSend -= xfer_len;
|
||||
tx_buff += xfer_len;
|
||||
addr += xfer_len;
|
||||
}
|
||||
progress.display(i);
|
||||
}
|
||||
progress.done();
|
||||
|
||||
/* unset reset */
|
||||
if (!reset(0))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// 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_
|
||||
|
|
@ -31,6 +31,14 @@ class FX2_ll {
|
|||
uint16_t vid, uint16_t pid, const std::string &firmware_path);
|
||||
~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
|
||||
* \param[in] endpoint: endpoint to use
|
||||
|
|
@ -53,20 +61,22 @@ class FX2_ll {
|
|||
* \param[in] wValue
|
||||
* \param[in] buff: buffer to write
|
||||
* \param[in] len: buffer length
|
||||
* \param[in] wIndex: the index field for the setup packet
|
||||
* \return false when transfer fails, true otherwise
|
||||
*/
|
||||
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
|
||||
* \param[in] bRequest
|
||||
* \param[in] wValue
|
||||
* \param[in] buff: buffer to write
|
||||
* \param[in] len: buffer length
|
||||
* \param[in] wIndex: the index field for the setup packet
|
||||
* \return false when transfer fails, true otherwise
|
||||
*/
|
||||
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:
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ void Gowin::checkCRC()
|
|||
* is used, try to compare with this value
|
||||
*/
|
||||
try {
|
||||
std::string hdr = _fs->getHeaderVal("checkSum");
|
||||
std::string hdr = _fs->getHeaderVal("CheckSum");
|
||||
if (!hdr.empty()) {
|
||||
if (ucode == strtol(hdr.c_str(), NULL, 16))
|
||||
goto success;
|
||||
|
|
|
|||
15
src/jtag.cpp
15
src/jtag.cpp
|
|
@ -58,6 +58,9 @@
|
|||
#ifdef ENABLE_XVC_CLIENT
|
||||
#include "xvc_client.hpp"
|
||||
#endif
|
||||
#ifdef ENABLE_XILINX_PLATFORM_CABLE_USB
|
||||
#include "xilinxPlatformCableUSB.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#define DEBUG 0
|
||||
|
|
@ -162,7 +165,8 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
|
|||
break;
|
||||
case MODE_ESP:
|
||||
#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
|
||||
std::cerr << "Jtag: support for esp32s3 cable was not enabled at compile time" << std::endl;
|
||||
throw std::exception();
|
||||
|
|
@ -206,6 +210,15 @@ Jtag::Jtag(const cable_t &cable, const jtag_pins_conf_t *pin_conf,
|
|||
case MODE_REMOTEBITBANG:
|
||||
_jtag = new RemoteBitbang_client(ip_adr, port, verbose);
|
||||
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
|
||||
default:
|
||||
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 device;
|
||||
std::string cable;
|
||||
std::string ftdi_serial;
|
||||
std::string usb_serial_num;
|
||||
int ftdi_channel;
|
||||
int status_pin;
|
||||
uint32_t freq;
|
||||
|
|
@ -264,13 +264,6 @@ int main(int argc, char **argv)
|
|||
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 (cable.type != MODE_FTDI_SERIAL){
|
||||
printError("Error: FTDI status pin is for FTDI MPSSE cables.");
|
||||
|
|
@ -279,6 +272,14 @@ int main(int argc, char **argv)
|
|||
}
|
||||
#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) {
|
||||
printInfo("Cable VID overridden");
|
||||
cable.vid = args.vid;
|
||||
|
|
@ -389,7 +390,7 @@ int main(int argc, char **argv)
|
|||
|
||||
Jtag *jtag;
|
||||
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.invert_read_edge, args.probe_firmware,
|
||||
args.user_misc_devs);
|
||||
|
|
@ -667,7 +668,7 @@ int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
|||
try {
|
||||
XVC_server *xvc = NULL;
|
||||
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);
|
||||
/* create connection */
|
||||
xvc->open_connection();
|
||||
|
|
@ -889,6 +890,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
|||
jtag_pins_conf_t *pins_config)
|
||||
{
|
||||
std::string freqo;
|
||||
std::string ftdi_serial;
|
||||
std::vector<std::string> pins, bus_dev_num;
|
||||
bool verbose = false, quiet = false;
|
||||
int8_t verbose_level = -2;
|
||||
|
|
@ -927,8 +929,10 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
|||
("busdev-num",
|
||||
"select a probe by it bus and device number (bus_num:device_addr)",
|
||||
cxxopts::value<std::vector<std::string>>(bus_dev_num))
|
||||
("ftdi-serial", "FTDI chip serial number",
|
||||
cxxopts::value<std::string>(args->ftdi_serial))
|
||||
("usb-serial-num", "USB iSerial (FTDI chip serial number or ESP32 iSerialNumber substring)",
|
||||
cxxopts::value<std::string>(args->usb_serial_num))
|
||||
("ftdi-serial", "FTDI chip serial number (Deprecated)",
|
||||
cxxopts::value<std::string>(ftdi_serial))
|
||||
("ftdi-channel",
|
||||
"FTDI chip channel number (channels 0-3 map to A-D)",
|
||||
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))
|
||||
("pins", "pin config TDI:TDO:TCK:TMS or MOSI:MISO:SCK:CS[:HOLDN:WPN]",
|
||||
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))
|
||||
("protect-flash", "protect SPI flash area",
|
||||
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))
|
||||
("user-flash", "User flash file (Gowin LittleBee FPGA only)",
|
||||
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"});
|
||||
auto result = options.parse(argc, argv);
|
||||
|
|
@ -1055,7 +1060,7 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
|||
args->verbose = verbose_level;
|
||||
}
|
||||
|
||||
if (result.count("Version")) {
|
||||
if (result.count("Version") || result.count("version")) {
|
||||
std::cout << "openFPGALoader " << VERSION << std::endl;
|
||||
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 (bus_dev_num.size() != 2) {
|
||||
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}},
|
||||
|
||||
/* Altera Agilex 3 */
|
||||
{0x4361b0dd, {"altera", "agilex 3", "A3CY100", 10}},
|
||||
{0x436db0dd, {"altera", "agilex 3", "A3CZ135", 10}},
|
||||
|
||||
/* Altera Agilex 5 */
|
||||
|
|
|
|||
|
|
@ -76,25 +76,27 @@ RemoteBitbang_client::~RemoteBitbang_client()
|
|||
}
|
||||
|
||||
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
|
||||
// if asked flush
|
||||
if (len == 0)
|
||||
return ((flush_buffer) ? flush() : 0);
|
||||
|
||||
_last_tdi = (tdi) ? TDI_BIT : 0;
|
||||
|
||||
uint8_t base_v = '0' + _last_tdi;
|
||||
for (uint32_t pos = 0; pos < len; pos++) {
|
||||
// buffer full -> write
|
||||
if (_num_bytes == _buffer_size)
|
||||
ll_write(NULL);
|
||||
if ((_num_bytes + 2) >= _buffer_size)
|
||||
flush();
|
||||
_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 + TCK_BIT;
|
||||
}
|
||||
|
||||
// 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 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;
|
||||
for (uint32_t pos = 0; pos < len; pos++) {
|
||||
if (_num_bytes == _buffer_size)
|
||||
ll_write(NULL); // NULL because _num_bytes is always 0 when read
|
||||
_last_tdi = (tx[pos >> 3] & (1 << (pos & 0x07))) ? TDI_BIT : 0;
|
||||
const uint32_t pos_byte = (pos >> 3);
|
||||
const uint32_t pos_bit = (1 << (pos & 0x07));
|
||||
if ((_num_bytes + 2) >= _buffer_size)
|
||||
flush();
|
||||
_last_tdi = (tx[pos_byte] & pos_bit) ? TDI_BIT : 0;
|
||||
if (end && pos == len - 1) {
|
||||
_last_tms = TMS_BIT;
|
||||
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;
|
||||
ll_write(&tdo);
|
||||
if (tdo == '1')
|
||||
rx[pos >> 3] |= (1 << (pos & 0x07));
|
||||
rx[pos_byte] |= pos_bit;
|
||||
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.
|
||||
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
|
||||
if (clk_len == 0)
|
||||
return 0;
|
||||
if (_num_bytes != 0)
|
||||
flush();
|
||||
|
||||
_last_tms = tms;
|
||||
_last_tdi = tdi;
|
||||
uint8_t val = (_last_tms | _last_tdi);
|
||||
|
||||
// flush buffer before starting
|
||||
if (_num_bytes != 0)
|
||||
flush();
|
||||
const uint8_t val = (_last_tms | _last_tdi);
|
||||
|
||||
for (uint32_t len = 0; len < clk_len; len++) {
|
||||
if (len == _num_bytes)
|
||||
ll_write(NULL);
|
||||
if ((_num_bytes + 2) >= _buffer_size)
|
||||
flush();
|
||||
_xfer_buf[_num_bytes++] = '0' + val;
|
||||
_xfer_buf[_num_bytes++] = '0' + (val | TCK_BIT);
|
||||
}
|
||||
|
||||
ll_write(NULL);
|
||||
flush();
|
||||
|
||||
return clk_len;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ UsbBlaster::UsbBlaster(const cable_t &cable, const std::string &firmware_path,
|
|||
#else
|
||||
throw std::runtime_error("usb-blasterI: Not build");
|
||||
#endif
|
||||
#ifdef ENABLE_USB_BLASTERII
|
||||
else if (cable.pid == 0x6810 || cable.pid == 0x6010)
|
||||
#ifdef ENABLE_USB_BLASTERII
|
||||
ll_driver = new UsbBlasterII(firmware_path);
|
||||
#else
|
||||
throw std::runtime_error("usb-blasterII: Not build");
|
||||
|
|
@ -459,7 +459,7 @@ UsbBlasterII::UsbBlasterII(const std::string &firmware_path)
|
|||
else
|
||||
fpath = firmware_path;
|
||||
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.");
|
||||
}
|
||||
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 */
|
||||
if (_is_bpi_board) {
|
||||
program_bpi(bit, offset);
|
||||
reset();
|
||||
} else {
|
||||
if (_flash_chips & 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);
|
||||
program_spi(secondary_bit, _secondary_file_extension, offset, unprotect_flash);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
} else {
|
||||
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");
|
||||
}
|
||||
|
||||
/* Reset the board if skip_reset is not set */
|
||||
post_flash_access();
|
||||
|
||||
printInfo("BPI flash programming complete");
|
||||
}
|
||||
|
||||
|
|
@ -1277,6 +1277,18 @@ bool Xilinx::dumpFlash(uint32_t base_addr, uint32_t len)
|
|||
|
||||
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) {
|
||||
select_flash_chip(PRIMARY_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