├── .github └── workflows │ ├── cmake.yml │ └── codeql-analysis.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── CMakeSettings.json ├── LICENSE ├── README.md ├── cmake ├── Toolchain-cross-mingw32.cmake └── Toolchain-cross-mingw64.cmake ├── ftd2xx-amd64.lib ├── ftd2xx.h ├── ftd2xx.lib ├── fujprog.c ├── fujprog.h.in ├── getopt.c ├── getopt.h ├── images ├── ULX3S-as-FTDI-device.PNG ├── ULX3S-as-libusbK-device.PNG ├── Uninstall-libusbK-device-step2.PNG ├── Uninstall-libusbK-device.PNG ├── Zadig-FTDI-to-libusbK.PNG ├── Zadig-success.PNG └── securityblock.png └── ulx2s_prep.sh /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push] 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: Release 8 | 9 | jobs: 10 | build: 11 | # The CMake configure and build commands are platform agnostic and should work equally 12 | # well on Windows or Mac. You can convert this to a matrix build if you need 13 | # cross-platform coverage. 14 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Install prereqs 21 | # Some projects don't allow in-source building, so create a separate build directory 22 | # We'll use this as our working directory for all subsequent commands 23 | run: sudo apt-get install --yes libftdi1-dev libusb-dev cmake make build-essential 24 | 25 | - name: Create Build Environment 26 | # Some projects don't allow in-source building, so create a separate build directory 27 | # We'll use this as our working directory for all subsequent commands 28 | run: cmake -E make_directory ${{runner.workspace}}/build 29 | 30 | - name: Configure CMake 31 | # Use a bash shell so we can use the same syntax for environment variable 32 | # access regardless of the host operating system 33 | shell: bash 34 | working-directory: ${{runner.workspace}}/build 35 | # Note the current convention is to use the -S and -B options here to specify source 36 | # and build directories, but this is only available with CMake 3.13 and higher. 37 | # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 38 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE 39 | 40 | - name: Build 41 | working-directory: ${{runner.workspace}}/build 42 | shell: bash 43 | # Execute the build. You can specify a specific target with "--target " 44 | run: cmake --build . --config $BUILD_TYPE 45 | 46 | - name: Test 47 | working-directory: ${{runner.workspace}}/build 48 | shell: bash 49 | # Execute tests defined by the CMake configuration. 50 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 51 | run: ctest -C $BUILD_TYPE 52 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # ******** NOTE ******** 12 | 13 | name: "CodeQL" 14 | 15 | on: 16 | push: 17 | branches: [ master ] 18 | pull_request: 19 | # The branches below must be a subset of the branches above 20 | branches: [ master ] 21 | schedule: 22 | - cron: '20 1 * * 3' 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | language: [ 'cpp' ] 33 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 34 | # Learn more... 35 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection 36 | 37 | steps: 38 | - name: Install prereqs 39 | # Some projects don't allow in-source building, so create a separate build directory 40 | # We'll use this as our working directory for all subsequent commands 41 | run: sudo apt-get install --yes libftdi1-dev libusb-dev cmake make build-essential 42 | 43 | - name: Checkout repository 44 | uses: actions/checkout@v2 45 | 46 | # Initializes the CodeQL tools for scanning. 47 | - name: Initialize CodeQL 48 | uses: github/codeql-action/init@v1 49 | with: 50 | languages: ${{ matrix.language }} 51 | # If you wish to specify custom queries, you can do so here or in a config file. 52 | # By default, queries listed here will override any specified in a config file. 53 | # Prefix the list here with "+" to use these queries and those in the config file. 54 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v1 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 https://git.io/JvXDl 63 | 64 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 65 | # and modify them (or add more) to build your code if your project 66 | # uses a compiled language 67 | 68 | #- run: | 69 | # make bootstrap 70 | # make release 71 | 72 | - name: Perform CodeQL Analysis 73 | uses: github/codeql-action/analyze@v1 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | /.vs 54 | /out/build 55 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | matrix: 4 | include: 5 | - os: linux 6 | env: PLATFORM="linux-gcc" CMakeArgs="" ARCH=x86_64 7 | compiler: gcc 8 | arch: amd64 9 | - os: linux 10 | env: PLATFORM="linux-clang" CMakeArgs="" ARCH=x86_64 11 | compiler: clang 12 | arch: amd64 13 | - os: linux 14 | env: PLATFORM="linux-gcc" CMakeArgs="" ARCH=i386 15 | compiler: gcc 16 | arch: amd64 17 | - os: linux 18 | env: PLATFORM="linux-clang" CMakeArgs="" ARCH=i386 19 | compiler: clang 20 | arch: amd64 21 | - os: osx 22 | env: PLATFORM="osx-gcc" CMakeArgs="" 23 | compiler: gcc 24 | - os: osx 25 | env: PLATFORM="osx-clang" CMakeArgs="" 26 | compiler: clang 27 | - os: linux 28 | env: PLATFORM="win-mingw-x86" CMakeArgs="-D CMAKE_SYSTEM_NAME=Windows -D CMAKE_C_COMPILER=x86_64-w64-mingw32-gcc-posix -D CMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++-posix" ARCH="i386" 29 | compiler: gcc 30 | - os: linux 31 | env: PLATFORM="win-mingw-x64" CMakeArgs="-D CMAKE_SYSTEM_NAME=Windows -D CMAKE_C_COMPILER=i686-w64-mingw32-gcc-posix -D CMAKE_CXX_COMPILER=i686-w64-mingw32-g++-posix" ARCH="x86_64" 32 | compiler: gcc 33 | 34 | before_install: 35 | - wget https://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.4.tar.bz2 36 | - tar -xjf libftdi1-1.4.tar.bz2 37 | 38 | install: 39 | - cd libftdi1-1.4 40 | - if [ "$TRAVIS_OS_NAME" = "linux" ]; 41 | then 42 | sudo apt-get update -qq; 43 | if [ "$ARCH" = "x86_64" ]; 44 | then 45 | sudo apt-get install -qq libusb-1.0-0-dev; 46 | elif [ "$ARCH" = "i386" ]; 47 | then 48 | sudo apt-get install -qq gcc-multilib libusb-1.0-0-dev:i386 pkg-config:i386; 49 | export CFLAGS="-m32"; 50 | fi 51 | fi 52 | - if [ "$TRAVIS_OS_NAME" = "osx" ]; 53 | then 54 | brew update; 55 | brew install libusb; 56 | fi 57 | - mkdir build 58 | - cd build 59 | - cmake ../ 60 | - make 61 | - sudo make install 62 | - cd ../../ 63 | - if [ $TRAVIS_OS_NAME = linux ] && [ -n "$CMakeArgs" ]; then unset CXX; unset CC; sudo apt-get install gcc-mingw-w64-i686 gcc-mingw-w64-x86-64 g++-mingw-w64-i686 g++-mingw-w64-x86-64; fi 64 | 65 | script: 66 | - mkdir build 67 | - cd build 68 | - if [ $TRAVIS_OS_NAME = linux ] && [ -n "$CMakeArgs" ]; 69 | then 70 | if [ "$ARCH" = "x86_64" ]; 71 | then 72 | cp -f ../ftd2xx-amd64.lib ../ftd2xx.lib; 73 | cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cmake/Toolchain-cross-mingw64.cmake ../; 74 | elif [ "$ARCH" = "i386" ]; 75 | then 76 | cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cmake/Toolchain-cross-mingw32.cmake ../; 77 | fi 78 | elif [ "$TRAVIS_OS_NAME" = "osx" ]; 79 | then 80 | cmake -DBUILD_STATICLIB=ON ../; 81 | else 82 | cmake ../; 83 | fi 84 | - make 85 | - sudo make install/strip 86 | - if [ $TRAVIS_OS_NAME = linux ] && [ ! -n "$CMakeArgs" ]; then LD_LIBRARY_PATH=/usr/local/lib /usr/local/bin/fujprog -h; fi 87 | - if [ $TRAVIS_OS_NAME = osx ]; then /usr/local/bin/fujprog -h; fi 88 | 89 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | # set the project name and version 4 | project(fujprog VERSION 4.8) 5 | 6 | # control where the static and shared libraries are built so that on windows 7 | # we don't need to tinker with the path to run the executable 8 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 9 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 10 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") 11 | 12 | option(BUILD_STATIC "Build completely static binary" OFF) 13 | option(BUILD_STATICLIB "Build binary with non default static binaries" OFF) 14 | 15 | if (BUILD_STATIC) 16 | set(CMAKE_EXE_LINKER_FLAGS "-static") 17 | set(BUILD_SHARED_LIBS OFF) 18 | endif() 19 | 20 | if (BUILD_STATICLIB) 21 | find_library(LIBFTDISTATIC libftdi1.a REQUIRED) 22 | find_library(LIBUSBSTATIC libusb-1.0.a REQUIRED) 23 | endif() 24 | 25 | if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 26 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreFoundation -framework IOKit") 27 | endif() 28 | 29 | 30 | 31 | set(FUJPROG_HEADERS 32 | fujprog.h 33 | ) 34 | 35 | set(FUJPROG_SOURCE 36 | fujprog.c 37 | ) 38 | 39 | if (MSVC) 40 | set(FUJPROG_SOURCE "${FUJPROG_SOURCE}" "getopt.c") 41 | add_compile_options( 42 | $<$:/MT> #---------| 43 | $<$:/MTd> #---|-- Statically link the runtime libraries 44 | $<$:/MT> #--| 45 | ) 46 | else() 47 | find_package(PkgConfig REQUIRED) 48 | pkg_check_modules(LIBFTDI REQUIRED libftdi1) 49 | pkg_check_modules(LIBUSB REQUIRED libusb-1.0) 50 | link_directories(${LIBUSB_LIBRARY_DIRS} ${LIBFTDI_LIBRARY_DIRS}) 51 | endif() 52 | 53 | set(fujprog_git_version "unknown") 54 | 55 | find_package(Git) 56 | if(GIT_FOUND) 57 | execute_process( 58 | COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 59 | WORKING_DIRECTORY "${local_dir}" 60 | OUTPUT_VARIABLE fujprog_git_version 61 | ERROR_QUIET 62 | OUTPUT_STRIP_TRAILING_WHITESPACE 63 | ) 64 | message( STATUS "GIT hash: ${fujprog_git_version}") 65 | else() 66 | message(STATUS "GIT not found") 67 | endif() 68 | 69 | string(TIMESTAMP _time_stamp) 70 | 71 | add_executable(fujprog 72 | ${FUJPROG_SOURCE} 73 | ${FUJPROG_HEADERS} 74 | ) 75 | 76 | if (WIN32) 77 | link_directories(${PROJECT_SOURCE_DIR}) 78 | add_definitions(-DFTD2XX_STATIC=1) 79 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") 80 | find_library(LIBFTDISTATIC ftd2xx.lib PATHS ${CMAKE_CURRENT_SOURCE_DIR} REQUIRED) 81 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 82 | target_link_libraries(fujprog PUBLIC ${LIBFTDISTATIC}) 83 | else() 84 | if (BUILD_STATICLIB) 85 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 86 | set_target_properties(fujprog PROPERTIES LINK_SEARCH_START_STATIC 1) 87 | set_target_properties(fujprog PROPERTIES LINK_SEARCH_END_STATIC 1) 88 | target_link_libraries(fujprog PUBLIC ${LIBFTDISTATIC} ${LIBUSBSTATIC}) 89 | else() 90 | target_link_libraries(fujprog 91 | ${LIBUSB_LIBRARIES} 92 | ${LIBFTDI_LIBRARIES} 93 | ) 94 | endif() 95 | endif() 96 | 97 | # configure a header file to pass the version number only 98 | configure_file(fujprog.h.in fujprog.h) 99 | 100 | include_directories( 101 | ${LIBUSB_INCLUDE_DIRS} 102 | ${LIBFTDI_INCLUDE_DIRS} 103 | ${CMAKE_CURRENT_BINARY_DIR} 104 | ) 105 | 106 | 107 | if (BUILD_STATIC) 108 | set_target_properties(fujprog PROPERTIES LINK_SEARCH_END_STATIC 1) 109 | endif() 110 | 111 | # install 112 | install(TARGETS fujprog DESTINATION bin) 113 | 114 | -------------------------------------------------------------------------------- /CMakeSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "x64-Debug", 5 | "generator": "Ninja", 6 | "configurationType": "Debug", 7 | "inheritEnvironments": [ "msvc_x64_x64" ], 8 | "buildRoot": "${projectDir}\\out\\build\\${name}", 9 | "installRoot": "${projectDir}\\out\\install\\${name}", 10 | "cmakeCommandArgs": "", 11 | "buildCommandArgs": "-v", 12 | "ctestCommandArgs": "", 13 | "variables": [ 14 | { 15 | "name": "LIBFTDISTATIC", 16 | "value": "C:/ftdi/Static/amd64/ftd2xx.lib", 17 | "type": "FILEPATH" 18 | } 19 | ] 20 | }, 21 | { 22 | "name": "x64-Release", 23 | "generator": "Ninja", 24 | "configurationType": "RelWithDebInfo", 25 | "buildRoot": "${projectDir}\\out\\build\\${name}", 26 | "installRoot": "${projectDir}\\out\\install\\${name}", 27 | "cmakeCommandArgs": "", 28 | "buildCommandArgs": "-v", 29 | "ctestCommandArgs": "", 30 | "inheritEnvironments": [ "msvc_x64_x64" ], 31 | "variables": [ 32 | { 33 | "name": "LIBFTDISTATIC", 34 | "value": "C:/ftdi/Static/amd64/ftd2xx.lib", 35 | "type": "FILEPATH" 36 | }, 37 | { 38 | "name": "CMAKE_BUILD_TYPE", 39 | "value": "Release", 40 | "type": "STRING" 41 | } 42 | ] 43 | }, 44 | { 45 | "name": "x86-Release", 46 | "generator": "Ninja", 47 | "configurationType": "RelWithDebInfo", 48 | "buildRoot": "${projectDir}\\out\\build\\${name}", 49 | "installRoot": "${projectDir}\\out\\install\\${name}", 50 | "cmakeCommandArgs": "", 51 | "buildCommandArgs": "-v", 52 | "ctestCommandArgs": "", 53 | "inheritEnvironments": [ "msvc_x86" ], 54 | "variables": [ 55 | { 56 | "name": "LIBFTDISTATIC", 57 | "value": "C:/ftdi/Static/i386/ftd2xx.lib", 58 | "type": "FILEPATH" 59 | }, 60 | { 61 | "name": "CMAKE_BUILD_TYPE", 62 | "value": "Release", 63 | "type": "STRING" 64 | } 65 | ] 66 | }, 67 | { 68 | "name": "x86-Debug", 69 | "generator": "Ninja", 70 | "configurationType": "Debug", 71 | "buildRoot": "${projectDir}\\out\\build\\${name}", 72 | "installRoot": "${projectDir}\\out\\install\\${name}", 73 | "cmakeCommandArgs": "", 74 | "buildCommandArgs": "-v", 75 | "ctestCommandArgs": "", 76 | "inheritEnvironments": [ "msvc_x86" ], 77 | "variables": [ 78 | { 79 | "name": "LIBFTDISTATIC", 80 | "value": "C:/ftdi/Static/i386/ftd2xx.lib", 81 | "type": "FILEPATH" 82 | } 83 | ] 84 | } 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2008-2018 Marko Zec, University of Zagreb 4 | Copyright (c) 2014-2019 EMARD 5 | Copyright (c) 2020, kost 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright notice, 15 | this list of conditions and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis (.org)](https://img.shields.io/travis/kost/fujprog)](https://travis-ci.org/kost/fujprog "Travis CI") 2 | 3 | # ULX2S / ULX3S JTAG programmer 4 | 5 | This is FPGA JTAG programmer for [ULX2/3S boards](https://radiona.org/ulx3s/). You need to have bitstream ready. 6 | 7 | ## Usage 8 | 9 | FPGA ULX2S / ULX3S JTAG programmer command line options: 10 | 11 | ``` 12 | Usage: fujprog [option(s)] [bitstream_file] 13 | 14 | Valid options: 15 | -p PORT Select USB JTAG / UART PORT (default is 0) 16 | -P TTY Select TTY port (valid only with -t or -a) 17 | -T TYPE Select TYPE of input (svf, img, bit or jed) 18 | -i identify and exit 19 | -j TARGET Select bitstream TARGET as SRAM (default) or FLASH 20 | -f ADDR Start writing to SPI flash at ADDR, optional with -j flash 21 | -s FILE Convert bitstream to SVF FILE and exit 22 | -r Reload FPGA configuration from FLASH 23 | -t Enter terminal emulation mode after completing JTAG operations 24 | -b SPEED Set baudrate to SPEED (300 to 3000000 bauds) 25 | -e FILE Send and execute a f32c (MIPS/RISCV) binary FILE 26 | -x SPEED Set binary transfer speed, optional with -e 27 | -a FILE Send a raw FILE 28 | -d debug (verbose) 29 | -D DELAY Delay transmission of each byte by DELAY ms 30 | -V display version and exit 31 | -z Force action 32 | -h This help message 33 | -l X Display messages in log fashion every times 34 | -S serial Select FTDI by serial to support multiple boards 35 | -q Suppress messages 36 | ``` 37 | 38 | ## Example usage 39 | 40 | Upload bitstream: 41 | ``` 42 | fujprog bitstream.bit 43 | ``` 44 | 45 | Upload bitstream to flash: 46 | ``` 47 | fujprog -j flash bitstream.bit 48 | ``` 49 | 50 | Upload bitstream from curl: 51 | ``` 52 | curl https://www.site.com/bitstream.bit | fujprog 53 | ``` 54 | 55 | Upload flash image from curl: 56 | ``` 57 | curl https://www.site.com/bitstream.img | fujprog -T img -j flash 58 | ``` 59 | 60 | # Building 61 | 62 | It is standard CMake procedure: 63 | 64 | ``` 65 | mkdir build 66 | cd build 67 | cmake .. 68 | make 69 | make install 70 | ``` 71 | 72 | You can also pass optional parameters: 73 | 74 | ``` 75 | cmake -DBUILD_STATIC=ON -DLIBFTDISTATIC=/opt/libftdi/lib/libftdi.a -DLIBUSB0STATIC=/opt/libusb0/lib/libusb.a .. 76 | make install/strip 77 | ``` 78 | 79 | ### Linux requirements 80 | 81 | 82 | You need following packages in order to build on Debian/Ubuntu systems: 83 | ``` 84 | sudo apt-get install libftdi1-dev libusb-dev cmake make build-essential 85 | ``` 86 | 87 | ## MacOS X build 88 | 89 | You need to install following dependencies (tested with homebrew): 90 | ``` 91 | brew install libftdi libftdi0 92 | ``` 93 | 94 | And then it is standard build with `-DSTATICLIB=ON`: 95 | 96 | ``` 97 | mkdir build 98 | cd build 99 | cmake -DBUILD_STATICLIB=ON .. 100 | make 101 | make install/strip 102 | ``` 103 | 104 | Note that full static binary is not supported by Apple. 105 | 106 | ## Windows build 107 | 108 | You need to download ftdi dependency lib: 109 | ``` 110 | wget https://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.28%20WHQL%20Certified.zip 111 | ``` 112 | 113 | Then you can just open folder inside Visual Studio and build Release versions. 114 | 115 | ## Windows cross-compile 116 | 117 | You need to download ftdi dependency lib: 118 | ``` 119 | wget https://www.ftdichip.com/Drivers/CDM/CDM%20v2.12.28%20WHQL%20Certified.zip 120 | ``` 121 | 122 | Cross compiling is done using standard cmake toolchain file: 123 | ``` 124 | mkdir build 125 | cd build 126 | cmake -DCMAKE_TOOLCHAIN_FILE=`pwd`/../cmake/Toolchain-cross-mingw32.cmake .. 127 | make 128 | ``` 129 | 130 | ## FreeBSD build 131 | 132 | You need to install dependencies: 133 | ``` 134 | pkg install libftdi1 pkgconf git cmake 135 | ``` 136 | 137 | And then it is standard CMake procedure: 138 | ``` 139 | mkdir build 140 | cd build 141 | cmake .. 142 | make 143 | make install 144 | ``` 145 | 146 | If you need static binary version, you need to perform following cmake command: 147 | ``` 148 | cmake -E env CFLAGS="-pthread" cmake -DBUILD_STATIC=ON .. 149 | ``` 150 | 151 | # Windows Notes 152 | 153 | You may need to disable windows security block 154 | 155 | ![windows security block](/images/securityblock.png) 156 | 157 | ## Windows Drivers 158 | 159 | The JTAG features of this fujprog cannot be used concurrently with OpenOCD. 160 | 161 | In order to use OpenOCD with the ULX3S, the `libusbK` dirvers are needed. One way of manually changing the drivers is to use [Zadig](https://zadig.akeo.ie/). The problem with using the `libusbK` drivers is that this fujprog will no longer work, as it needs the FTDI drivers. 162 | 163 | ## Change ULX3S Driver to libusbK using Zadig 164 | 165 | The ULX3S is using the FTDI drivers if it shows up in the Device Manager - Ports (COM & LPT) 166 | 167 | ![ULX3S-as-FTDI-device](/images/ULX3S-as-FTDI-device.PNG) 168 | 169 | Launch Zadig and click on `Options - List all Devices`. Select the ULX3S device from the dropdown: 170 | 171 | ![Zadig-FTDI-to-libusbK](/images/Zadig-FTDI-to-libusbK.PNG) 172 | 173 | Press the Replace Driver button and after a few moments you should see a message that the drivers were installed successfully: 174 | 175 | ![Zadig-success](/images/Zadig-success.PNG) 176 | 177 | The driver change typically works immediately and no reboot is needed. 178 | 179 | ## Change ULX3S Driver to FTDI 180 | 181 | The FTDI drivers should already be installed. If so, Windows will automatically use these drivers when a new ULXS3 is plugged in. If the FTDI Drivers are not installed, they can be downloaded from https://www.ftdichip.com/Drivers/D2XX.htm (the setup executable noted in the comments column may be the easiest way to install the drivers). 182 | 183 | The ULX3S is using the libusbK drivers if it shows up in Device Manager - libusbK USB Devices. (typically when using OpenOCD) 184 | 185 | ![ULX3S-as-libusbK-device](/images/ULX3S-as-libusbK-device.PNG) 186 | 187 | To remove the libusbK drivers, right click on your ULX3S device in Device Manager and select `Uninstall Device`: 188 | 189 | ![Uninstall-libusbK-device](/images/Uninstall-libusbK-device.PNG) 190 | 191 | Then click the Uninstall button (don't check the box unless you want to actually uninstall the drivers from Windows and then reinstall the drivers later; we are only uninstalling the device): 192 | 193 | ![Uninstall-libusbK-device-step2](/images/Uninstall-libusbK-device-step2.PNG) 194 | 195 | After clicking the Uninstall button, `Device Manager` may flicker a bit, but no message is typically shown. If the device was removed it will no longer be visible. If there are no other libusbK devices, then then entire `libusbK USB Devices` container will also be gone. 196 | 197 | To complete the process of installing the FDTI drivers: Unplug the ULX3S, wait 30 seconds and plug it back in. Windows should automatically use the FTDI drivers and a new COM port will appear in `Device Manager - Ports (COM & LPT)` as shown above. 198 | 199 | # Troubleshooting 200 | 201 | ## WINDOWS 202 | 203 | Most issues come from windows platform. In some cases 204 | fujprog doesn't work. Sometimes it is just a matter of dynamic 205 | linking (DLL file "ftd2xx.dll" or "ftd2xx64.dll", easiest is 206 | just to copy this file from FTDI D2XX CDM driver to the same 207 | directory where fujprog.exe is) 208 | 209 | On VoIFS there is strange problem related with fujprog.exe 210 | compiled with mingw. fujprog.exe, if started from "wrong" directory 211 | doesn't work. When started from "wrong" directory, fujprog.exe 212 | will exit without printing any error or any other message while 213 | it should print help/usage message shown on top of this page. 214 | Possible cause of this problem is that "ftd2xx64.dll" (for win64) 215 | is found copied to System32 directory under name "ftd2xx.dll" (for win32). 216 | 217 | Possible solution would be to remove all ftd2xx copies and copy 218 | fujprog.exe and dll to another directory and try again. 219 | 220 | ## LINUX 221 | 222 | Here we have much better success, fujprog is statically linked and 223 | doesn't depend on any other file. Most issues come from user permissions 224 | so fujprog should be either run as root or the user should be given 225 | permissions to access USB and serial device, that's usually done 226 | easily with some udev rule: 227 | 228 | # /etc/udev/rules.d/80-fpga-ulx3s.rules 229 | # this is for usb-serial tty device 230 | SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ 231 | MODE="664", GROUP="dialout" 232 | # this is for fujprog libusb access 233 | ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ 234 | GROUP="dialout", MODE="666" 235 | 236 | ## APPLE 237 | 238 | Make sure that FTDI driver is not loaded. For example: 239 | 240 | ``` 241 | sudo kextstat | grep -i ftdi 242 | ``` 243 | 244 | Should not return com.FTDI.driver.FTDIUSBSerialDriver when ulx3s is connected to USB port like this: 245 | 246 | ``` 247 | 195 0 0xffffff7f85521000 0x7000 0x7000 com.FTDI.driver.FTDIUSBSerialDriver (2.4.4) 248 | ``` 249 | 250 | If does, try to run fujprog as root as it will try to automatically handle kexts. Also, you can temporarily remove them by running following commands: 251 | 252 | ``` 253 | /sbin/kextunload -bundle-id com.FTDI.driver.FTDIUSBSerialDriver 254 | /sbin/kextunload -bundle-id com.apple.driver.AppleUSBFTDI 255 | ``` 256 | 257 | Feel free to report any problems. If you have problems running released binary try to compile your own version. 258 | 259 | # Credits 260 | 261 | Fujprog is based on ujprog originally authored by Marko Zec. 262 | Contributions from EMARD, gojimmypi and kost. 263 | 264 | Copyright (C), 2008-2018 Marko Zec, University of Zagreb 265 | 266 | Copyright (c), 2014-2019 EMARD 267 | 268 | Copyright (c), 2020 kost 269 | 270 | -------------------------------------------------------------------------------- /cmake/Toolchain-cross-mingw32.cmake: -------------------------------------------------------------------------------- 1 | # the name of the target operating system 2 | SET(CMAKE_SYSTEM_NAME Windows) 3 | 4 | # Choose an appropriate compiler prefix 5 | 6 | # for classical mingw32 7 | # see http://www.mingw.org/ 8 | #set(COMPILER_PREFIX "i586-mingw32msvc") 9 | 10 | # for 32 or 64 bits mingw-w64 11 | # see http://mingw-w64.sourceforge.net/ 12 | set(COMPILER_PREFIX "i686-w64-mingw32") 13 | #set(COMPILER_PREFIX "x86_64-w64-mingw32" 14 | 15 | # which compilers to use for C and C++ 16 | find_program(CMAKE_RC_COMPILER NAMES ${COMPILER_PREFIX}-windres) 17 | #SET(CMAKE_RC_COMPILER ${COMPILER_PREFIX}-windres) 18 | find_program(CMAKE_C_COMPILER NAMES ${COMPILER_PREFIX}-gcc) 19 | #SET(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) 20 | find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) 21 | #SET(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) 22 | 23 | 24 | # here is the target environment located 25 | #SET(USER_ROOT_PATH /home/erk/erk-win32-dev) 26 | #SET(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX} ${USER_ROOT_PATH}) 27 | 28 | # adjust the default behaviour of the FIND_XXX() commands: 29 | # search headers and libraries in the target environment, search 30 | # programs in the host environment 31 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 32 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 33 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 34 | -------------------------------------------------------------------------------- /cmake/Toolchain-cross-mingw64.cmake: -------------------------------------------------------------------------------- 1 | # the name of the target operating system 2 | SET(CMAKE_SYSTEM_NAME Windows) 3 | 4 | # Choose an appropriate compiler prefix 5 | 6 | # for classical mingw32 7 | # see http://www.mingw.org/ 8 | #set(COMPILER_PREFIX "i586-mingw32msvc") 9 | 10 | # for 32 or 64 bits mingw-w64 11 | # see http://mingw-w64.sourceforge.net/ 12 | #set(COMPILER_PREFIX "i686-w64-mingw32") 13 | set(COMPILER_PREFIX "x86_64-w64-mingw32") 14 | 15 | # which compilers to use for C and C++ 16 | find_program(CMAKE_RC_COMPILER NAMES ${COMPILER_PREFIX}-windres) 17 | #SET(CMAKE_RC_COMPILER ${COMPILER_PREFIX}-windres) 18 | find_program(CMAKE_C_COMPILER NAMES ${COMPILER_PREFIX}-gcc) 19 | #SET(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc) 20 | find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) 21 | #SET(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++) 22 | 23 | 24 | # here is the target environment located 25 | #SET(USER_ROOT_PATH /home/erk/erk-win32-dev) 26 | #SET(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX} ${USER_ROOT_PATH}) 27 | 28 | # adjust the default behaviour of the FIND_XXX() commands: 29 | # search headers and libraries in the target environment, search 30 | # programs in the host environment 31 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 32 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 33 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 34 | -------------------------------------------------------------------------------- /ftd2xx-amd64.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/ftd2xx-amd64.lib -------------------------------------------------------------------------------- /ftd2xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/ftd2xx.h -------------------------------------------------------------------------------- /ftd2xx.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/ftd2xx.lib -------------------------------------------------------------------------------- /fujprog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * FT-232R / FT-231X USB JTAG programmer 3 | * 4 | * Copyright (c) 2010 - 2018 Marko Zec, University of Zagreb 5 | * Copyright (c) 2014-2019 EMARD 6 | * Copyright (c) 2020, kost 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | * TODO: 32 | * 33 | * - WIN32: check for USB device string description 34 | * 35 | * - JTAG scan / identify chain on entry. 36 | * 37 | * - verify SRAM / FLASH 38 | * 39 | * - RUN TEST delay downscaling. 40 | * 41 | * - disable resetting the TAP on entry / leave? 42 | * 43 | * - execute SVF commands provided as command line args? 44 | */ 45 | 46 | static const char *verstr = "ULX2S / ULX3S JTAG programmer"; 47 | static const char *credstr = "Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors"; 48 | 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | #ifdef _MSC_VER 59 | //not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw 60 | #define strncasecmp _strnicmp 61 | #define strcasecmp _stricmp 62 | #define strtok_r strtok_s 63 | #include "getopt.h" 64 | #include 65 | void usleep(__int64 usec) 66 | { 67 | HANDLE timer; 68 | LARGE_INTEGER ft; 69 | 70 | ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time 71 | 72 | timer = CreateWaitableTimer(NULL, TRUE, NULL); 73 | SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); 74 | WaitForSingleObject(timer, INFINITE); 75 | CloseHandle(timer); 76 | } 77 | #else 78 | #include 79 | #endif 80 | 81 | #include "fujprog.h" 82 | 83 | #ifdef __FreeBSD__ 84 | #define USE_PPI 85 | #endif 86 | 87 | #if defined(__linux__) 88 | #include 89 | #endif 90 | 91 | #if defined(__linux__) || defined(WIN32) 92 | #define isnumber(x) (x >= '0' && x <= '9') 93 | #endif 94 | 95 | #ifdef WIN32 96 | #include 97 | #include 98 | #include 99 | #else 100 | #include 101 | #include 102 | #include 103 | #ifdef USE_PPI 104 | #include 105 | #include 106 | #endif 107 | #include 108 | #endif 109 | 110 | #ifdef WIN32 111 | #define BITMODE_OFF 0x0 112 | #define BITMODE_BITBANG 0x1 113 | #define BITMODE_SYNCBB 0x4 114 | #define BITMODE_CBUS 0x20 115 | #endif 116 | 117 | /* Forward declarations */ 118 | static int commit(int); 119 | static void set_state(int); 120 | static int exec_svf_tokenized(int, char **); 121 | static int send_dr(int, char *, char *, char *); 122 | static int send_ir(int, char *, char *, char *); 123 | static int exec_svf_mem(char *, int, int); 124 | static int cmp_chip_ids(char *, char *); 125 | 126 | 127 | enum svf_cmd { 128 | SVF_SDR, SVF_SIR, SVF_STATE, SVF_RUNTEST, SVF_HDR, SVF_HIR, 129 | SVF_TDR, SVF_TIR, SVF_ENDDR, SVF_ENDIR, SVF_FREQUENCY, SVF_UNKNOWN 130 | }; 131 | 132 | static struct svf_cmdtable { 133 | enum svf_cmd cmd_id; 134 | char *cmd_str; 135 | } svf_cmdtable[] = { 136 | {SVF_SDR, "SDR"}, 137 | {SVF_SIR, "SIR"}, 138 | {SVF_STATE, "STATE"}, 139 | {SVF_RUNTEST, "RUNTEST"}, 140 | {SVF_HDR, "HDR"}, 141 | {SVF_HIR, "HIR"}, 142 | {SVF_TDR, "TDR"}, 143 | {SVF_TIR, "TIR"}, 144 | {SVF_ENDDR, "ENDDR"}, 145 | {SVF_ENDIR, "ENDIR"}, 146 | {SVF_FREQUENCY, "FREQUENCY"}, 147 | {SVF_UNKNOWN, NULL} 148 | }; 149 | 150 | 151 | enum tap_state { 152 | RESET, IDLE, 153 | DRSELECT, DRCAPTURE, DRSHIFT, DREXIT1, DRPAUSE, DREXIT2, DRUPDATE, 154 | IRSELECT, IRCAPTURE, IRSHIFT, IREXIT1, IRPAUSE, IREXIT2, IRUPDATE, 155 | UNDEFINED, UNSUPPORTED, 156 | }; 157 | 158 | static struct tap_statetable { 159 | enum tap_state state_id; 160 | char *state_str; 161 | } tap_statetable[] = { 162 | {RESET, "RESET"}, 163 | {IDLE, "IDLE"}, 164 | {DRSELECT, "DRSELECT"}, 165 | {DRCAPTURE, "DRCAPTURE"}, 166 | {DRSHIFT, "DRSHIFT"}, 167 | {DREXIT1, "DREXIT1"}, 168 | {DRPAUSE, "DRPAUSE"}, 169 | {DREXIT2, "DREXIT2"}, 170 | {DRUPDATE, "DRUPDATE"}, 171 | {IRSELECT, "IRSELECT"}, 172 | {IRCAPTURE, "IRCAPTURE"}, 173 | {IRSHIFT, "IRSHIFT"}, 174 | {IREXIT1, "IREXIT1"}, 175 | {IRPAUSE, "IRPAUSE"}, 176 | {IREXIT2, "IREXIT2"}, 177 | {IRUPDATE, "IRUPDATE"}, 178 | {UNDEFINED, "UNDEFINED"}, 179 | {UNSUPPORTED, NULL} 180 | }; 181 | 182 | #define STATE2STR(state) (tap_statetable[state].state_str) 183 | 184 | 185 | static enum port_mode { 186 | PORT_MODE_ASYNC, PORT_MODE_SYNC, PORT_MODE_UART, PORT_MODE_UNKNOWN 187 | } port_mode = PORT_MODE_UNKNOWN; 188 | 189 | 190 | static enum cable_hw { 191 | CABLE_HW_USB, CABLE_HW_PPI, CABLE_HW_COM, CABLE_HW_UNKNOWN 192 | } cable_hw = CABLE_HW_UNKNOWN; 193 | 194 | 195 | static struct cable_hw_map { 196 | int cable_hw; 197 | int usb_vid; 198 | int usb_pid; 199 | char *cable_path; 200 | char tck, tms, tdi, tdo; 201 | char cbus_led; 202 | } cable_hw_map[] = { 203 | { 204 | .cable_hw = CABLE_HW_USB, 205 | .usb_vid = 0x0403, 206 | .usb_pid = 0x6001, 207 | .cable_path = "FER ULXP2 board JTAG / UART", 208 | .tck = 0x20, 209 | .tms = 0x80, 210 | .tdi = 0x08, 211 | .tdo = 0x40, 212 | .cbus_led = 0x02 213 | }, 214 | { 215 | .cable_hw = CABLE_HW_USB, 216 | .usb_vid = 0x0403, 217 | .usb_pid = 0x6001, 218 | .cable_path = "FER ULX2S board JTAG / UART", 219 | .tck = 0x20, 220 | .tms = 0x80, 221 | .tdi = 0x08, 222 | .tdo = 0x40, 223 | .cbus_led = 0x02 224 | }, 225 | { 226 | .cable_hw = CABLE_HW_USB, 227 | .usb_vid = 0x0403, 228 | .usb_pid = 0x6015, 229 | .cable_path = "ULX3S FPGA board", 230 | .tck = 0x20, 231 | .tms = 0x40, 232 | .tdi = 0x80, 233 | .tdo = 0x08, 234 | .cbus_led = 0x00 235 | }, 236 | { 237 | .cable_hw = CABLE_HW_USB, 238 | .usb_vid = 0x0403, 239 | .usb_pid = 0x6015, 240 | .cable_path = "ULX3S FPGA v1.7", 241 | .tck = 0x20, 242 | .tms = 0x40, 243 | .tdi = 0x80, 244 | .tdo = 0x08, 245 | .cbus_led = 0x00 246 | }, 247 | { 248 | .cable_hw = CABLE_HW_USB, 249 | .usb_vid = 0x0403, 250 | .usb_pid = 0x6015, 251 | .cable_path = "ULX3S FPGA 25K v1.7", 252 | .tck = 0x20, 253 | .tms = 0x40, 254 | .tdi = 0x80, 255 | .tdo = 0x08, 256 | .cbus_led = 0x00 257 | }, 258 | { 259 | .cable_hw = CABLE_HW_USB, 260 | .usb_vid = 0x0403, 261 | .usb_pid = 0x6015, 262 | .cable_path = "ULX3S FPGA 45K v1.7", 263 | .tck = 0x20, 264 | .tms = 0x40, 265 | .tdi = 0x80, 266 | .tdo = 0x08, 267 | .cbus_led = 0x00 268 | }, 269 | { 270 | .cable_hw = CABLE_HW_USB, 271 | .usb_vid = 0x0403, 272 | .usb_pid = 0x6015, 273 | .cable_path = "ULX3S FPGA 12K v2.1.2", 274 | .tck = 0x20, 275 | .tms = 0x40, 276 | .tdi = 0x80, 277 | .tdo = 0x08, 278 | .cbus_led = 0x00 279 | }, 280 | { 281 | .cable_hw = CABLE_HW_USB, 282 | .usb_vid = 0x0403, 283 | .usb_pid = 0x6015, 284 | .cable_path = "ULX3S FPGA 25K v2.1.2", 285 | .tck = 0x20, 286 | .tms = 0x40, 287 | .tdi = 0x80, 288 | .tdo = 0x08, 289 | .cbus_led = 0x00 290 | }, 291 | { 292 | .cable_hw = CABLE_HW_USB, 293 | .usb_vid = 0x0403, 294 | .usb_pid = 0x6015, 295 | .cable_path = "ULX3S FPGA 45K v2.1.2", 296 | .tck = 0x20, 297 | .tms = 0x40, 298 | .tdi = 0x80, 299 | .tdo = 0x08, 300 | .cbus_led = 0x00 301 | }, 302 | { 303 | .cable_hw = CABLE_HW_USB, 304 | .usb_vid = 0x0403, 305 | .usb_pid = 0x6015, 306 | .cable_path = "ULX3S FPGA 85K v2.1.2", 307 | .tck = 0x20, 308 | .tms = 0x40, 309 | .tdi = 0x80, 310 | .tdo = 0x08, 311 | .cbus_led = 0x00 312 | }, 313 | { 314 | .cable_hw = CABLE_HW_USB, 315 | .usb_vid = 0x0403, 316 | .usb_pid = 0x6015, 317 | .cable_path = "ULX3S FPGA 12K v3.0.3", 318 | .tck = 0x20, 319 | .tms = 0x40, 320 | .tdi = 0x80, 321 | .tdo = 0x08, 322 | .cbus_led = 0x00 323 | }, 324 | { 325 | .cable_hw = CABLE_HW_USB, 326 | .usb_vid = 0x0403, 327 | .usb_pid = 0x6015, 328 | .cable_path = "ULX3S FPGA 25K v3.0.3", 329 | .tck = 0x20, 330 | .tms = 0x40, 331 | .tdi = 0x80, 332 | .tdo = 0x08, 333 | .cbus_led = 0x00 334 | }, 335 | { 336 | .cable_hw = CABLE_HW_USB, 337 | .usb_vid = 0x0403, 338 | .usb_pid = 0x6015, 339 | .cable_path = "ULX3S FPGA 45K v3.0.3", 340 | .tck = 0x20, 341 | .tms = 0x40, 342 | .tdi = 0x80, 343 | .tdo = 0x08, 344 | .cbus_led = 0x00 345 | }, 346 | { 347 | .cable_hw = CABLE_HW_USB, 348 | .usb_vid = 0x0403, 349 | .usb_pid = 0x6015, 350 | .cable_path = "ULX3S FPGA 85K v3.0.3", 351 | .tck = 0x20, 352 | .tms = 0x40, 353 | .tdi = 0x80, 354 | .tdo = 0x08, 355 | .cbus_led = 0x00 356 | }, 357 | { 358 | .cable_hw = CABLE_HW_USB, 359 | .usb_vid = 0x0403, 360 | .usb_pid = 0x6015, 361 | .cable_path = "ULX3S FPGA 12K v3.0.7", 362 | .tck = 0x20, 363 | .tms = 0x40, 364 | .tdi = 0x80, 365 | .tdo = 0x08, 366 | .cbus_led = 0x00 367 | }, 368 | { 369 | .cable_hw = CABLE_HW_USB, 370 | .usb_vid = 0x0403, 371 | .usb_pid = 0x6015, 372 | .cable_path = "ULX3S FPGA 25K v3.0.7", 373 | .tck = 0x20, 374 | .tms = 0x40, 375 | .tdi = 0x80, 376 | .tdo = 0x08, 377 | .cbus_led = 0x00 378 | }, 379 | { 380 | .cable_hw = CABLE_HW_USB, 381 | .usb_vid = 0x0403, 382 | .usb_pid = 0x6015, 383 | .cable_path = "ULX3S FPGA 45K v3.0.7", 384 | .tck = 0x20, 385 | .tms = 0x40, 386 | .tdi = 0x80, 387 | .tdo = 0x08, 388 | .cbus_led = 0x00 389 | }, 390 | { 391 | .cable_hw = CABLE_HW_USB, 392 | .usb_vid = 0x0403, 393 | .usb_pid = 0x6015, 394 | .cable_path = "ULX3S FPGA 85K v3.0.7", 395 | .tck = 0x20, 396 | .tms = 0x40, 397 | .tdi = 0x80, 398 | .tdo = 0x08, 399 | .cbus_led = 0x00 400 | }, 401 | { 402 | .cable_hw = CABLE_HW_USB, 403 | .usb_vid = 0x0403, 404 | .usb_pid = 0x6015, 405 | .cable_path = "ULX3S FPGA 12K v3.0.8", 406 | .tck = 0x20, 407 | .tms = 0x40, 408 | .tdi = 0x80, 409 | .tdo = 0x08, 410 | .cbus_led = 0x00 411 | }, 412 | { 413 | .cable_hw = CABLE_HW_USB, 414 | .usb_vid = 0x0403, 415 | .usb_pid = 0x6015, 416 | .cable_path = "ULX3S FPGA 25K v3.0.8", 417 | .tck = 0x20, 418 | .tms = 0x40, 419 | .tdi = 0x80, 420 | .tdo = 0x08, 421 | .cbus_led = 0x00 422 | }, 423 | { 424 | .cable_hw = CABLE_HW_USB, 425 | .usb_vid = 0x0403, 426 | .usb_pid = 0x6015, 427 | .cable_path = "ULX3S FPGA 45K v3.0.8", 428 | .tck = 0x20, 429 | .tms = 0x40, 430 | .tdi = 0x80, 431 | .tdo = 0x08, 432 | .cbus_led = 0x00 433 | }, 434 | { 435 | .cable_hw = CABLE_HW_USB, 436 | .usb_vid = 0x0403, 437 | .usb_pid = 0x6015, 438 | .cable_path = "ULX3S FPGA 85K v3.0.8", 439 | .tck = 0x20, 440 | .tms = 0x40, 441 | .tdi = 0x80, 442 | .tdo = 0x08, 443 | .cbus_led = 0x00 444 | }, 445 | { 446 | .cable_hw = CABLE_HW_USB, 447 | .usb_vid = 0x0403, 448 | .usb_pid = 0x6010, 449 | .cable_path = "Lattice ECP5 Evaluation Board", 450 | .tck = 0x01, 451 | .tms = 0x08, 452 | .tdi = 0x02, 453 | .tdo = 0x04, 454 | .cbus_led = 0x10 455 | }, 456 | { 457 | .cable_hw = CABLE_HW_USB, 458 | .usb_vid = 0x0403, 459 | .usb_pid = 0x6011, 460 | .cable_path = "Digilent FFC", 461 | .tck = 0x01, 462 | .tms = 0x08, 463 | .tdi = 0x02, 464 | .tdo = 0x04, 465 | .cbus_led = 0x00 466 | }, 467 | { 468 | .cable_hw = CABLE_HW_UNKNOWN, 469 | .cable_path = "UNKNOWN" 470 | } 471 | }; 472 | 473 | 474 | #define USB_BAUDS 1000000 475 | 476 | #define USB_TCK (hmp->tck) 477 | #define USB_TMS (hmp->tms) 478 | #define USB_TDI (hmp->tdi) 479 | #define USB_TDO (hmp->tdo) 480 | #define USB_CBUS_LED (hmp->cbus_led) 481 | 482 | #define PPI_TCK 0x02 483 | #define PPI_TMS 0x04 484 | #define PPI_TDI 0x01 485 | #define PPI_TDO 0x40 486 | 487 | #define USB_BUFLEN_ASYNC 8192 488 | #ifdef WIN32 489 | #define USB_BUFLEN_SYNC 4096 490 | #else 491 | #define USB_BUFLEN_SYNC 384 492 | #endif 493 | 494 | #define BUFLEN_MAX USB_BUFLEN_ASYNC /* max(SYNC, ASYNC) */ 495 | 496 | #define LED_BLINK_RATE 250 497 | 498 | #define BREAK_MS 250 499 | 500 | #define SPI_PAGE_SIZE 256 501 | #define SPI_SECTOR_SIZE (256 * SPI_PAGE_SIZE) 502 | 503 | #define TYPE_UNSPECIFIED 0 504 | #define TYPE_BIT 1 505 | #define TYPE_IMG 2 506 | #define TYPE_SVF 3 507 | #define TYPE_JED 4 508 | 509 | static char *statc = "-\\|/"; 510 | 511 | /* Runtime globals */ 512 | static int cur_s = UNDEFINED; 513 | static uint8_t txbuf[64 * BUFLEN_MAX]; 514 | static uint8_t rxbuf[64 * BUFLEN_MAX]; 515 | static int txpos; 516 | static int need_led_blink; /* Schedule CBUS led toggle */ 517 | static int last_ledblink_ms; /* Last time we toggled the CBUS LED */ 518 | static int led_state; /* CBUS LED indicator state */ 519 | static int blinker_phase; 520 | static int progress_perc; 521 | static int display_log; /* display in log like fashion */ 522 | static int display_counter; /* display counter for displaying progress */ 523 | static int bauds = 115200; /* async terminal emulation baudrate */ 524 | static int xbauds; /* binary transfer baudrate */ 525 | static int port_index; 526 | static const char *serial = NULL; /* FTDI serial to support more than one device */ 527 | static int input_type = TYPE_UNSPECIFIED; /* specify type of input */ 528 | static int terminal; /* terminal emulation mode */ 529 | static int reload; /* send break to reset f32c */ 530 | static int quiet; /* suppress standard messages */ 531 | char *svf_name; /* SVF output name */ 532 | static int txfu_ms; /* txt file upload character delay (ms) */ 533 | static int tx_binary; /* send in raw (0) or binary (1) format */ 534 | static const char *txfname; /* file to send */ 535 | static const char *com_name; /* COM / TTY port name for -a or -t */ 536 | static int spi_addr; /* Base address for -j flash programming */ 537 | static int global_debug; 538 | static int force_prog; /* force programming even if chip ids do not match*/ 539 | static int opt_info=0; /* display info */ 540 | 541 | static struct cable_hw_map *hmp; /* Selected cable hardware map */ 542 | #ifdef WIN32 543 | static FT_HANDLE ftHandle; /* USB port handle */ 544 | static HANDLE com_port; /* COM port file */ 545 | static struct _DCB tty; /* COM port TTY handle */ 546 | #else 547 | static struct ftdi_context fc; /* USB port handle */ 548 | static int com_port; /* COM port file */ 549 | static struct termios tty; /* COM port TTY handle */ 550 | #ifdef USE_PPI 551 | static int ppi; /* Parallel port handle */ 552 | #endif 553 | #endif 554 | 555 | 556 | /* ms_sleep() sleeps for at least the number of milliseconds given as arg */ 557 | #define ms_sleep(delay_ms) usleep((delay_ms) * 1000) 558 | 559 | 560 | static long 561 | ms_uptime(void) 562 | { 563 | long ms; 564 | #ifndef WIN32 565 | struct timeval tv; 566 | 567 | gettimeofday(&tv, 0); 568 | ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; 569 | #else 570 | ms = GetTickCount(); 571 | #endif 572 | return (ms); 573 | } 574 | 575 | char *read_stdin(size_t *size) 576 | { 577 | size_t cap = 4096, /* Initial capacity for the char buffer */ 578 | len = 0; /* Current offset of the buffer */ 579 | char *buffer = malloc(cap * sizeof(char)); 580 | int c; 581 | 582 | freopen(NULL, "rb", stdin); 583 | 584 | /* Read char by char, breaking if we reach EOF */ 585 | do { 586 | c=fgetc(stdin); 587 | if (feof(stdin)) break; 588 | buffer[len] = c; 589 | /* When cap == len, we need to resize the buffer 590 | * so that we don't overwrite any bytes 591 | */ 592 | if (++len == cap) 593 | /* Make the output buffer twice its current size */ 594 | buffer = realloc(buffer, (cap *= 2) * sizeof(char)); 595 | } while (!feof(stdin)); 596 | /* Trim off any unused bytes from the buffer */ 597 | buffer = realloc(buffer, (len + 1) * sizeof(char)); 598 | /* Pad the last byte so we don't overread the buffer in the future */ 599 | buffer[len] = '\0'; 600 | *size = len; 601 | 602 | return buffer; 603 | } 604 | 605 | static int 606 | set_port_mode(int mode) 607 | { 608 | int res = 0; 609 | 610 | /* No-op if already in requested mode, or not using USB */ 611 | if (!need_led_blink && 612 | (port_mode == mode || cable_hw != CABLE_HW_USB)) { 613 | port_mode = mode; 614 | return (0); 615 | } 616 | 617 | /* Flush any stale TX buffers */ 618 | commit(1); 619 | 620 | /* Run only if not in identify mode */ 621 | if (!opt_info) { 622 | /* Blink status LED by deactivating CBUS pulldown pin */ 623 | if (need_led_blink) { 624 | need_led_blink = 0; 625 | led_state ^= USB_CBUS_LED; 626 | if (!quiet && progress_perc < 100) { 627 | if (!display_log) { 628 | fprintf(stderr, "\r"); 629 | fprintf(stderr, "Programming: %d%% %c ", 630 | progress_perc, statc[blinker_phase]); 631 | fflush(stderr); 632 | } else { 633 | display_counter++; 634 | if (display_counter >= display_log) { 635 | display_counter=0; 636 | fprintf(stderr, "Programming: %d%%\n", 637 | progress_perc); 638 | fflush(stderr); 639 | } 640 | } 641 | } 642 | blinker_phase = (blinker_phase + 1) & 0x3; 643 | } 644 | } 645 | 646 | #ifdef WIN32 647 | if (mode == PORT_MODE_ASYNC) 648 | mode = PORT_MODE_SYNC; 649 | #endif 650 | 651 | switch (mode) { 652 | case PORT_MODE_SYNC: 653 | #ifdef WIN32 654 | /* 655 | * If switching to SYNC mode, attempt to allow for TX 656 | * buffers to drain first. 657 | */ 658 | if (port_mode != PORT_MODE_SYNC) 659 | ms_sleep(20); 660 | 661 | res = FT_SetBitMode(ftHandle, 662 | #else 663 | res = ftdi_set_bitmode(&fc, 664 | #endif 665 | USB_TCK | USB_TMS | USB_TDI | led_state, 666 | BITMODE_SYNCBB | (BITMODE_CBUS * (USB_CBUS_LED != 0))); 667 | 668 | if (port_mode == PORT_MODE_SYNC) 669 | break; 670 | 671 | /* Flush any stale RX buffers */ 672 | #ifdef WIN32 673 | for (res = 0; res < 2; res++) { 674 | do { 675 | ms_sleep(10); 676 | } while (FT_StopInTask(ftHandle) != FT_OK); 677 | FT_Purge(ftHandle, FT_PURGE_RX); 678 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 679 | ms_sleep(10); 680 | } 681 | #else 682 | do { 683 | res = ftdi_read_data(&fc, &txbuf[0], sizeof(txbuf)); 684 | } while (res == sizeof(txbuf)); 685 | #endif 686 | break; 687 | 688 | case PORT_MODE_ASYNC: 689 | #ifdef WIN32 690 | res = FT_SetBitMode(ftHandle, 691 | #else 692 | res = ftdi_set_bitmode(&fc, 693 | #endif 694 | USB_TCK | USB_TMS | USB_TDI | led_state, 695 | BITMODE_BITBANG | (BITMODE_CBUS * (USB_CBUS_LED != 0))); 696 | break; 697 | 698 | case PORT_MODE_UART: 699 | res = 0; 700 | if (port_mode == PORT_MODE_UART) 701 | break; 702 | /* Pull TCK low so that we don't incidentally pulse it. */ 703 | memset(txbuf, 0, 10); 704 | #ifdef WIN32 705 | FT_Write(ftHandle, txbuf, 100, (DWORD *) &res); 706 | if (res < 0) { 707 | fprintf(stderr, "FT_Write() failed\n"); 708 | return (res); 709 | } 710 | res = FT_SetBitMode(ftHandle, 0, BITMODE_OFF); 711 | #else 712 | res = ftdi_write_data(&fc, &txbuf[0], 10); 713 | if (res < 0) { 714 | fprintf(stderr, "ftdi_write_data() failed\n"); 715 | return (res); 716 | } 717 | res = ftdi_disable_bitbang(&fc); 718 | #endif 719 | break; 720 | 721 | default: 722 | res = -1; 723 | } 724 | 725 | port_mode = mode; 726 | return (res); 727 | } 728 | 729 | 730 | #ifdef WIN32 731 | static int 732 | setup_usb(void) 733 | { 734 | FT_STATUS res; 735 | FT_DEVICE ftDevice; 736 | DWORD deviceID; 737 | char Description[64]; 738 | 739 | res = FT_Open(port_index, &ftHandle); 740 | if (res != FT_OK) { 741 | fprintf(stderr, "FT_Open() failed\n"); 742 | return (res); 743 | } 744 | 745 | res = FT_GetDeviceInfo(ftHandle, &ftDevice, &deviceID, serial, 746 | Description, NULL); 747 | if (res != FT_OK) { 748 | fprintf(stderr, "FT_GetDeviceInfo() failed\n"); 749 | return (res); 750 | } 751 | 752 | if (global_debug) 753 | fprintf(stderr, "Going through cable_hw_map loop\n"); 754 | 755 | for (hmp = cable_hw_map; hmp->cable_hw != CABLE_HW_UNKNOWN; hmp++) { 756 | if (global_debug) 757 | fprintf(stderr, "Looking cableID %d (0x%04x, 0x%04x) with path %s\n", hmp->cable_hw, hmp->usb_vid, hmp->usb_pid, hmp->cable_path); 758 | if ((deviceID == hmp->usb_vid << 16 | hmp->usb_pid) 759 | && strcmp(Description, hmp->cable_path) == 0) { 760 | if (global_debug) 761 | fprintf(stderr, "Found cableID %d (0x%04x, 0x%04x) with path %s\n", hmp->cable_hw, hmp->usb_vid, hmp->usb_pid, hmp->cable_path); 762 | break; 763 | } 764 | } 765 | 766 | if (hmp->cable_hw == CABLE_HW_UNKNOWN) { 767 | fprintf(stderr, "CABLE_HW_UNKNOWN failed\n"); 768 | return (-1); 769 | } 770 | 771 | if (!quiet) 772 | printf("Using USB cable: %s\n", hmp->cable_path); 773 | 774 | res = FT_SetBaudRate(ftHandle, USB_BAUDS); 775 | if (res != FT_OK) { 776 | fprintf(stderr, "FT_SetBaudRate() failed\n"); 777 | return (res); 778 | } 779 | 780 | #ifdef NOTYET 781 | FT_setUSB_Parameters(); 782 | res = ftdi_write_data_set_chunksize(&fc, BUFLEN_MAX); 783 | if (res < 0) { 784 | fprintf(stderr, "ftdi_write_data_set_chunksize() failed\n"); 785 | return (res); 786 | } 787 | #endif 788 | 789 | res = FT_SetLatencyTimer(ftHandle, 1); 790 | if (res != FT_OK) { 791 | fprintf(stderr, "FT_SetLatencyTimer() failed\n"); 792 | return (res); 793 | } 794 | 795 | res = FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 796 | if (res != FT_OK) { 797 | fprintf(stderr, "FT_SetFlowControl() failed\n"); 798 | return (res); 799 | } 800 | 801 | res = FT_SetBitMode(ftHandle, 0, BITMODE_BITBANG); 802 | if (res != FT_OK) { 803 | fprintf(stderr, "FT_SetBitMode() failed\n"); 804 | return (res); 805 | } 806 | 807 | res = FT_SetTimeouts(ftHandle, 1000, 1000); 808 | if (res != FT_OK) { 809 | fprintf(stderr, "FT_SetTimeouts() failed\n"); 810 | return (res); 811 | } 812 | 813 | FT_Purge(ftHandle, FT_PURGE_TX); 814 | FT_Purge(ftHandle, FT_PURGE_RX); 815 | 816 | if (global_debug) 817 | fprintf(stderr, "Returning from setup_usb()\n"); 818 | 819 | return (0); 820 | } 821 | 822 | 823 | static int 824 | shutdown_usb(void) 825 | { 826 | 827 | int res; 828 | 829 | /* Allow for the USB FIFO to drain, just in case. */ 830 | ms_sleep(10); 831 | 832 | /* Clean up */ 833 | res = set_port_mode(PORT_MODE_UART); 834 | if (res < 0) { 835 | fprintf(stderr, "set_port_mode() failed\n"); 836 | return (res); 837 | } 838 | 839 | res = FT_SetLatencyTimer(ftHandle, 20); 840 | if (res < 0) { 841 | fprintf(stderr, "FT_SetLatencyTimer() failed\n"); 842 | return (res); 843 | } 844 | 845 | res = FT_Close(ftHandle); 846 | if (res < 0) { 847 | fprintf(stderr, "FT_Close() failed\n"); 848 | return (res); 849 | } 850 | 851 | return (0); 852 | } 853 | #endif /* WIN32 */ 854 | 855 | 856 | #ifndef WIN32 857 | #ifdef USE_PPI 858 | static int 859 | setup_ppi(void) 860 | { 861 | char c = 0; 862 | 863 | ppi = open("/dev/ppi0", O_RDWR); 864 | if (ppi < 0) 865 | return (errno); 866 | 867 | ioctl(ppi, PPISDATA, &c); 868 | ioctl(ppi, PPISSTATUS, &c); 869 | ioctl(ppi, PPIGSTATUS, &c); 870 | if ((c & 0xb6) != 0x06) { 871 | close (ppi); 872 | return (EINVAL); 873 | } 874 | 875 | return (0); 876 | } 877 | 878 | 879 | static void 880 | shutdown_ppi(void) 881 | { 882 | 883 | /* Pull TCK low so that we don't incidentally pulse it on next run. */ 884 | txbuf[0] = 0; 885 | ioctl(ppi, PPISDATA, &txbuf[0]); 886 | 887 | close (ppi); 888 | } 889 | #endif 890 | 891 | 892 | static int 893 | setup_usb(void) 894 | { 895 | int res; 896 | 897 | 898 | #ifdef __APPLE__ 899 | uid_t uid=getuid(), euid=geteuid(); 900 | if (uid<=0 || uid!=euid) { 901 | if (!quiet) { 902 | fprintf(stderr, "elevated/root permissions detected, handling kexts\n"); 903 | } 904 | setuid(0); 905 | system("/sbin/kextunload" 906 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 907 | system("/sbin/kextunload" 908 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 909 | } else { 910 | if (!quiet) { 911 | fprintf(stderr, "no root permissions, not handling kexts\n"); 912 | } 913 | } 914 | 915 | #endif 916 | 917 | res = ftdi_init(&fc); 918 | if (res < 0) { 919 | fprintf(stderr, "ftdi_init() failed\n"); 920 | return (res); 921 | } 922 | 923 | if (global_debug) 924 | fprintf(stderr, "Going through cable_hw_map loop\n"); 925 | 926 | for (hmp = cable_hw_map; hmp->cable_hw != CABLE_HW_UNKNOWN; hmp++) { 927 | if (global_debug) 928 | fprintf(stderr, "Looking cableID %d (0x%04x, 0x%04x) with path %s\n", hmp->cable_hw, hmp->usb_vid, hmp->usb_pid, hmp->cable_path); 929 | res = ftdi_usb_open_desc_index(&fc, hmp->usb_vid, hmp->usb_pid, 930 | hmp->cable_path, serial, port_index); 931 | if (res == 0) { 932 | if (global_debug) 933 | fprintf(stderr, "Found cableID %d (0x%04x, 0x%04x) with path %s\n", hmp->cable_hw, hmp->usb_vid, hmp->usb_pid, hmp->cable_path); 934 | break; 935 | } 936 | } 937 | if (res < 0) { 938 | res = ftdi_usb_open_desc_index(&fc, 0x0403, 0x6001, 939 | NULL, serial, port_index); 940 | if (res < 0) { 941 | #ifdef __APPLE__ 942 | if (uid<0 || uid!=euid) { 943 | system("/sbin/kextload" 944 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 945 | system("/sbin/kextload" 946 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 947 | } 948 | #endif 949 | return (res); 950 | } 951 | } 952 | 953 | res = ftdi_set_baudrate(&fc, USB_BAUDS); 954 | if (res < 0) { 955 | fprintf(stderr, "ftdi_set_baudrate() failed\n"); 956 | return (res); 957 | } 958 | 959 | res = ftdi_write_data_set_chunksize(&fc, BUFLEN_MAX); 960 | if (res < 0) { 961 | fprintf(stderr, "ftdi_write_data_set_chunksize() failed\n"); 962 | return (res); 963 | } 964 | 965 | /* Reducing latency to 1 ms for BITMODE_SYNCBB is crucial! */ 966 | res = ftdi_set_latency_timer(&fc, 1); 967 | if (res < 0) { 968 | fprintf(stderr, "ftdi_set_latency_timer() failed\n"); 969 | return (res); 970 | } 971 | 972 | res = ftdi_set_bitmode(&fc, USB_TCK | USB_TMS | USB_TDI, 973 | BITMODE_BITBANG); 974 | if (res < 0) { 975 | fprintf(stderr, "ftdi_set_bitmode() failed\n"); 976 | return (EXIT_FAILURE); 977 | } 978 | if (global_debug) 979 | fprintf(stderr, "Returning from setup_usb()\n"); 980 | 981 | return (0); 982 | } 983 | 984 | 985 | static int 986 | shutdown_usb(void) 987 | { 988 | int res; 989 | 990 | /* Clean up */ 991 | res = set_port_mode(PORT_MODE_UART); 992 | if (res < 0) { 993 | fprintf(stderr, "ftdi_disable_bitbang() failed\n"); 994 | return (res); 995 | } 996 | 997 | res = ftdi_set_latency_timer(&fc, 20); 998 | if (res < 0) { 999 | fprintf(stderr, "ftdi_set_latency_timer() failed\n"); 1000 | return (res); 1001 | } 1002 | 1003 | #ifdef __linux__ 1004 | if (fc.usb_dev != NULL) { 1005 | res = libusb_release_interface(fc.usb_dev, fc.interface); 1006 | if (res < 0) { 1007 | fprintf(stderr, "release interface failed %d\n", res); 1008 | return EXIT_FAILURE; 1009 | } 1010 | /* libusb_attach_kernel_driver is only available on Linux. */ 1011 | if (fc.module_detach_mode == AUTO_DETACH_SIO_MODULE) { 1012 | res = libusb_attach_kernel_driver(fc.usb_dev, fc.interface); 1013 | if( res != 0) 1014 | fprintf(stderr, "detach error %d\n", res); 1015 | } 1016 | } 1017 | #endif 1018 | res = ftdi_usb_close(&fc); 1019 | ftdi_deinit(&fc); 1020 | 1021 | #ifdef __APPLE__ 1022 | uid_t uid=getuid(), euid=geteuid(); 1023 | if (uid<0 || uid!=euid) { 1024 | system("/sbin/kextload" 1025 | " -bundle-id com.FTDI.driver.FTDIUSBSerialDriver"); 1026 | system("/sbin/kextload" 1027 | " -bundle-id com.apple.driver.AppleUSBFTDI"); 1028 | } 1029 | #endif 1030 | 1031 | return (0); 1032 | } 1033 | #endif /* !WIN32 */ 1034 | 1035 | 1036 | static void 1037 | set_tms_tdi(int tms, int tdi) 1038 | { 1039 | int val = 0; 1040 | 1041 | if (cable_hw == CABLE_HW_USB) { 1042 | if (tms) 1043 | val |= USB_TMS; 1044 | if (tdi) 1045 | val |= USB_TDI; 1046 | txbuf[txpos++] = val; 1047 | txbuf[txpos++] = val | USB_TCK; 1048 | } else { /* PPI */ 1049 | if (tms) 1050 | val |= PPI_TMS; 1051 | if (tdi) 1052 | val |= PPI_TDI; 1053 | txbuf[txpos++] = val; 1054 | txbuf[txpos++] = val | PPI_TCK; 1055 | } 1056 | 1057 | if (txpos > sizeof(txbuf)) { 1058 | fprintf(stderr, "txbuf overflow\n"); 1059 | if (cable_hw == CABLE_HW_USB) 1060 | shutdown_usb(); 1061 | exit(EXIT_FAILURE); 1062 | } 1063 | } 1064 | 1065 | 1066 | static int 1067 | send_generic(int bits, char *tdi, char *tdo, char *mask) 1068 | { 1069 | int res, i, bitpos, tdomask, tdoval, maskval, val = 0, txval = 0; 1070 | int rxpos, rxlen; 1071 | 1072 | if (cable_hw == CABLE_HW_USB) 1073 | tdomask = USB_TDO; 1074 | else 1075 | tdomask = PPI_TDO; 1076 | 1077 | i = strlen(tdi); 1078 | if (i != (bits + 3) / 4) { 1079 | fprintf(stderr, "send_generic(): bitcount and tdi " 1080 | "data length do not match\n"); 1081 | return (EXIT_FAILURE); 1082 | } 1083 | if (tdo != NULL && strlen(tdo) != i) { 1084 | if (mask != NULL && strlen(mask) != i) { 1085 | fprintf(stderr, "send_generic(): tdi, tdo and mask " 1086 | "must be of same length\n"); 1087 | return (EXIT_FAILURE); 1088 | } 1089 | fprintf(stderr, "send_generic(): tdi and tdo " 1090 | "must be of same length\n"); 1091 | return (EXIT_FAILURE); 1092 | } 1093 | 1094 | if (cur_s == DRPAUSE || cur_s == IRPAUSE ) { 1095 | /* Move from *PAUSE to *EXIT2 state */ 1096 | set_tms_tdi(1, 0); 1097 | } 1098 | 1099 | /* Move from *CAPTURE or *EXIT2 to *SHIFT state */ 1100 | set_tms_tdi(0, 0); 1101 | 1102 | /* Set up receive index / length */ 1103 | rxpos = txpos + 2; 1104 | rxlen = bits; 1105 | 1106 | for (bitpos = 0; bits > 0; bits--) { 1107 | if (bitpos == 0) { 1108 | i--; 1109 | val = tdi[i]; 1110 | if (val >= '0' && val <= '9') 1111 | val = val - '0'; 1112 | else if (val >= 'A' && val <= 'F') 1113 | val = val + 10 - 'A'; 1114 | else { 1115 | fprintf(stderr, "send_generic():" 1116 | "TDI data not in hex format\n"); 1117 | return (EXIT_FAILURE); 1118 | } 1119 | } 1120 | 1121 | txval = val & 0x1; 1122 | if (bits > 1) 1123 | set_tms_tdi(0, txval); 1124 | else 1125 | set_tms_tdi(1, txval); 1126 | 1127 | val = val >> 1; 1128 | bitpos = (bitpos + 1) & 0x3; 1129 | } 1130 | 1131 | /* Move from *EXIT1 to *PAUSE state */ 1132 | set_tms_tdi(0, txval); 1133 | 1134 | /* Send / receive data on JTAG port */ 1135 | res = commit(0); 1136 | 1137 | /* Translate received bitstream into hex, apply mask, store in tdi */ 1138 | if (port_mode == PORT_MODE_SYNC) { 1139 | if (mask != NULL) 1140 | mask += strlen(tdi); 1141 | if (tdo != NULL) 1142 | tdo += strlen(tdi); 1143 | tdi += strlen(tdi); 1144 | val = 0; 1145 | for (i = rxpos, bits = 0; bits < rxlen; i += 2) { 1146 | val += (((txbuf[i] & tdomask) != 0) << (bits & 0x3)); 1147 | bits++; 1148 | if ((bits & 0x3) == 0 || bits == rxlen) { 1149 | if (mask != NULL) { 1150 | /* Apply mask to received data */ 1151 | mask--; 1152 | maskval = *mask; 1153 | if (maskval >= '0' && maskval <= '9') 1154 | maskval = maskval - '0'; 1155 | else if (maskval >= 'A' && 1156 | maskval <= 'F') 1157 | maskval = maskval + 10 - 'A'; 1158 | val &= maskval; 1159 | /* Apply mask to expected TDO as well */ 1160 | if (tdo != NULL) { 1161 | tdo--; 1162 | tdoval = *tdo; 1163 | if (tdoval >= '0' && 1164 | tdoval <= '9') 1165 | tdoval = tdoval - '0'; 1166 | else if (tdoval >= 'A' && 1167 | tdoval <= 'F') 1168 | tdoval = 1169 | tdoval + 10 - 'A'; 1170 | tdoval &= maskval; 1171 | if (tdoval < 10) 1172 | *tdo = tdoval + '0'; 1173 | else 1174 | *tdo = 1175 | tdoval - 10 + 'A'; 1176 | } 1177 | } 1178 | tdi--; 1179 | if (val < 10) 1180 | *tdi = val + '0'; 1181 | else 1182 | *tdi = val - 10 + 'A'; 1183 | val = 0; 1184 | } 1185 | } 1186 | } 1187 | 1188 | return (res); 1189 | } 1190 | 1191 | 1192 | static int 1193 | send_dr(int bits, char *tdi, char *tdo, char *mask) 1194 | { 1195 | int res; 1196 | 1197 | if (cur_s != DRPAUSE) { 1198 | fprintf(stderr, "Must be in DRPAUSE on entry to send_dr()!\n"); 1199 | return (EXIT_FAILURE); 1200 | } 1201 | res = send_generic(bits, tdi, tdo, mask); 1202 | cur_s = DRPAUSE; 1203 | return (res); 1204 | } 1205 | 1206 | 1207 | static int 1208 | send_ir(int bits, char *tdi, char *tdo, char *mask) 1209 | { 1210 | int res; 1211 | 1212 | if (cur_s != IRPAUSE) { 1213 | fprintf(stderr, "Must be in IRPAUSE on entry to send_ir()!\n"); 1214 | return (EXIT_FAILURE); 1215 | } 1216 | res = send_generic(bits, tdi, tdo, mask); 1217 | cur_s = IRPAUSE; 1218 | return (res); 1219 | } 1220 | 1221 | 1222 | static int 1223 | commit_usb(void) 1224 | { 1225 | int txchunklen, res, i; 1226 | 1227 | for (i = 0; i < txpos; i += txchunklen) { 1228 | txchunklen = txpos - i; 1229 | if (port_mode == PORT_MODE_SYNC && txchunklen > USB_BUFLEN_SYNC) 1230 | txchunklen = USB_BUFLEN_SYNC; 1231 | #ifdef WIN32 1232 | FT_Write(ftHandle, &txbuf[i], txchunklen, (DWORD *) &res); 1233 | #else 1234 | res = ftdi_write_data(&fc, &txbuf[i], txchunklen); 1235 | #endif 1236 | if (res != txchunklen) { 1237 | fprintf(stderr, "ftdi_write_data() failed\n"); 1238 | return (EXIT_FAILURE); 1239 | } 1240 | 1241 | if (port_mode == PORT_MODE_SYNC) { 1242 | #ifdef WIN32 1243 | FT_Read(ftHandle, &txbuf[i], txchunklen, 1244 | (DWORD *) &res); 1245 | #else 1246 | int rep = 0; 1247 | for (res = 0; res < txchunklen && rep < 8; 1248 | rep++) { 1249 | res += ftdi_read_data(&fc, &txbuf[i], 1250 | txchunklen - res); 1251 | } 1252 | #endif 1253 | if (res != txchunklen) { 1254 | #ifdef WIN32 1255 | fprintf(stderr, "FT_Read() failed: " 1256 | "expected %d, received %d bytes\n", 1257 | txchunklen, res); 1258 | #else 1259 | fprintf(stderr, "ftdi_read_data() failed\n"); 1260 | #endif 1261 | return (EXIT_FAILURE); 1262 | } 1263 | } 1264 | } 1265 | txpos = 0; 1266 | 1267 | /* Schedule CBUS LED blinking */ 1268 | i = ms_uptime(); 1269 | if (i - last_ledblink_ms >= LED_BLINK_RATE) { 1270 | last_ledblink_ms += LED_BLINK_RATE; 1271 | need_led_blink = 1; 1272 | } 1273 | 1274 | return (0); 1275 | } 1276 | 1277 | 1278 | #ifdef USE_PPI 1279 | static int 1280 | commit_ppi(void) 1281 | { 1282 | int i, val; 1283 | 1284 | for (i = 0; i < txpos; i++) { 1285 | val = txbuf[i]; 1286 | if (port_mode == PORT_MODE_SYNC && !(i & 1)) { 1287 | ioctl(ppi, PPIGSTATUS, &txbuf[i]); 1288 | } 1289 | ioctl(ppi, PPISDATA, &val); 1290 | } 1291 | 1292 | txpos = 0; 1293 | return (0); 1294 | } 1295 | #endif 1296 | 1297 | 1298 | static int 1299 | commit(int force) 1300 | { 1301 | 1302 | if (txpos == 0 || (!force && port_mode != PORT_MODE_SYNC && 1303 | txpos < sizeof(txbuf) / 2)) 1304 | return (0); 1305 | 1306 | #ifdef USE_PPI 1307 | if (cable_hw == CABLE_HW_PPI) 1308 | return (commit_ppi()); 1309 | #endif 1310 | if (cable_hw == CABLE_HW_USB) 1311 | return (commit_usb()); 1312 | else 1313 | return (EINVAL); 1314 | } 1315 | 1316 | 1317 | static int 1318 | str2tapstate(char *str) 1319 | { 1320 | int i; 1321 | 1322 | for (i = 0; tap_statetable[i].state_str != NULL; i++) { 1323 | if (strcmp(str, tap_statetable[i].state_str) == 0) 1324 | break; 1325 | } 1326 | return (tap_statetable[i].state_id); 1327 | } 1328 | 1329 | 1330 | static void 1331 | set_state(int tgt_s) { 1332 | int i, res = 0; 1333 | 1334 | switch (tgt_s) { 1335 | case RESET: 1336 | for (i = 0; i < 6; i++) 1337 | set_tms_tdi(1, 0); 1338 | break; 1339 | 1340 | case IDLE: 1341 | switch (cur_s) { 1342 | case RESET: 1343 | case DRUPDATE: 1344 | case IRUPDATE: 1345 | case IDLE: 1346 | set_tms_tdi(0, 0); 1347 | break; 1348 | 1349 | case UNDEFINED: 1350 | set_state(RESET); 1351 | set_state(IDLE); 1352 | break; 1353 | 1354 | case DRPAUSE: 1355 | set_state(DREXIT2); 1356 | set_state(DRUPDATE); 1357 | set_state(IDLE); 1358 | break; 1359 | 1360 | case IRPAUSE: 1361 | set_state(IREXIT2); 1362 | set_state(IRUPDATE); 1363 | set_state(IDLE); 1364 | break; 1365 | 1366 | default: 1367 | res = -1; 1368 | } 1369 | break; 1370 | 1371 | case DRSELECT: 1372 | switch (cur_s) { 1373 | case IDLE: 1374 | case DRUPDATE: 1375 | case IRUPDATE: 1376 | set_tms_tdi(1, 0); 1377 | break; 1378 | 1379 | default: 1380 | res = -1; 1381 | } 1382 | break; 1383 | 1384 | case DRCAPTURE: 1385 | switch (cur_s) { 1386 | case DRSELECT: 1387 | set_tms_tdi(0, 0); 1388 | break; 1389 | 1390 | case IDLE: 1391 | set_state(DRSELECT); 1392 | set_state(DRCAPTURE); 1393 | break; 1394 | 1395 | case IRPAUSE: 1396 | set_state(IDLE); 1397 | set_state(DRSELECT); 1398 | set_state(DRCAPTURE); 1399 | break; 1400 | 1401 | default: 1402 | res = -1; 1403 | } 1404 | break; 1405 | 1406 | case DREXIT1: 1407 | switch (cur_s) { 1408 | case DRCAPTURE: 1409 | set_tms_tdi(1, 0); 1410 | break; 1411 | 1412 | default: 1413 | res = -1; 1414 | } 1415 | break; 1416 | 1417 | case DRPAUSE: 1418 | switch (cur_s) { 1419 | case DREXIT1: 1420 | set_tms_tdi(0, 0); 1421 | break; 1422 | 1423 | case IDLE: 1424 | set_state(DRSELECT); 1425 | set_state(DRCAPTURE); 1426 | set_state(DREXIT1); 1427 | set_state(DRPAUSE); 1428 | break; 1429 | 1430 | case IRPAUSE: 1431 | set_state(IREXIT2); 1432 | set_state(IRUPDATE); 1433 | set_state(DRSELECT); 1434 | set_state(DRCAPTURE); 1435 | set_state(DREXIT1); 1436 | set_state(DRPAUSE); 1437 | break; 1438 | 1439 | case DRPAUSE: 1440 | break; 1441 | 1442 | default: 1443 | res = -1; 1444 | } 1445 | break; 1446 | 1447 | case DREXIT2: 1448 | switch (cur_s) { 1449 | case DRPAUSE: 1450 | set_tms_tdi(1, 0); 1451 | break; 1452 | 1453 | default: 1454 | res = -1; 1455 | } 1456 | break; 1457 | 1458 | case DRUPDATE: 1459 | switch (cur_s) { 1460 | case DREXIT2: 1461 | set_tms_tdi(1, 0); 1462 | break; 1463 | 1464 | default: 1465 | res = -1; 1466 | } 1467 | break; 1468 | 1469 | case IRSELECT: 1470 | switch (cur_s) { 1471 | case DRSELECT: 1472 | set_tms_tdi(1, 0); 1473 | break; 1474 | 1475 | default: 1476 | res = -1; 1477 | } 1478 | break; 1479 | 1480 | case IRCAPTURE: 1481 | switch (cur_s) { 1482 | case IRSELECT: 1483 | set_tms_tdi(0, 0); 1484 | break; 1485 | 1486 | case IDLE: 1487 | set_state(DRSELECT); 1488 | set_state(IRSELECT); 1489 | set_state(IRCAPTURE); 1490 | break; 1491 | 1492 | case DRPAUSE: 1493 | set_state(DREXIT2); 1494 | set_state(DRUPDATE); 1495 | set_state(DRSELECT); 1496 | set_state(IRSELECT); 1497 | set_state(IRCAPTURE); 1498 | break; 1499 | 1500 | default: 1501 | res = -1; 1502 | } 1503 | break; 1504 | 1505 | case IREXIT1: 1506 | switch (cur_s) { 1507 | case IRCAPTURE: 1508 | set_tms_tdi(1, 0); 1509 | break; 1510 | 1511 | default: 1512 | res = -1; 1513 | } 1514 | break; 1515 | 1516 | case IRPAUSE: 1517 | switch (cur_s) { 1518 | case IREXIT1: 1519 | set_tms_tdi(0, 0); 1520 | break; 1521 | 1522 | case IDLE: 1523 | set_state(DRSELECT); 1524 | set_state(IRSELECT); 1525 | set_state(IRCAPTURE); 1526 | set_state(IREXIT1); 1527 | set_state(IRPAUSE); 1528 | break; 1529 | 1530 | case DRPAUSE: 1531 | set_state(DREXIT2); 1532 | set_state(DRUPDATE); 1533 | set_state(DRSELECT); 1534 | set_state(IRSELECT); 1535 | set_state(IRCAPTURE); 1536 | set_state(IREXIT1); 1537 | set_state(IRPAUSE); 1538 | break; 1539 | 1540 | case IRPAUSE: 1541 | break; 1542 | 1543 | default: 1544 | res = -1; 1545 | } 1546 | break; 1547 | 1548 | case IREXIT2: 1549 | switch (cur_s) { 1550 | case IRPAUSE: 1551 | set_tms_tdi(1, 0); 1552 | break; 1553 | 1554 | default: 1555 | res = -1; 1556 | } 1557 | break; 1558 | 1559 | case IRUPDATE: 1560 | switch (cur_s) { 1561 | case IREXIT2: 1562 | set_tms_tdi(1, 0); 1563 | break; 1564 | 1565 | default: 1566 | res = -1; 1567 | } 1568 | break; 1569 | 1570 | default: 1571 | res = -1; 1572 | } 1573 | 1574 | if (res) { 1575 | fprintf(stderr, "Don't know how to proceed: %s -> %s\n", 1576 | STATE2STR(cur_s), STATE2STR(tgt_s)); 1577 | if (cable_hw == CABLE_HW_USB) 1578 | shutdown_usb(); 1579 | exit(EXIT_FAILURE); 1580 | } 1581 | 1582 | cur_s = tgt_s; 1583 | } 1584 | 1585 | 1586 | static int 1587 | exec_svf_tokenized(int tokc, char *tokv[]) 1588 | { 1589 | static int last_sdr = PORT_MODE_UNKNOWN; 1590 | int cmd, i, res = 0; 1591 | int repeat = 1, delay_ms = 0; 1592 | 1593 | if (global_debug) { 1594 | for (i= 0; i< tokc; i++) { 1595 | printf("[d] exec_svf_tokenized - %d got token: %s\n", i, tokv[i]); 1596 | } 1597 | } 1598 | for (i = 0; svf_cmdtable[i].cmd_str != NULL; i++) { 1599 | if (strcmp(tokv[0], svf_cmdtable[i].cmd_str) == 0) 1600 | break; 1601 | } 1602 | 1603 | cmd = svf_cmdtable[i].cmd_id; 1604 | if (global_debug) 1605 | printf("[d] exec_svf_tokenized - using command id: %d\n", cmd); 1606 | switch (cmd) { 1607 | case SVF_SDR: 1608 | case SVF_SIR: 1609 | if (tokc == 4) { 1610 | if (cmd == SVF_SDR && last_sdr == PORT_MODE_ASYNC) 1611 | set_port_mode(PORT_MODE_ASYNC); 1612 | tokv[5] = NULL; 1613 | tokv[7] = NULL; 1614 | if (cmd == SVF_SDR) 1615 | last_sdr = PORT_MODE_ASYNC; 1616 | } else if (tokc == 6 || tokc == 8) { 1617 | set_port_mode(PORT_MODE_SYNC); 1618 | if (tokc == 5) 1619 | tokv[7] = NULL; 1620 | if (cmd == SVF_SDR) 1621 | last_sdr = PORT_MODE_SYNC; 1622 | } else { 1623 | res = EXIT_FAILURE; 1624 | break; 1625 | } 1626 | if (cmd == SVF_SDR) { 1627 | set_state(DRPAUSE); 1628 | res = send_dr(atoi(tokv[1]), tokv[3], tokv[5], tokv[7]); 1629 | } else { 1630 | set_state(IRPAUSE); 1631 | res = send_ir(atoi(tokv[1]), tokv[3], tokv[5], tokv[7]); 1632 | } 1633 | if (res) 1634 | break; 1635 | if ((tokc == 6 || tokc ==8 ) && opt_info) { 1636 | if (strlen(tokv[3]) == 8 && strlen(tokv[5]) == 8 && 1637 | strcmp(tokv[7], "FFFFFFFF") == 0) 1638 | { 1639 | break; 1640 | } 1641 | } 1642 | if ((tokc == 6 || tokc == 8) && strcmp(tokv[3], tokv[5]) != 0) { 1643 | if (!force_prog) { 1644 | if (strlen(tokv[3]) == 8 && strlen(tokv[5]) == 8 && 1645 | strcmp(tokv[7], "FFFFFFFF") == 0 && 1646 | cmp_chip_ids(tokv[3], tokv[5]) == 0) 1647 | return (ENODEV); 1648 | fprintf(stderr, "Received and expected data " 1649 | "do not match!\n"); 1650 | if (tokc == 6) 1651 | fprintf(stderr, "TDO: %s Expected: %s\n", 1652 | tokv[3], tokv[5]); 1653 | if (tokc == 8) 1654 | fprintf(stderr, "TDO: %s Expected: %s " 1655 | "mask: %s\n", tokv[3], tokv[5], tokv[7]); 1656 | res = EXIT_FAILURE; 1657 | } else { 1658 | fprintf(stderr,"Forcing the programming. Hope you know what you're doing!\n"); 1659 | } 1660 | } 1661 | break; 1662 | 1663 | case SVF_STATE: 1664 | set_state(str2tapstate(tokv[1])); 1665 | res = commit(0); 1666 | break; 1667 | 1668 | case SVF_RUNTEST: 1669 | for (i = 2; i < tokc; i += 2) { 1670 | if (strcmp(tokv[i + 1], "TCK") == 0) { 1671 | repeat = atoi(tokv[i]); 1672 | if (repeat < 1 || repeat > 1000) { 1673 | fprintf(stderr, 1674 | "Unexpected token: %s\n", 1675 | tokv[i]); 1676 | res = EXIT_FAILURE; 1677 | break; 1678 | } 1679 | } else if (strcmp(tokv[i + 1], "SEC") == 0) { 1680 | float f; 1681 | sscanf(tokv[i], "%f", &f); 1682 | delay_ms = (f + 0.0005) * 1000; 1683 | if (delay_ms < 1 || delay_ms > 120000) { 1684 | fprintf(stderr, 1685 | "Unexpected token: %s\n", 1686 | tokv[i]); 1687 | res = EXIT_FAILURE; 1688 | break; 1689 | } 1690 | /* Silently reduce insanely long waits */ 1691 | if (delay_ms > 3000) 1692 | delay_ms = 3000; 1693 | } else { 1694 | fprintf(stderr, "Unexpected token: %s\n", 1695 | tokv[i + 1]); 1696 | res = EXIT_FAILURE; 1697 | break; 1698 | } 1699 | } 1700 | set_state(str2tapstate(tokv[1])); 1701 | i = delay_ms * (USB_BAUDS / 2000); 1702 | #ifdef USE_PPI 1703 | /* libftdi is relatively slow in sync mode on FreeBSD */ 1704 | if (port_mode == PORT_MODE_SYNC && i > USB_BUFLEN_SYNC / 2) 1705 | i /= 2; 1706 | #endif 1707 | if (i > repeat) 1708 | repeat = i; 1709 | for (i = 0; i < repeat; i++) { 1710 | txbuf[txpos++] = 0; 1711 | txbuf[txpos++] = USB_TCK; 1712 | if (txpos >= sizeof(txbuf) / 2) { 1713 | commit(0); 1714 | if (need_led_blink) 1715 | set_port_mode(port_mode); 1716 | } 1717 | } 1718 | break; 1719 | 1720 | case SVF_HDR: 1721 | case SVF_HIR: 1722 | case SVF_TDR: 1723 | case SVF_TIR: 1724 | if (tokc != 2 || strcmp(tokv[1], "0") != 0) 1725 | res = EINVAL; 1726 | break; 1727 | 1728 | case SVF_ENDDR: 1729 | if (tokc != 2 || 1730 | (strcmp(tokv[1], "DRPAUSE") != 0 && 1731 | strcmp(tokv[1], "IDLE") != 0)) 1732 | res = EINVAL; 1733 | break; 1734 | 1735 | case SVF_ENDIR: 1736 | if (tokc != 2 || 1737 | (strcmp(tokv[1], "IRPAUSE") != 0 && 1738 | strcmp(tokv[1], "IDLE") != 0)) 1739 | res = EINVAL; 1740 | break; 1741 | 1742 | case SVF_FREQUENCY: 1743 | /* Silently ignored. */ 1744 | break; 1745 | 1746 | default: 1747 | res = EOPNOTSUPP; 1748 | } 1749 | 1750 | return (res); 1751 | } 1752 | 1753 | 1754 | enum jed_states { 1755 | JED_INIT, JED_PACK_KNOWN, JED_SIZE_KNOWN, JED_PROG_INITIATED, 1756 | JED_FUSES, JED_FUSES_DONE, JED_SED_CRC, JED_HAVE_SED_CRC, JED_USER_SIG 1757 | }; 1758 | 1759 | enum jed_target { 1760 | JED_TGT_SRAM, JED_TGT_FLASH, JED_TGT_UNKNOWN 1761 | }; 1762 | 1763 | static struct jed_devices { 1764 | char *name; 1765 | int id; 1766 | int fuses; 1767 | int col_width; 1768 | int row_width; 1769 | } jed_devices[] = { 1770 | { 1771 | .name = "LFXP2-5E", 1772 | .id = 0x01299043, 1773 | .fuses = 1236476, 1774 | .col_width = 638, 1775 | .row_width = 1938, 1776 | }, 1777 | { 1778 | .name = "LFXP2-8E", 1779 | .id = 0x0129A043, 1780 | .fuses = 1954736, 1781 | .col_width = 772, 1782 | .row_width= 2532, 1783 | }, 1784 | { 1785 | .name = "LFXP2-17E", 1786 | .id = 0x0129B043, 1787 | .fuses = 3627704, 1788 | .col_width = 2188, 1789 | .row_width = 1658, 1790 | }, 1791 | { 1792 | .name = "LFXP2-30E", 1793 | .id = 0x0129D043, 1794 | .fuses = 5954320, 1795 | .col_width = 2644, 1796 | .row_width = 2532, 1797 | }, 1798 | { 1799 | .name = "LFXP2-40E", 1800 | .id = 0x0129E043, 1801 | .fuses = 8304368, 1802 | .col_width = 3384, 1803 | .row_width = 2454, 1804 | }, 1805 | { 1806 | .name = "LFE5U-12F", 1807 | .id = 0x21111043, 1808 | .fuses = 5681848, 1809 | .col_width = 592, 1810 | .row_width = 7562, 1811 | }, 1812 | { 1813 | .name = "LFE5U-25F", 1814 | .id = 0x41111043, 1815 | .fuses = 5681848, 1816 | .col_width = 592, 1817 | .row_width = 7562, 1818 | }, 1819 | { 1820 | .name = "LFE5U-45F", 1821 | .id = 0x41112043, 1822 | .fuses = 10208312, 1823 | .col_width = 848, 1824 | .row_width = 9470, 1825 | }, 1826 | { 1827 | .name = "LFE5U-85F", 1828 | .id = 0x41113043, 1829 | .fuses = 19244856, 1830 | .col_width = 1136, 1831 | .row_width = 13294, 1832 | }, 1833 | { 1834 | .name = "LFE5UM-25F", 1835 | .id = 0x01111043, 1836 | .fuses = 5681848, 1837 | .col_width = 592, 1838 | .row_width = 7562, 1839 | }, 1840 | { 1841 | .name = "LFE5UM-45F", 1842 | .id = 0x01112043, 1843 | .fuses = 10208312, 1844 | .col_width = 848, 1845 | .row_width = 9470, 1846 | }, 1847 | { 1848 | .name = "LFE5UM-85F", 1849 | .id = 0x01113043, 1850 | .fuses = 19244856, 1851 | .col_width = 1136, 1852 | .row_width = 13294, 1853 | }, 1854 | {NULL, 0, 0} 1855 | }; 1856 | 1857 | 1858 | static int 1859 | cmp_chip_ids(char *got, char *exp) 1860 | { 1861 | int got_id, exp_id; 1862 | struct jed_devices *got_jd, *exp_jd; 1863 | 1864 | sscanf(got, "%x", &got_id); 1865 | sscanf(exp, "%x", &exp_id); 1866 | 1867 | for (got_jd = jed_devices; got_jd->name != NULL; got_jd++) 1868 | if (got_jd->id == got_id) 1869 | break; 1870 | for (exp_jd = jed_devices; exp_jd->name != NULL; exp_jd++) 1871 | if (exp_jd->id == exp_id) 1872 | break; 1873 | 1874 | if (exp_jd->name == NULL && got_jd->name == NULL) 1875 | return (EXIT_FAILURE); 1876 | 1877 | fprintf(stderr, "\nFound "); 1878 | if (got_jd->name) 1879 | fprintf(stderr, "%s", got_jd->name); 1880 | else 1881 | fprintf(stderr, "unknown (%s)", got); 1882 | fprintf(stderr, " device, but the bitstream is for "); 1883 | if (exp_jd->name) 1884 | fprintf(stderr, "%s", exp_jd->name); 1885 | else 1886 | fprintf(stderr, "unknown (%s)", exp); 1887 | fprintf(stderr, ".\n"); 1888 | return (0); 1889 | } 1890 | 1891 | /* 1892 | * Parse a Lattice XP2 JEDEC file and convert it into a SVF stream stored 1893 | * in a contiguos chunk of memory. If parsing is sucessfull proceed with 1894 | * calling exec_svf_mem(). 1895 | */ 1896 | static int 1897 | exec_jedec_file(char *path, int target, int debug) 1898 | { 1899 | char *inbuf, *outbuf, *incp, *outcp; 1900 | char tmpbuf[2048]; 1901 | FILE *fd; 1902 | long flen; 1903 | int jed_state = JED_INIT; 1904 | int jed_dev = -1; 1905 | int i, j, val, row, res; 1906 | 1907 | if (path == NULL) { 1908 | fprintf(stderr, "jedec not file supported for stdin\n"); 1909 | return (EXIT_FAILURE); 1910 | } 1911 | 1912 | fd = fopen(path, "r"); 1913 | if (fd == NULL) { 1914 | fprintf(stderr, "open(%s) failed\n", path); 1915 | return (EXIT_FAILURE); 1916 | } 1917 | 1918 | fseek(fd, 0, SEEK_END); 1919 | flen = ftell(fd); 1920 | fseek(fd, 0, SEEK_SET); 1921 | 1922 | inbuf = malloc(flen); 1923 | outbuf = malloc(flen * 2); /* XXX rough estimate */ 1924 | if (inbuf == NULL || outbuf == NULL) { 1925 | fprintf(stderr, "malloc(%ld) failed\n", flen); 1926 | return (EXIT_FAILURE); 1927 | } 1928 | 1929 | incp = inbuf; 1930 | outcp = outbuf; 1931 | while (!feof(fd) && fgets(incp, flen, fd) != NULL) { 1932 | /* Trim CR / LF chars from the tail of the line */ 1933 | incp += strlen(incp) - 1; 1934 | while (incp >= inbuf && (*incp == 10 || *incp == 13)) 1935 | incp--; 1936 | incp[1] = 0; 1937 | 1938 | /* Is this the first line of an "L" command? */ 1939 | if (*inbuf == 'L') { 1940 | if (jed_state < JED_PROG_INITIATED) { 1941 | fprintf(stderr, "Invalid bitstream file\n"); 1942 | return (EXIT_FAILURE); 1943 | } 1944 | if (jed_state == JED_PROG_INITIATED) 1945 | jed_state = JED_FUSES; 1946 | else 1947 | jed_state = JED_SED_CRC; 1948 | incp = inbuf; 1949 | continue; 1950 | } 1951 | 1952 | /* Does the command terminate on this line? */ 1953 | if (*incp != '*') { 1954 | incp++; 1955 | continue; 1956 | } else 1957 | *incp = 0; 1958 | 1959 | /* Is this the SED_CRC fuses string? */ 1960 | if (jed_state == JED_SED_CRC) { 1961 | val = 0; 1962 | for (i = 32, j = 0; i > 0; i--, val <<= 1) { 1963 | val += (inbuf[i - 1] == '1'); 1964 | if ((i & 0x3) == 1) { 1965 | if (val < 10) 1966 | tmpbuf[j++] = '0' + 1967 | val; 1968 | else 1969 | tmpbuf[j++] = 'A' + 1970 | val - 10; 1971 | val = 0; 1972 | } 1973 | } 1974 | tmpbuf[j++] = 0; 1975 | if (strlen(tmpbuf) != 8) { 1976 | fprintf(stderr, "Invalid bitstream file\n"); 1977 | return (EXIT_FAILURE); 1978 | } 1979 | jed_state = JED_HAVE_SED_CRC; 1980 | } 1981 | 1982 | /* Is this the main fuses string? */ 1983 | if (jed_state == JED_FUSES) { 1984 | 1985 | outcp += sprintf(outcp, "\n\n! Program Fuse Map\n\n"); 1986 | *outcp++ = 0; 1987 | outcp += sprintf(outcp, "SIR 8 TDI (21);\n"); 1988 | *outcp++ = 0; 1989 | outcp += sprintf(outcp, 1990 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 1991 | *outcp++ = 0; 1992 | 1993 | if (target == JED_TGT_SRAM) { 1994 | outcp += sprintf(outcp, 1995 | "SIR 8 TDI (67);\n"); 1996 | *outcp++ = 0; 1997 | } 1998 | 1999 | for (incp = inbuf, row = 1; 2000 | row <= jed_devices[jed_dev].row_width; row++) { 2001 | if (target == JED_TGT_FLASH) { 2002 | outcp += sprintf(outcp, 2003 | "SIR 8 TDI (67);\n"); 2004 | *outcp++ = 0; 2005 | } 2006 | 2007 | val = 0; 2008 | for (i = jed_devices[jed_dev].col_width, j = 0; 2009 | i > 0; i--, val <<= 1) { 2010 | val += (incp[i - 1] == '1'); 2011 | if ((i & 0x3) == 1) { 2012 | if (val < 10) 2013 | tmpbuf[j++] = '0' + 2014 | val; 2015 | else 2016 | tmpbuf[j++] = 'A' + 2017 | val - 10; 2018 | val = 0; 2019 | } 2020 | } 2021 | tmpbuf[j++] = 0; 2022 | incp += jed_devices[jed_dev].col_width; 2023 | 2024 | outcp += sprintf(outcp, 2025 | "! Shift in Data Row = %d\n", row); 2026 | *outcp++ = 0; 2027 | outcp += sprintf(outcp, 2028 | "SDR %d TDI (%s);\n", 2029 | jed_devices[jed_dev].col_width, tmpbuf); 2030 | *outcp++ = 0; 2031 | if (target == JED_TGT_FLASH) { 2032 | outcp += sprintf(outcp, 2033 | "RUNTEST IDLE" 2034 | " 3 TCK 1.00E-003 SEC;\n"); 2035 | } else { 2036 | outcp += sprintf(outcp, 2037 | "RUNTEST IDLE 3 TCK;\n"); 2038 | } 2039 | *outcp++ = 0; 2040 | 2041 | if (target == JED_TGT_FLASH) { 2042 | outcp += sprintf(outcp, 2043 | "SIR 8 TDI (52);\n"); 2044 | *outcp++ = 0; 2045 | 2046 | outcp += sprintf(outcp, 2047 | "SDR 1 TDI (0)\n"); 2048 | *outcp++ = 0; 2049 | outcp += sprintf(outcp, 2050 | " TDO (1);\n"); 2051 | *outcp++ = 0; 2052 | } 2053 | } 2054 | 2055 | /* Check that we have consumed all fuse bits */ 2056 | if (strlen(incp) != 0) { 2057 | fprintf(stderr, "Invalid bitstream file\n"); 2058 | return (EXIT_FAILURE); 2059 | } 2060 | 2061 | jed_state++; 2062 | } 2063 | 2064 | /* Is this a comment line? */ 2065 | if (*inbuf == 'N') { 2066 | if (jed_state == JED_INIT) { 2067 | outcp += sprintf(outcp, "! %s\n", inbuf); 2068 | *outcp++ = 0; 2069 | } 2070 | if (strncmp(inbuf, "NOTE DEVICE NAME:", 17) == 0) { 2071 | incp = &inbuf[18]; 2072 | for (jed_dev = 0; 2073 | jed_devices[jed_dev].name != NULL; 2074 | jed_dev++) { 2075 | if (strncmp(jed_devices[jed_dev].name, 2076 | incp, strlen( 2077 | jed_devices[jed_dev].name)) == 0) 2078 | break; 2079 | } 2080 | if (jed_devices[jed_dev].name == NULL) { 2081 | fprintf(stderr, "Bitstream for " 2082 | "unsupported target: %s\n", incp); 2083 | return (EXIT_FAILURE); 2084 | } 2085 | } 2086 | incp = inbuf; 2087 | continue; 2088 | } 2089 | 2090 | /* Packaging line? */ 2091 | if (*inbuf == 'Q') { 2092 | i = atoi(&inbuf[2]); 2093 | if (inbuf[1] == 'P') { 2094 | if (jed_dev < 0 || jed_state != JED_INIT) { 2095 | fprintf(stderr, 2096 | "Invalid bitstream file\n"); 2097 | return (EXIT_FAILURE); 2098 | } 2099 | jed_state = JED_PACK_KNOWN; 2100 | } else if (inbuf[1] == 'F') { 2101 | if (jed_dev < 0 || jed_state != JED_PACK_KNOWN 2102 | || jed_devices[jed_dev].fuses != i) { 2103 | fprintf(stderr, 2104 | "Invalid bitstream file\n"); 2105 | return (EXIT_FAILURE); 2106 | } 2107 | jed_state = JED_SIZE_KNOWN; 2108 | } else { 2109 | fprintf(stderr, "Invalid bitstream file\n"); 2110 | return (EXIT_FAILURE); 2111 | } 2112 | } 2113 | 2114 | /* "F" line? */ 2115 | if (*inbuf == 'F') { 2116 | if (jed_state != JED_SIZE_KNOWN) { 2117 | fprintf(stderr, "Invalid bitstream file\n"); 2118 | return (EXIT_FAILURE); 2119 | } 2120 | jed_state = JED_PROG_INITIATED; 2121 | 2122 | outcp += sprintf(outcp, "\n\n! Check the IDCODE\n\n"); 2123 | *outcp++ = 0; 2124 | outcp += sprintf(outcp, "STATE RESET;\n"); 2125 | *outcp++ = 0; 2126 | outcp += sprintf(outcp, "STATE IDLE;\n"); 2127 | *outcp++ = 0; 2128 | outcp += sprintf(outcp, "SIR 8 TDI (16);\n"); 2129 | *outcp++ = 0; 2130 | outcp += sprintf(outcp, 2131 | "SDR 32 TDI (FFFFFFFF)\n"); 2132 | *outcp++ = 0; 2133 | outcp += sprintf(outcp, " TDO (%08X)\n", 2134 | jed_devices[jed_dev].id); 2135 | *outcp++ = 0; 2136 | outcp += sprintf(outcp, 2137 | " MASK (FFFFFFFF);\n"); 2138 | *outcp++ = 0; 2139 | 2140 | if (target == JED_TGT_SRAM) { 2141 | outcp += sprintf(outcp, 2142 | "\n\n! Program Bscan register\n\n"); 2143 | *outcp++ = 0; 2144 | outcp += sprintf(outcp, 2145 | "SIR 8 TDI (1C);\n"); 2146 | *outcp++ = 0; 2147 | outcp += sprintf(outcp, "STATE DRPAUSE;\n"); 2148 | *outcp++ = 0; 2149 | outcp += sprintf(outcp, "STATE IDLE;\n"); 2150 | *outcp++ = 0; 2151 | 2152 | outcp += sprintf(outcp, 2153 | "\n\n! Enable SRAM programming mode\n\n"); 2154 | *outcp++ = 0; 2155 | outcp += sprintf(outcp, 2156 | "SIR 8 TDI (55);\n"); 2157 | *outcp++ = 0; 2158 | outcp += sprintf(outcp, "RUNTEST IDLE" 2159 | " 3 TCK 1.00E-003 SEC;\n"); 2160 | *outcp++ = 0; 2161 | 2162 | outcp += sprintf(outcp, 2163 | "\n\n! Erase the device\n\n"); 2164 | *outcp++ = 0; 2165 | outcp += sprintf(outcp, 2166 | "SIR 8 TDI (03);\n"); 2167 | *outcp++ = 0; 2168 | outcp += sprintf(outcp, "RUNTEST IDLE" 2169 | " 3 TCK 1.00E-003 SEC;\n"); 2170 | *outcp++ = 0; 2171 | } else { 2172 | outcp += sprintf(outcp, 2173 | "\n\n! Enable XPROGRAM mode\n\n"); 2174 | *outcp++ = 0; 2175 | outcp += sprintf(outcp, 2176 | "SIR 8 TDI (35);\n"); 2177 | *outcp++ = 0; 2178 | outcp += sprintf(outcp, "RUNTEST IDLE" 2179 | " 3 TCK 1.00E-003 SEC;\n"); 2180 | *outcp++ = 0; 2181 | 2182 | outcp += sprintf(outcp, 2183 | "\n\n! Check the Key Protection fuses\n\n"); 2184 | *outcp++ = 0; 2185 | 2186 | outcp += sprintf(outcp, 2187 | "SIR 8 TDI (B2);\n"); 2188 | *outcp++ = 0; 2189 | outcp += sprintf(outcp, "RUNTEST IDLE" 2190 | " 3 TCK 1.00E-003 SEC;\n"); 2191 | *outcp++ = 0; 2192 | outcp += sprintf(outcp, 2193 | "SDR 8 TDI (00)\n"); 2194 | *outcp++ = 0; 2195 | outcp += sprintf(outcp, 2196 | " TDO (00)\n"); 2197 | *outcp++ = 0; 2198 | outcp += sprintf(outcp, 2199 | " MASK (10);\n"); 2200 | *outcp++ = 0; 2201 | 2202 | outcp += sprintf(outcp, 2203 | "SIR 8 TDI (B2);\n"); 2204 | *outcp++ = 0; 2205 | outcp += sprintf(outcp, "RUNTEST IDLE" 2206 | " 3 TCK 1.00E-003 SEC;\n"); 2207 | *outcp++ = 0; 2208 | outcp += sprintf(outcp, 2209 | "SDR 8 TDI (00)\n"); 2210 | *outcp++ = 0; 2211 | outcp += sprintf(outcp, 2212 | " TDO (00)\n"); 2213 | *outcp++ = 0; 2214 | outcp += sprintf(outcp, 2215 | " MASK (40);\n"); 2216 | *outcp++ = 0; 2217 | 2218 | outcp += sprintf(outcp, 2219 | "SIR 8 TDI (B2);\n"); 2220 | *outcp++ = 0; 2221 | outcp += sprintf(outcp, "RUNTEST IDLE" 2222 | " 3 TCK 1.00E-003 SEC;\n"); 2223 | *outcp++ = 0; 2224 | outcp += sprintf(outcp, 2225 | "SDR 8 TDI (00)\n"); 2226 | *outcp++ = 0; 2227 | outcp += sprintf(outcp, 2228 | " TDO (00)\n"); 2229 | *outcp++ = 0; 2230 | outcp += sprintf(outcp, 2231 | " MASK (04);\n"); 2232 | *outcp++ = 0; 2233 | 2234 | outcp += sprintf(outcp, 2235 | "\n\n! Erase the device\n\n"); 2236 | *outcp++ = 0; 2237 | outcp += sprintf(outcp, 2238 | "SIR 8 TDI (03);\n"); 2239 | *outcp++ = 0; 2240 | outcp += sprintf(outcp, "RUNTEST IDLE" 2241 | " 3 TCK 1.20E+002 SEC;\n"); 2242 | *outcp++ = 0; 2243 | 2244 | outcp += sprintf(outcp, 2245 | "SIR 8 TDI (52);\n"); 2246 | *outcp++ = 0; 2247 | outcp += sprintf(outcp, 2248 | "SDR 1 TDI (0)\n"); 2249 | *outcp++ = 0; 2250 | outcp += sprintf(outcp, 2251 | " TDO (1);\n"); 2252 | *outcp++ = 0; 2253 | 2254 | outcp += sprintf(outcp, 2255 | "SIR 8 TDI (B2);\n"); 2256 | *outcp++ = 0; 2257 | outcp += sprintf(outcp, "RUNTEST IDLE" 2258 | " 3 TCK 1.00E-003 SEC;\n"); 2259 | *outcp++ = 0; 2260 | outcp += sprintf(outcp, 2261 | "SDR 8 TDI (00)\n"); 2262 | *outcp++ = 0; 2263 | outcp += sprintf(outcp, 2264 | " TDO (00)\n"); 2265 | *outcp++ = 0; 2266 | outcp += sprintf(outcp, 2267 | " MASK (01);\n"); 2268 | *outcp++ = 0; 2269 | } 2270 | } 2271 | 2272 | /* "U" line? */ 2273 | if (*inbuf == 'U') { 2274 | if (inbuf[1] != 'H' || jed_state != JED_HAVE_SED_CRC) { 2275 | fprintf(stderr, "Invalid bitstream file\n"); 2276 | return (EXIT_FAILURE); 2277 | } 2278 | 2279 | outcp += sprintf(outcp, "\n\n! Program USERCODE\n\n"); 2280 | *outcp++ = 0; 2281 | outcp += sprintf(outcp, "SIR 8 TDI (1A);\n"); 2282 | *outcp++ = 0; 2283 | outcp += sprintf(outcp, 2284 | "SDR 32 TDI (%s);\n", &inbuf[2]); 2285 | *outcp++ = 0; 2286 | outcp += sprintf(outcp, 2287 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 2288 | *outcp++ = 0; 2289 | 2290 | if (target == JED_TGT_FLASH) { 2291 | outcp += sprintf(outcp, 2292 | "\n\n! Read the status bit;\n\n"); 2293 | *outcp++ = 0; 2294 | outcp += sprintf(outcp, 2295 | "SIR 8 TDI (B2);\n"); 2296 | *outcp++ = 0; 2297 | outcp += sprintf(outcp, "RUNTEST IDLE" 2298 | " 3 TCK 1.00E-003 SEC;\n"); 2299 | *outcp++ = 0; 2300 | outcp += sprintf(outcp, 2301 | "SDR 8 TDI (00)\n"); 2302 | *outcp++ = 0; 2303 | outcp += sprintf(outcp, 2304 | " TDO (00)\n"); 2305 | *outcp++ = 0; 2306 | outcp += sprintf(outcp, 2307 | " MASK (01);\n"); 2308 | *outcp++ = 0; 2309 | } 2310 | 2311 | outcp += sprintf(outcp, 2312 | "\n\n! Program and Verify 32 bits SED_CRC\n\n"); 2313 | *outcp++ = 0; 2314 | outcp += sprintf(outcp, "SIR 8 TDI (45);\n"); 2315 | *outcp++ = 0; 2316 | outcp += sprintf(outcp, 2317 | "SDR 32 TDI (%s);\n", tmpbuf); 2318 | *outcp++ = 0; 2319 | outcp += sprintf(outcp, 2320 | "RUNTEST IDLE 3 TCK 1.00E-002 SEC;\n"); 2321 | *outcp++ = 0; 2322 | 2323 | outcp += sprintf(outcp, "SIR 8 TDI (44);\n"); 2324 | *outcp++ = 0; 2325 | outcp += sprintf(outcp, 2326 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2327 | *outcp++ = 0; 2328 | 2329 | outcp += sprintf(outcp, 2330 | "SDR 32 TDI (00000000)\n"); 2331 | *outcp++ = 0; 2332 | outcp += sprintf(outcp, 2333 | " TDO (%s);\n", tmpbuf); 2334 | *outcp++ = 0; 2335 | 2336 | outcp += sprintf(outcp, "SIR 8 TDI (B2);\n"); 2337 | *outcp++ = 0; 2338 | outcp += sprintf(outcp, 2339 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2340 | *outcp++ = 0; 2341 | outcp += sprintf(outcp, "SDR 8 TDI (00)\n"); 2342 | *outcp++ = 0; 2343 | outcp += sprintf(outcp, " TDO (00)\n"); 2344 | *outcp++ = 0; 2345 | outcp += sprintf(outcp, " MASK (01);\n"); 2346 | *outcp++ = 0; 2347 | 2348 | outcp += sprintf(outcp, 2349 | "\n\n! Program DONE bit\n\n"); 2350 | *outcp++ = 0; 2351 | outcp += sprintf(outcp, "SIR 8 TDI (2F);\n"); 2352 | *outcp++ = 0; 2353 | if (target == JED_TGT_FLASH) { 2354 | outcp += sprintf(outcp, "RUNTEST IDLE" 2355 | " 3 TCK 2.00E-001 SEC;\n"); 2356 | } else { 2357 | outcp += sprintf(outcp, "RUNTEST IDLE" 2358 | " 3 TCK;\n"); 2359 | } 2360 | *outcp++ = 0; 2361 | outcp += sprintf(outcp, "SIR 8 TDI (B2);\n"); 2362 | *outcp++ = 0; 2363 | outcp += sprintf(outcp, 2364 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2365 | *outcp++ = 0; 2366 | outcp += sprintf(outcp, "SDR 8 TDI (00)\n"); 2367 | *outcp++ = 0; 2368 | outcp += sprintf(outcp, " TDO (02)\n"); 2369 | *outcp++ = 0; 2370 | outcp += sprintf(outcp, " MASK (03);\n"); 2371 | *outcp++ = 0; 2372 | 2373 | if (target == JED_TGT_FLASH) { 2374 | outcp += sprintf(outcp, 2375 | "\n\n! Verify DONE bit\n\n"); 2376 | *outcp++ = 0; 2377 | outcp += sprintf(outcp, 2378 | "SIR 8 TDI (B2)\n"); 2379 | *outcp++ = 0; 2380 | outcp += sprintf(outcp, 2381 | " TDO (FF)\n"); 2382 | *outcp++ = 0; 2383 | outcp += sprintf(outcp, 2384 | " MASK (04);\n"); 2385 | *outcp++ = 0; 2386 | } 2387 | 2388 | outcp += sprintf(outcp, 2389 | "\n\n! Exit the programming mode\n\n"); 2390 | *outcp++ = 0; 2391 | outcp += sprintf(outcp, "SIR 8 TDI (1E);\n"); 2392 | *outcp++ = 0; 2393 | outcp += sprintf(outcp, 2394 | "RUNTEST IDLE 3 TCK 2.00E-003 SEC;\n"); 2395 | *outcp++ = 0; 2396 | outcp += sprintf(outcp, "SIR 8 TDI (FF);\n"); 2397 | *outcp++ = 0; 2398 | outcp += sprintf(outcp, 2399 | "RUNTEST IDLE 3 TCK 1.00E-003 SEC;\n"); 2400 | *outcp++ = 0; 2401 | outcp += sprintf(outcp, 2402 | "STATE RESET;\n"); 2403 | *outcp++ = 0; 2404 | } 2405 | 2406 | incp = inbuf; 2407 | } 2408 | fclose(fd); 2409 | 2410 | /* Count number of lines in outbuf, store in j */ 2411 | for (i = 0, j = 0; outcp > outbuf; outcp--) 2412 | if (*outcp == 0) 2413 | j++; 2414 | 2415 | if (svf_name) { 2416 | int of; 2417 | 2418 | if (strncmp(svf_name, "-", 1) == 0) 2419 | of = 0; 2420 | else 2421 | of = open(svf_name, O_RDWR | O_CREAT | O_TRUNC, 0644); 2422 | if (of < 0) { 2423 | res = errno; 2424 | goto done; 2425 | } 2426 | res = 0; 2427 | for (i = 0, outcp = outbuf; i < j; i++) { 2428 | write(of, outcp, strlen(outcp)); 2429 | outcp += (strlen(outcp) + 1); 2430 | } 2431 | if (of) 2432 | close(of); 2433 | } else 2434 | res = exec_svf_mem(outbuf, j, debug); 2435 | 2436 | done: 2437 | free(outbuf); 2438 | free(inbuf); 2439 | return (res); 2440 | } 2441 | 2442 | 2443 | #define bitrev(a) ((a & 0x1) << 7) | ((a & 0x2) << 5) | ((a & 0x4) << 3) | ((a & 0x8) << 1) | ((a & 0x10) >> 1) | ((a & 0x20) >> 3) | ((a & 0x40) >> 5) | ((a & 0x80) >> 7) 2444 | 2445 | #define buf_sprintf(p, ...) do { \ 2446 | (p) += sprintf((p), ## __VA_ARGS__); \ 2447 | *(p)++ = 0; \ 2448 | } while (0) 2449 | 2450 | char *exec_svf_line(char *cmdbuf) 2451 | { 2452 | int tokc; 2453 | int lno,i; 2454 | char *tokv[256]; 2455 | int res = 0; 2456 | char *cp; 2457 | char *retbuf=cmdbuf; 2458 | 2459 | char cmdbuf2[]= 2460 | "STATE IDLE;\n" 2461 | "STATE RESET;\n" 2462 | "STATE IDLE;\n\n" 2463 | "SIR 8 TDI (E0);\n" 2464 | "SDR 32 TDI (00000000)\n" 2465 | " TDO (00000000)\n" 2466 | " MASK (FFFFFFFF);\n\n"; 2467 | 2468 | if (global_debug) 2469 | printf("[d] Using following command: %s\n", cmdbuf); 2470 | 2471 | /* Normalize to all upper case letters, separate tokens */ 2472 | tokc = 0; 2473 | tokv[0] = cmdbuf; 2474 | for (cp = cmdbuf; *cp != 0; cp++) { 2475 | if (*cp == ' ') { 2476 | *cp++ = 0; 2477 | tokc++; 2478 | tokv[tokc] = cp; 2479 | } 2480 | *cp = toupper(*cp); 2481 | } 2482 | if (*tokv[tokc] != 0) 2483 | tokc++; 2484 | 2485 | if (global_debug) 2486 | printf("[d] Using following tokenized command: %s\n", cmdbuf); 2487 | 2488 | /* Execute command */ 2489 | res = exec_svf_tokenized(tokc, tokv); 2490 | if (global_debug) { 2491 | printf("[d] exec_svf_tokenized returned %d\n", res); 2492 | printf("[d] got id: %s\n", tokv[3]); 2493 | } 2494 | if (res) { 2495 | if (res != ENODEV) 2496 | fprintf(stderr, "Line %s: %s\n", cmdbuf, 2497 | strerror(res)); 2498 | return (NULL); 2499 | } 2500 | 2501 | cp = cmdbuf; 2502 | 2503 | commit(1); 2504 | 2505 | if (tokc>3) { 2506 | retbuf=tokv[3]; 2507 | } 2508 | return (retbuf); 2509 | } 2510 | 2511 | static int 2512 | exec_info(char *path, int jed_target, int debug) 2513 | { 2514 | int i, ret=0, fsize=0; 2515 | char *idcode; 2516 | char cmds[5][128]={ 2517 | "STATE IDLE", 2518 | "STATE RESET", 2519 | "STATE IDLE", 2520 | "SIR 8 TDI E0", 2521 | "SDR 32 TDI 00000000 TDO 00000000 MASK FFFFFFFF" 2522 | }; 2523 | 2524 | for (i=0; i < 5; i++) { 2525 | idcode=exec_svf_line(cmds[i]); 2526 | if (idcode==NULL) { 2527 | printf("Error sending line: %s\n", cmds[i]); 2528 | return(EXIT_FAILURE); 2529 | } 2530 | } 2531 | printf("FPGA IDCODE: %s\n", idcode); 2532 | if (strcmp(idcode,"41111043")==0) fsize=25; 2533 | if (strcmp(idcode,"21111043")==0) fsize=12; 2534 | if (strcmp(idcode,"41112043")==0) fsize=45; 2535 | if (strcmp(idcode,"41113043")==0) fsize=85; 2536 | printf("FPGA identified SIZE: %d\n", fsize); 2537 | return(0); 2538 | } 2539 | 2540 | 2541 | /* 2542 | * Parse a Lattice ECP5 bitstream file and convert it into a SVF stream, 2543 | * stored in a contiguos chunk of memory. If parsing is sucessfull proceed 2544 | * with calling exec_svf_mem(). 2545 | */ 2546 | static int 2547 | exec_bit_file(char *path, int jed_target, int debug) 2548 | { 2549 | uint8_t *inbuf; 2550 | char *outbuf, *op; 2551 | char *outcp; 2552 | FILE *fd; 2553 | long flen, got; 2554 | uint32_t idcode; 2555 | int i, j, n, addr; 2556 | int row_size = 64000 / 8; 2557 | int hexlen = 50; 2558 | int res; 2559 | size_t slen; 2560 | int is_bit=0; 2561 | 2562 | if (path == NULL) { 2563 | inbuf =(uint8_t *) read_stdin(&slen); 2564 | flen = slen; 2565 | } else { 2566 | fd = fopen(path, "rb"); 2567 | if (fd == NULL) { 2568 | fprintf(stderr, "open(%s) failed\n", path); 2569 | return (EXIT_FAILURE); 2570 | } 2571 | 2572 | fseek(fd, 0, SEEK_END); 2573 | flen = ftell(fd); 2574 | fseek(fd, 0, SEEK_SET); 2575 | inbuf = malloc(flen); 2576 | if (inbuf == NULL) { 2577 | fprintf(stderr, "malloc(%ld) of inbuf failed\n", flen); 2578 | return (EXIT_FAILURE); 2579 | } 2580 | 2581 | got = fread(inbuf, 1, flen, fd); 2582 | if (got != flen) { 2583 | fprintf(stderr, "short read: %ld instead of %ld\n", 2584 | got, flen); 2585 | return (EXIT_FAILURE); 2586 | } 2587 | if (strcasecmp(&path[strlen(path) - 4], ".bit") == 0) { 2588 | is_bit = 1; 2589 | } 2590 | } 2591 | 2592 | outbuf = malloc(flen * 4); /* XXX rough estimate */ 2593 | if (inbuf == NULL || outbuf == NULL) { 2594 | fprintf(stderr, "malloc(%ld) failed\n", flen); 2595 | return (EXIT_FAILURE); 2596 | } 2597 | op = outbuf; 2598 | 2599 | buf_sprintf(op, "STATE IDLE;\n"); 2600 | buf_sprintf(op, "STATE RESET;\n"); 2601 | buf_sprintf(op, "STATE IDLE;\n\n"); 2602 | 2603 | if (input_type==TYPE_BIT || is_bit) { 2604 | /* Search for bitstream preamble and IDCODE markers */ 2605 | for (i = 0, j = 0; i < flen - 32 && i < 2000; i++) 2606 | if (inbuf[i] == 0xbd && inbuf[i + 1] == 0xb3 2607 | && inbuf[i + 10] == 0xe2 && inbuf[i + 11] == 0 2608 | && inbuf[i + 12] == 0 && inbuf[i + 13] == 0) { 2609 | j = i; 2610 | break; 2611 | } 2612 | if (j == 0) { 2613 | fprintf(stderr, 2614 | "can't find IDCODE, invalid bitstream\n"); 2615 | return (EXIT_FAILURE); 2616 | } 2617 | idcode = inbuf[i + 14] << 24; 2618 | idcode += inbuf[i + 15] << 16; 2619 | idcode += inbuf[i + 16] << 8; 2620 | idcode += inbuf[i + 17]; 2621 | 2622 | /* IDCODE_PUB(0xE0): check IDCODE */ 2623 | buf_sprintf(op, "SIR 8 TDI (E0);\n"); 2624 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2625 | buf_sprintf(op, " TDO (%08X)\n", idcode); 2626 | buf_sprintf(op, " MASK (FFFFFFFF);\n\n"); 2627 | } 2628 | 2629 | /* LSC_PRELOAD(0x1C): Program Bscan register */ 2630 | buf_sprintf(op, "SIR 8 TDI (1C);\n"); 2631 | buf_sprintf(op, "SDR 510 TDI (3FFFFFFFFFFFFFF" 2632 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 2633 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);\n\n"); 2634 | 2635 | /* ISC ENABLE(0xC6): Enable SRAM programming mode */ 2636 | buf_sprintf(op, "SIR 8 TDI (C6);\n"); 2637 | buf_sprintf(op, "SDR 8 TDI (00);\n"); 2638 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2639 | 2640 | /* ISC ERASE(0x0e): Erase the SRAM */ 2641 | buf_sprintf(op, "SIR 8 TDI (0e);\n"); 2642 | buf_sprintf(op, "SDR 8 TDI (01);\n"); 2643 | buf_sprintf(op, "RUNTEST IDLE 32 TCK 1.00E-01 SEC;\n\n"); 2644 | 2645 | /* LSC_READ_STATUS(0x3c) */ 2646 | buf_sprintf(op, "SIR 8 TDI (3C);\n"); 2647 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2648 | buf_sprintf(op, " TDO (00000000)\n"); 2649 | buf_sprintf(op, " MASK (0000B000);\n\n"); 2650 | 2651 | if (jed_target == JED_TGT_FLASH) { 2652 | buf_sprintf(op, "STATE RESET;\n"); 2653 | buf_sprintf(op, "STATE IDLE;\n"); 2654 | 2655 | /* BYPASS(0xFF) */ 2656 | buf_sprintf(op, "SIR 8 TDI(FF);\n"); 2657 | buf_sprintf(op, "RUNTEST IDLE 32 TCK;\n"); 2658 | 2659 | /* LSC_PROG_SPI(0x3A) */ 2660 | buf_sprintf(op, "SIR 8 TDI(3A);\n"); 2661 | buf_sprintf(op, "SDR 16 TDI(68FE);\n"); 2662 | buf_sprintf(op, "RUNTEST IDLE 32 TCK;\n\n"); 2663 | 2664 | /* Software reset RSTEN 66h RST 99h (both invariant under bit-reverse) */ 2665 | buf_sprintf(op, "SDR 8 tdi(66);\n"); 2666 | buf_sprintf(op, "SDR 8 tdi(99);\n"); 2667 | 2668 | /* Erase sectors */ 2669 | printf("Erasing sectors, please wait.\n"); 2670 | for (i = 0; i < flen; i += SPI_SECTOR_SIZE) { 2671 | addr = i + spi_addr; 2672 | 2673 | /* SPI write enable */ 2674 | buf_sprintf(op, "SDR 8 TDI(60);\n"); 2675 | 2676 | /* Read status register (some chips won't clear WIP without this) */ 2677 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2678 | buf_sprintf(op, " TDO(40FF)\n"); 2679 | buf_sprintf(op, " MASK(C100);\n\n"); 2680 | 2681 | buf_sprintf(op, "SDR 32 TDI(0000%02x1B);\n", 2682 | bitrev(addr / SPI_SECTOR_SIZE)); 2683 | buf_sprintf(op, "RUNTEST DRPAUSE 5.50E-01 SEC;\n"); 2684 | 2685 | /* Read status register */ 2686 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2687 | buf_sprintf(op, " TDO(00FF)\n"); 2688 | buf_sprintf(op, " MASK(C100);\n\n"); 2689 | } 2690 | 2691 | /* SPI write disable */ 2692 | buf_sprintf(op, "SDR 8 TDI(20);\n\n"); 2693 | 2694 | row_size = SPI_PAGE_SIZE; 2695 | } else { 2696 | /* LSC_INIT_ADDRESS(0x46) */ 2697 | buf_sprintf(op, "SIR 8 TDI (46);\n"); 2698 | buf_sprintf(op, "SDR 8 TDI (01);\n"); 2699 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2700 | 2701 | /* LSC_BITSTREAM_BURST(0x7a) */ 2702 | buf_sprintf(op, "SIR 8 TDI (7A);\n"); 2703 | buf_sprintf(op, "RUNTEST IDLE 2 TCK;\n\n"); 2704 | } 2705 | 2706 | for (i = 0; i < flen; i += row_size) { 2707 | n = flen - i; 2708 | if (n > row_size) 2709 | n = row_size; 2710 | if (jed_target == JED_TGT_FLASH) { 2711 | /* Skip write if all bits set in a block */ 2712 | for (j = 0; j < n; j++) 2713 | if (inbuf[i + j] != 0xff) 2714 | break; 2715 | if (j == n) 2716 | continue; 2717 | 2718 | buf_sprintf(op, "SDR 8 TDI(60);\n"); 2719 | buf_sprintf(op, "SDR %d TDI (", n * 8 + 32); 2720 | } else 2721 | buf_sprintf(op, "SDR %d TDI (", n * 8); 2722 | do { 2723 | n--; 2724 | op += sprintf(op, "%02X", bitrev(inbuf[i + n])); 2725 | if (n % hexlen == 0 && n > 0) 2726 | buf_sprintf(op, "\n\t"); 2727 | } while (n > 0); 2728 | if (jed_target == JED_TGT_FLASH) { 2729 | addr = i + spi_addr; 2730 | 2731 | buf_sprintf(op, "%02x%02x%02x40);\n\n", 2732 | bitrev(addr % 256), bitrev((addr / 256) % 256), 2733 | bitrev((addr / 65536) % 256)); 2734 | buf_sprintf(op, "RUNTEST DRPAUSE 2.00E-03 SEC;\n"); 2735 | buf_sprintf(op, "SDR 16 TDI(00A0)\n"); 2736 | buf_sprintf(op, " TDO(00FF)\n"); 2737 | buf_sprintf(op, " MASK(C100);\n\n"); 2738 | } else 2739 | buf_sprintf(op, ");\n\n"); 2740 | } 2741 | 2742 | /* BYPASS(0xFF) */ 2743 | buf_sprintf(op, "SIR 8 TDI (FF);\n"); 2744 | buf_sprintf(op, "RUNTEST IDLE 100 TCK;\n\n"); 2745 | 2746 | /* ISC DISABLE(Ox26): exit the programming mode */ 2747 | buf_sprintf(op, "SIR 8 TDI (26);\n"); 2748 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 2.00E-03 SEC;\n\n"); 2749 | buf_sprintf(op, "SIR 8 TDI (FF);\n"); 2750 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 1.00E-03 SEC;\n\n"); 2751 | 2752 | if (jed_target == JED_TGT_FLASH) { 2753 | /* LSC_REFRESH(0x79) */ 2754 | buf_sprintf(op, "SIR 8 TDI (79);\n"); 2755 | buf_sprintf(op, "SDR 24 TDI (000000);\n"); 2756 | buf_sprintf(op, "RUNTEST IDLE 2 TCK 1.00E-01 SEC;\n\n"); 2757 | } else { 2758 | /* LSC_READ_STATUS(0x3c): verify status register */ 2759 | buf_sprintf(op, "SIR 8 TDI (3C);\n"); 2760 | buf_sprintf(op, "SDR 32 TDI (00000000)\n"); 2761 | buf_sprintf(op, " TDO (00000100)\n"); 2762 | buf_sprintf(op, " MASK (00002100);\n\n"); 2763 | } 2764 | op--; 2765 | i = 0; 2766 | do { 2767 | if (*op == '\n') 2768 | i++; 2769 | } while (op-- != outbuf); 2770 | 2771 | if (svf_name) { 2772 | int of; 2773 | 2774 | if (strncmp(svf_name, "-", 1) == 0) 2775 | of = 0; 2776 | else 2777 | of = open(svf_name, O_RDWR | O_CREAT | O_TRUNC, 0644); 2778 | if (of < 0) { 2779 | res = errno; 2780 | return(res); 2781 | } 2782 | res = 0; 2783 | for (j = 0, outcp = outbuf; j < i; j++) { 2784 | write(of, outcp, strlen(outcp)); 2785 | outcp += (strlen(outcp) + 1); 2786 | } 2787 | if (of) 2788 | close(of); 2789 | } else 2790 | res = exec_svf_mem(outbuf, i, debug); 2791 | 2792 | free(outbuf); 2793 | free(inbuf); 2794 | return (res); 2795 | } 2796 | 2797 | 2798 | /* 2799 | * Load a SVF file in a contiguos chunk of memory, count number of lines, 2800 | * and then call exec_svf_mem(). 2801 | */ 2802 | static int 2803 | exec_svf_file(char *path, int target, int debug) 2804 | { 2805 | char *linebuf, *fbuf; 2806 | FILE *fd; 2807 | long flen; 2808 | int lines_tot = 1; 2809 | int res; 2810 | size_t i, slen; 2811 | 2812 | if (target != JED_TGT_SRAM) { 2813 | fprintf(stderr, "Unsupported target: svf files can only be written to SRAM (for now)\n"); 2814 | return (EXIT_FAILURE); 2815 | } 2816 | 2817 | if (path == NULL) { 2818 | fbuf=read_stdin(&slen); 2819 | flen = slen; 2820 | lines_tot = 0; 2821 | for (i=0; i send file\n" 2993 | " ~b change baudrate\n" 2994 | " ~r reprogram / reload " 2995 | "the FPGA\n" 2996 | " ~# send a BREAK signal\n" 2997 | " ~d enter f32c debugger\n" 2998 | " ~. exit from fujprog\n" 2999 | " ~? get this summary\n" 3000 | ); 3001 | } 3002 | 3003 | 3004 | static void 3005 | usage(void) 3006 | { 3007 | 3008 | printf("Usage: fujprog [option(s)] [bitstream_file]\n\n"); 3009 | 3010 | printf(" Valid options:\n"); 3011 | #ifdef USE_PPI 3012 | printf(" -c CABLE Select USB (default) or PPI JTAG CABLE\n"); 3013 | #endif 3014 | printf(" -p PORT Select USB JTAG / UART PORT (default is 0)\n"); 3015 | #ifdef WIN32 3016 | printf(" -P COM Select COM port (valid only with -t or -a)\n"); 3017 | #else 3018 | printf(" -P TTY Select TTY port (valid only with -t or -a)\n"); 3019 | #endif 3020 | printf(" -T TYPE Select TYPE of input (svf, img, bit or jed)\n"); 3021 | printf(" -i identify and exit\n"); 3022 | printf(" -j TARGET Select bitstream TARGET as SRAM (default)" 3023 | " or FLASH\n"); 3024 | printf(" -f ADDR Start writing to SPI flash at ADDR, " 3025 | "optional with -j flash\n"); 3026 | printf(" -s FILE Convert bitstream to SVF FILE and exit\n"); 3027 | printf(" -r Reload FPGA configuration from" 3028 | " FLASH\n"); 3029 | printf(" -t Enter terminal emulation mode after" 3030 | " completing JTAG operations\n"); 3031 | printf(" -b SPEED Set baudrate to SPEED (300 to 3000000" 3032 | " bauds)\n"); 3033 | printf(" -e FILE Send and execute a f32c (MIPS/RISCV) binary " 3034 | "FILE\n"); 3035 | printf(" -x SPEED Set binary transfer speed, optional with -e\n"); 3036 | printf(" -a FILE Send a raw FILE\n"); 3037 | printf(" -d debug (verbose)\n"); 3038 | printf(" -D DELAY Delay transmission of each byte by" 3039 | " DELAY ms\n"); 3040 | printf(" -V display version and exit\n"); 3041 | printf(" -z Force action\n"); 3042 | printf(" -h This help message\n"); 3043 | printf(" -l X Display messages in log fashion every times\n"); 3044 | printf(" -S serial Select FTDI by serial to support multiple boards\n"); 3045 | printf(" -q Suppress messages\n"); 3046 | 3047 | if (terminal) { 3048 | printf("\n Terminal emulation mode commands:\n"); 3049 | terminal_help(); 3050 | } 3051 | #ifndef WIN32 3052 | printf("\n"); 3053 | #endif 3054 | } 3055 | 3056 | 3057 | static int 3058 | gets1(char *cp, int size) 3059 | { 3060 | char *lp, *end; 3061 | char c; 3062 | int error = 0; 3063 | 3064 | lp = cp; 3065 | end = cp + size - 1; 3066 | for (;;) { 3067 | #ifdef WIN32 3068 | c = getch() & 0177; 3069 | #else 3070 | while (read(0, &c, 1) < 0) 3071 | ms_sleep(10); 3072 | #endif 3073 | switch (c) { 3074 | case 3: /* CTRL + C */ 3075 | error = -1; 3076 | case '\n': 3077 | case '\r': 3078 | printf("\n"); 3079 | *lp = '\0'; 3080 | return (error); 3081 | case '\b': 3082 | case '\177': 3083 | if (lp > cp) { 3084 | printf("%c \b", c); 3085 | fflush(stdout); 3086 | lp--; 3087 | } 3088 | continue; 3089 | case '\0': 3090 | continue; 3091 | default: 3092 | if (lp < end) { 3093 | printf("%c", c); 3094 | fflush(stdout); 3095 | *lp++ = c; 3096 | } 3097 | } 3098 | } 3099 | } 3100 | 3101 | 3102 | static int 3103 | prog(char *fname, int target, int debug) 3104 | { 3105 | int res, c, tstart, tend; 3106 | 3107 | tstart = ms_uptime(); 3108 | last_ledblink_ms = tstart; 3109 | 3110 | /* Move TAP into RESET state. */ 3111 | set_port_mode(PORT_MODE_ASYNC); 3112 | set_state(RESET); 3113 | 3114 | commit(1); 3115 | 3116 | if (!quiet && fname == NULL) { 3117 | fprintf(stderr, "Type, paste or pipe your bitstream.\n"); 3118 | } 3119 | 3120 | if (input_type==TYPE_UNSPECIFIED && fname!=NULL) { 3121 | c = strlen(fname) - 4; 3122 | if (c < 0) { 3123 | /* Handle small length file names */ 3124 | /* Execute flash target automatically */ 3125 | if (strlen(fname)>0) { 3126 | target = JED_TGT_FLASH; 3127 | res = exec_bit_file(fname, target, debug); 3128 | } else { 3129 | usage(); 3130 | exit(EXIT_FAILURE); 3131 | } 3132 | } 3133 | if (strcasecmp(&fname[c], ".jed") == 0) 3134 | res = exec_jedec_file(fname, target, debug); 3135 | else if (strcasecmp(&fname[c], ".bit") == 0 || 3136 | (strcasecmp(&fname[c], ".img") == 0 && target == JED_TGT_FLASH)) 3137 | res = exec_bit_file(fname, target, debug); 3138 | else if (strcasecmp(&fname[c], ".svf") == 0) 3139 | res = exec_svf_file(fname, target, debug); 3140 | else { 3141 | /* Execute flash target automatically */ 3142 | if (!quiet) { 3143 | fprintf(stderr, "Could not automatically guess type by extension: %s.\n", &fname[c]); 3144 | fprintf(stderr, "Automatically targeting flash and setting image type.\n"); 3145 | } 3146 | target = JED_TGT_FLASH; 3147 | res = exec_bit_file(fname, target, debug); 3148 | } 3149 | } else { 3150 | switch (input_type) { 3151 | case TYPE_JED: 3152 | res = exec_jedec_file(fname, target, debug); 3153 | break; 3154 | case TYPE_IMG: 3155 | case TYPE_BIT: 3156 | res = exec_bit_file(fname, target, debug); 3157 | break; 3158 | case TYPE_SVF: 3159 | res = exec_svf_file(fname, target, debug); 3160 | break; 3161 | case TYPE_UNSPECIFIED: 3162 | if (fname == NULL) { 3163 | res = exec_bit_file(fname, target, debug); 3164 | break; 3165 | } 3166 | default: 3167 | fprintf(stderr, "Could not recognize type specified: %d.\n", input_type); 3168 | res = -1; 3169 | } 3170 | } 3171 | 3172 | /* Leave TAP in RESET state. */ 3173 | set_port_mode(PORT_MODE_ASYNC); 3174 | set_state(IDLE); 3175 | set_state(RESET); 3176 | commit(1); 3177 | 3178 | tend = ms_uptime(); 3179 | if (res == 0) { 3180 | if (!quiet) { 3181 | if (!display_log) 3182 | fprintf(stderr, "\r"); 3183 | fprintf(stderr, "Programming: 100%% "); 3184 | fprintf(stderr, "\nCompleted in %.2f seconds.\n", 3185 | (tend - tstart) / 1000.0); 3186 | } 3187 | } else 3188 | fprintf(stderr, "\nFailed.\n"); 3189 | 3190 | return (res); 3191 | } 3192 | 3193 | 3194 | #if 0 3195 | static void 3196 | reload_xp2_flash(int debug) 3197 | { 3198 | char buf[128]; 3199 | char *c; 3200 | 3201 | if (!quiet) 3202 | printf("Reconfiguring FPGA...\n"); 3203 | last_ledblink_ms = ms_uptime(); 3204 | need_led_blink = 0; 3205 | 3206 | /* Move TAP into RESET state. */ 3207 | set_port_mode(PORT_MODE_SYNC); 3208 | set_state(IDLE); 3209 | set_state(RESET); 3210 | commit(1); 3211 | 3212 | /* Reset sequence */ 3213 | c = buf; 3214 | c += sprintf(c, "RUNTEST IDLE 30 TCK;\n"); 3215 | *c++ = 0; 3216 | c += sprintf(c, "SIR 8 TDI (1E);\n"); 3217 | *c++ = 0; 3218 | c += sprintf(c, "SIR 8 TDI (23);\n"); 3219 | *c++ = 0; 3220 | c += sprintf(c, "!\n"); 3221 | exec_svf_mem(buf, 4, debug); 3222 | 3223 | /* Leave TAP in RESET state. */ 3224 | set_state(IDLE); 3225 | set_state(RESET); 3226 | commit(1); 3227 | } 3228 | #endif 3229 | 3230 | 3231 | static int 3232 | async_read_block(int len) 3233 | { 3234 | int res, got = 0, backoff = 0, backoff_lim = 5; 3235 | int i; 3236 | #if defined(__FreeBSD__) || defined(__linux__) 3237 | if (cable_hw == CABLE_HW_COM) 3238 | backoff_lim = 10; 3239 | #endif 3240 | do { 3241 | if (cable_hw == CABLE_HW_USB) { 3242 | #ifdef WIN32 3243 | DWORD ev_stat, avail; 3244 | FT_GetStatus(ftHandle, &avail, &ev_stat, &ev_stat); 3245 | if (avail > len - got) 3246 | avail = len - got; 3247 | if (avail) 3248 | FT_Read(ftHandle, &rxbuf[got], avail, 3249 | (DWORD *) &res); 3250 | else 3251 | res = 0; 3252 | #else 3253 | res = ftdi_read_data(&fc, &rxbuf[got], len - got); 3254 | #endif 3255 | } else { 3256 | #ifdef WIN32 3257 | DWORD n; 3258 | n = len - got; 3259 | if (n > 32) 3260 | n = 32; 3261 | ReadFile(com_port, &rxbuf[got], n, 3262 | (DWORD *) &res, NULL); 3263 | #else 3264 | res = read(com_port, &rxbuf[got], len - got); 3265 | if (res == -1) 3266 | res = 0; 3267 | #endif 3268 | } 3269 | if (res > 0) { 3270 | got += res; 3271 | backoff = 0; 3272 | } else { 3273 | backoff++; 3274 | ms_sleep(backoff * 4); 3275 | } 3276 | } while (got < len && backoff < backoff_lim); 3277 | if(global_debug) 3278 | { 3279 | fprintf(stderr, "<"); 3280 | for(i = 0; i < got; i++) 3281 | fprintf(stderr, " %02x", rxbuf[i]); 3282 | fprintf(stderr, "\n"); 3283 | } 3284 | return (got); 3285 | } 3286 | 3287 | 3288 | static int 3289 | async_send_block(int len) 3290 | { 3291 | int sent; 3292 | int i; 3293 | 3294 | if (cable_hw == CABLE_HW_USB) { 3295 | #ifdef WIN32 3296 | FT_Write(ftHandle, txbuf, len, (DWORD *) &sent); 3297 | #else 3298 | sent = ftdi_write_data(&fc, txbuf, len); 3299 | #endif 3300 | } else { 3301 | #ifdef WIN32 3302 | WriteFile(com_port, txbuf, len, (DWORD *) &sent, NULL); 3303 | #else 3304 | fcntl(com_port, F_SETFL, 0); 3305 | sent = write(com_port, txbuf, len); 3306 | tcdrain(com_port); // flush data to hardware 3307 | fcntl(com_port, F_SETFL, O_NONBLOCK); 3308 | #endif 3309 | } 3310 | if(global_debug) 3311 | { 3312 | fprintf(stderr, ">"); 3313 | for(i = 0; i < sent && i < 20; i++) 3314 | fprintf(stderr, " %02x", txbuf[i]); 3315 | if(sent >= 20) 3316 | fprintf(stderr, "..."); 3317 | fprintf(stderr, "\n"); 3318 | } 3319 | if (sent == len) 3320 | return (0); 3321 | else 3322 | return (1); 3323 | } 3324 | 3325 | 3326 | static void 3327 | async_send_uint8(uint32_t data) 3328 | { 3329 | 3330 | txbuf[0] = data; 3331 | async_send_block(1); 3332 | } 3333 | 3334 | 3335 | static void 3336 | async_send_uint32(uint32_t data) 3337 | { 3338 | int i; 3339 | 3340 | for (i = 0; i < 4; i++) { 3341 | txbuf[i] = (data >> 24); 3342 | data <<= 8; 3343 | } 3344 | async_send_block(4); 3345 | } 3346 | 3347 | 3348 | static int 3349 | async_set_baudrate(int speed) 3350 | { 3351 | 3352 | if (cable_hw == CABLE_HW_USB) { 3353 | #ifdef WIN32 3354 | FT_SetBaudRate(ftHandle, speed); 3355 | #else 3356 | ftdi_set_baudrate(&fc, speed); 3357 | #endif 3358 | } else { 3359 | #ifdef WIN32 3360 | if (GetCommState(com_port, &tty) == 0) { 3361 | fprintf(stderr, "%s is not a COM port\n", com_name); 3362 | exit(EXIT_FAILURE); 3363 | } 3364 | tty.BaudRate = speed; 3365 | tty.StopBits = 0; 3366 | tty.Parity = 0; 3367 | tty.ByteSize = 8; 3368 | if (SetCommState(com_port, &tty) == 0) { 3369 | fprintf(stderr, "Can't set baudrate to %d\n", speed); 3370 | exit(EXIT_FAILURE); 3371 | } 3372 | #else 3373 | cfsetspeed(&tty, speed); 3374 | if (tcsetattr(com_port, TCSAFLUSH, &tty) != 0) { 3375 | fprintf(stderr, "Can't set baudrate to %d\n", speed); 3376 | exit(EXIT_FAILURE); 3377 | } 3378 | #endif 3379 | } 3380 | return (0); 3381 | } 3382 | 3383 | 3384 | static void 3385 | txfile(void) 3386 | { 3387 | int tx_cnt, i, infile, res; 3388 | int crc_retry; 3389 | int tx_retry, tx_success; 3390 | uint32_t rx_crc, local_crc, crc_i; 3391 | uint32_t base, bootaddr; 3392 | FILE *fd; 3393 | uint8_t hdrbuf[16]; 3394 | 3395 | if (tx_binary) { 3396 | fd = fopen(txfname, "r"); 3397 | if (fd == NULL) { 3398 | fprintf(stderr, "%s: cannot open\n", txfname); 3399 | return; 3400 | } 3401 | i = fread(hdrbuf, 1, 16, fd); 3402 | fseek(fd, 0, SEEK_END); 3403 | // len = ftell(fd); 3404 | fseek(fd, 0, SEEK_SET); 3405 | fclose(fd); 3406 | if (i != 16) { 3407 | fprintf(stderr, "%s: short read\n", txfname); 3408 | return; 3409 | } 3410 | if (hdrbuf[2] == 0x10 && hdrbuf[3] == 0x3c && 3411 | hdrbuf[6] == 0x10 && hdrbuf[7] == 0x26 && 3412 | hdrbuf[10] == 0x11 && hdrbuf[11] == 0x3c && 3413 | hdrbuf[14] == 0x31 && hdrbuf[7] == 0x26) { 3414 | /* MIPS, little-endian cookie found */ 3415 | base = (hdrbuf[1] << 24) + (hdrbuf[0] << 16) 3416 | + (hdrbuf[5] << 8) + hdrbuf[4]; 3417 | if (!quiet) 3418 | printf("MIPS little-endian"); 3419 | } else if (hdrbuf[2] == 0x10 && hdrbuf[3] == 0x3c && 3420 | hdrbuf[6] == 0x10 && hdrbuf[7] == 0x26 && 3421 | hdrbuf[10] == 0x11 && hdrbuf[11] == 0x3c) { 3422 | /* MIPS, big-endian cookie found */ 3423 | /* XXX fixme */ 3424 | fprintf(stderr, "%s: MIPS, big-endian UNSUPPORTED\n", 3425 | txfname); 3426 | return; 3427 | } else if ((hdrbuf[1] & 0xf) == 1 && hdrbuf[0] == 0x97 && 3428 | hdrbuf[4] == 0x93 && hdrbuf[5] == 0x81) { 3429 | /* RISC-V, little-endian cookie found */ 3430 | /* XXX hardcoded load address - fixme */ 3431 | base = 0x400; 3432 | if (!quiet) 3433 | printf("RISC-V (PIC)"); 3434 | } else { 3435 | fprintf(stderr, 3436 | "invalid file type, missing header cookie\n"); 3437 | return; 3438 | } 3439 | bootaddr = base; 3440 | if (!quiet) 3441 | printf(" binary, loading at 0x%08x, " 3442 | "TX speed %d bauds\n", base, xbauds); 3443 | } 3444 | 3445 | infile = open(txfname, 3446 | #ifdef WIN32 3447 | O_RDONLY | O_BINARY 3448 | #else 3449 | O_RDONLY 3450 | #endif 3451 | ); 3452 | if (infile < 0) { 3453 | fprintf(stderr, "%s: cannot open\n", txfname); 3454 | return; 3455 | } 3456 | 3457 | async_set_baudrate(bauds); 3458 | if (cable_hw == CABLE_HW_USB) { 3459 | set_port_mode(PORT_MODE_UART); 3460 | #ifdef WIN32 3461 | FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, 3462 | FT_PARITY_NONE); 3463 | FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 3464 | do {} while (FT_StopInTask(ftHandle) != FT_OK); 3465 | ms_sleep(50); 3466 | FT_Purge(ftHandle, FT_PURGE_RX); 3467 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 3468 | #else 3469 | ftdi_set_line_property(&fc, BITS_8, STOP_BIT_1, NONE); 3470 | ftdi_setflowctrl(&fc, SIO_DISABLE_FLOW_CTRL); 3471 | ftdi_usb_purge_buffers(&fc); 3472 | ms_sleep(50); 3473 | #endif 3474 | } 3475 | 3476 | /* Send a space mark to break into SIO loader prompt */ 3477 | async_send_uint8(' '); 3478 | 3479 | /* Wait for f32c ROM to catch up */ 3480 | if (tx_binary) 3481 | ms_sleep(200); 3482 | else 3483 | ms_sleep(100); 3484 | 3485 | /* Prune any stale data from rx buffer */ 3486 | async_read_block(2048); 3487 | 3488 | if (tx_binary) { 3489 | /* Start of binary transfer marker */ 3490 | async_send_uint8(255); 3491 | 3492 | async_send_uint8(0x80); /* CMD: set base */ 3493 | async_send_uint32(xbauds); 3494 | async_send_uint8(0xb0); /* CMD: set baudrate */ 3495 | ms_sleep(50); 3496 | async_set_baudrate(xbauds); 3497 | } 3498 | 3499 | i = bauds / 300; 3500 | if (bauds < 4800) 3501 | i = 16; 3502 | if (txfu_ms) 3503 | i = 1; 3504 | if (tx_binary) 3505 | i = 8192; 3506 | do { 3507 | if (!quiet) { 3508 | printf("%c ", statc[blinker_phase]); 3509 | printf("\rSending %s: ", txfname); 3510 | fflush(stdout); 3511 | blinker_phase = (blinker_phase + 1) & 0x3; 3512 | } 3513 | res = read(infile, &txbuf[8192], i); 3514 | if (!tx_binary && txfu_ms) 3515 | ms_sleep(txfu_ms); 3516 | if (res <= 0) { 3517 | tx_cnt = 0; 3518 | } else 3519 | tx_cnt = res; 3520 | 3521 | if (tx_cnt == 0) 3522 | break; 3523 | 3524 | if (tx_binary) { 3525 | tx_success = 0; 3526 | for(tx_retry = 0; tx_retry < 4 && tx_success == 0; tx_retry++) 3527 | { 3528 | async_send_uint8(0x80); /* CMD: set base */ 3529 | async_send_uint32(tx_cnt); 3530 | async_send_uint8(0x90); /* CMD: len = base */ 3531 | 3532 | async_send_uint8(0x80); /* CMD: set base */ 3533 | async_send_uint32(base); 3534 | 3535 | async_send_uint8(0xa0); /* CMD: Write block */ 3536 | local_crc = 0; 3537 | for (crc_i = 0; crc_i < tx_cnt; crc_i++) { 3538 | local_crc = 3539 | (local_crc >> 31) | (local_crc << 1); 3540 | txbuf[crc_i] = txbuf[crc_i + 8192]; 3541 | local_crc += txbuf[crc_i]; 3542 | } 3543 | #if 0 3544 | if(1) // intentionally damage tx packet to test CRC 3545 | { 3546 | // srandom(time(NULL)); // randomize seed, each run will be different 3547 | if( (rand() % 256) > 100 ) // error probability 100/256 3548 | txbuf[rand() % tx_cnt] = rand() % 0xFF; // error byte at random place 3549 | } 3550 | #endif 3551 | if (async_send_block(tx_cnt)) { 3552 | fprintf(stderr, "Block sending failed!\n"); 3553 | tx_cnt = -1; 3554 | continue; 3555 | } 3556 | if(txfu_ms > 0) 3557 | ms_sleep(txfu_ms); 3558 | async_send_uint8(0x81); // read checksum 3559 | res = 0; 3560 | for(crc_retry = 4; crc_retry > 0 && res != 4; ms_sleep(10), crc_retry--) 3561 | { 3562 | res = async_read_block(4); 3563 | if(crc_retry == 2 && res != 4) 3564 | async_send_uint8(0x81); // try again to read checksum 3565 | } 3566 | if(res != 4) 3567 | { 3568 | fprintf(stderr, "Checksum not received: " 3569 | "got %d bytes, should be 4 (0x%08X)\n", res, local_crc); 3570 | continue; 3571 | } 3572 | rx_crc = rxbuf[0] << 24; 3573 | rx_crc += rxbuf[1] << 16; 3574 | rx_crc += rxbuf[2] << 8; 3575 | rx_crc += rxbuf[3]; 3576 | if (rx_crc != local_crc) { 3577 | fprintf(stderr, "CRC error: " 3578 | "got 0x%08x, should be 0x%08x\n", 3579 | rx_crc, local_crc); 3580 | continue; 3581 | } 3582 | else 3583 | { 3584 | tx_success = 1; // checksum ok 3585 | tx_retry = 0; // reset number of retries 3586 | } 3587 | } 3588 | if(tx_success == 0) 3589 | { 3590 | tx_cnt = -1; // give up, no more retries retries 3591 | break; 3592 | } 3593 | } else { 3594 | memcpy(txbuf, &txbuf[8192], tx_cnt); 3595 | if (async_send_block(tx_cnt)) { 3596 | fprintf(stderr, "Block sending failed!\n"); 3597 | tx_cnt = -1; 3598 | break; 3599 | } 3600 | tx_success = 1; 3601 | } 3602 | if(tx_success) 3603 | base += tx_cnt; 3604 | } while (tx_cnt > 0); 3605 | 3606 | 3607 | if (tx_cnt >= 0 && !quiet) 3608 | printf("done.\n"); 3609 | close(infile); 3610 | fflush(stdout); 3611 | 3612 | if (tx_success == 0) 3613 | fprintf(stderr, "TX error at %08x\n", base); 3614 | else if (tx_binary) { 3615 | async_send_uint8(0x80); /* CMD: set base */ 3616 | async_send_uint32(bauds); 3617 | async_send_uint8(0xb0); /* CMD: set baudrate */ 3618 | ms_sleep(50); 3619 | async_set_baudrate(bauds); 3620 | 3621 | async_send_uint8(0x80); /* CMD: set base */ 3622 | async_send_uint32(bootaddr); 3623 | async_send_uint8(0xb1); /* CMD: jump to base */ 3624 | } 3625 | } 3626 | 3627 | 3628 | static void 3629 | genbrk(void) 3630 | { 3631 | 3632 | if (cable_hw == CABLE_HW_USB) { 3633 | #ifdef WIN32 3634 | FT_SetBreakOn(ftHandle); 3635 | ms_sleep(BREAK_MS); 3636 | FT_SetBreakOff(ftHandle); 3637 | #else 3638 | ftdi_set_line_property2(&fc, BITS_8, STOP_BIT_1, NONE, 3639 | BREAK_ON); 3640 | ms_sleep(BREAK_MS); 3641 | ftdi_set_line_property2(&fc, BITS_8, STOP_BIT_1, NONE, 3642 | BREAK_OFF); 3643 | #endif 3644 | } else { 3645 | #ifdef WIN32 3646 | EscapeCommFunction(com_port, SETBREAK); 3647 | ms_sleep(BREAK_MS); 3648 | EscapeCommFunction(com_port, CLRBREAK); 3649 | #else 3650 | ioctl(com_port, TIOCSBRK, NULL); 3651 | ms_sleep(BREAK_MS); 3652 | ioctl(com_port, TIOCCBRK, NULL); 3653 | #endif 3654 | } 3655 | ms_sleep(20); 3656 | } 3657 | 3658 | 3659 | static const char *riscv_reg_names[] = { 3660 | "zr", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 3661 | "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 3662 | "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 3663 | "s8", "s9", "sA", "sB", "t3", "t4", "t5", "t6" 3664 | }; 3665 | 3666 | static const char *mips_reg_names[] = { 3667 | "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", 3668 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 3669 | "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", 3670 | "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" 3671 | }; 3672 | 3673 | 3674 | static int deb_seqn; 3675 | static int deb_big_endian; 3676 | static int deb_riscv; 3677 | 3678 | 3679 | static void 3680 | deb_print_reg(int off) 3681 | { 3682 | int i; 3683 | 3684 | for (i = 0; i < 4; i++) 3685 | printf("%02x", rxbuf[off * 4 + (3 - i)]); 3686 | } 3687 | 3688 | 3689 | static int 3690 | deb_get_seqn() 3691 | { 3692 | int i; 3693 | 3694 | i = async_read_block(1); 3695 | if (i == 0) { 3696 | printf("Error: got no sequence number, " 3697 | "debugger disfunctional!\n"); 3698 | return (1); 3699 | } 3700 | if (rxbuf[0] != ((deb_seqn + 1) & 0xff)) { 3701 | printf("Error: bad sequence number: " 3702 | "got %d, should have %d\n", rxbuf[0], 3703 | (deb_seqn + 1) & 0xff); 3704 | return (1); 3705 | } 3706 | deb_seqn = rxbuf[0]; 3707 | return (0); 3708 | } 3709 | 3710 | 3711 | #define BREAKPOINTS 2 3712 | 3713 | static int 3714 | deb_print_breakpoints(void) 3715 | { 3716 | int i, enabled, trapped; 3717 | 3718 | async_send_uint8(0xa1); /* DEB_CMD_BREAKPOINT_RD */ 3719 | async_send_uint8(0); /* start at breakpoint #0 */ 3720 | async_send_uint8(BREAKPOINTS - 1);/* fetch values */ 3721 | deb_get_seqn(); 3722 | i = async_read_block(BREAKPOINTS * 4); 3723 | if (i != BREAKPOINTS * 4) { 3724 | printf("\nError: short read " 3725 | "(%d instead of %d)\n", i, BREAKPOINTS * 4); 3726 | return (-1); 3727 | } 3728 | 3729 | for (i = 0; i < BREAKPOINTS; i++) { 3730 | enabled = rxbuf[i * 4] & 1; 3731 | trapped = rxbuf[i * 4] & 2; 3732 | rxbuf[i * 4] &= ~3; 3733 | printf("breakpoint #%d: ", i); 3734 | if (enabled) { 3735 | deb_print_reg(i); 3736 | if (trapped) 3737 | printf(" (trapped)"); 3738 | printf("\n"); 3739 | } else 3740 | printf("disabled\n"); 3741 | } 3742 | 3743 | return (0); 3744 | } 3745 | 3746 | 3747 | static int 3748 | deb_print_registers(void) 3749 | { 3750 | int r, c, i; 3751 | 3752 | async_send_uint8(0xa0); /* DEB_CMD_REG_RD */ 3753 | async_send_uint8(0); /* start at reg #0 */ 3754 | async_send_uint8(63); /* fetch 64 values */ 3755 | deb_get_seqn(); 3756 | i = async_read_block(64 * 4); 3757 | if (i != 64 * 4) { 3758 | printf("\nError: short read " 3759 | "(%d instead of %d)\n", i, 64 * 4); 3760 | return (-1); 3761 | } 3762 | 3763 | for (r = 0; r < 8; r++) { 3764 | for (c = 0; c < 4; c++) { 3765 | if (r + 8 * c < 10) 3766 | printf(" "); 3767 | if (deb_riscv) 3768 | printf("x%d (%s): ", r + 8 * c, 3769 | riscv_reg_names[r + 8 * c]); 3770 | else 3771 | printf("$%d (%s): ", r + 8 * c, 3772 | mips_reg_names[r + 8 * c]); 3773 | deb_print_reg(r + 8 * c); 3774 | if (c != 3) 3775 | printf(" "); 3776 | } 3777 | printf("\n"); 3778 | } 3779 | printf("\n"); 3780 | 3781 | printf(" HI: "); 3782 | deb_print_reg(32); 3783 | printf(" LO: "); 3784 | deb_print_reg(33); 3785 | printf(" SR: "); 3786 | deb_print_reg(34); 3787 | printf(" CS: "); 3788 | deb_print_reg(35); 3789 | printf(" EPC: "); 3790 | deb_print_reg(36); 3791 | printf(" EB: "); 3792 | deb_print_reg(37); 3793 | printf("\n"); 3794 | 3795 | printf("\n"); 3796 | printf(" IF A: "); 3797 | deb_print_reg(40); 3798 | printf(" ID A: "); 3799 | deb_print_reg(42); 3800 | printf(" EX A: "); 3801 | deb_print_reg(44); 3802 | printf(" MA A: "); 3803 | deb_print_reg(46); 3804 | printf(" WB A: "); 3805 | deb_print_reg(48); 3806 | printf("\n"); 3807 | 3808 | printf(" IF I: "); 3809 | deb_print_reg(41); 3810 | printf(" ID I: "); 3811 | deb_print_reg(43); 3812 | printf(" EX I: "); 3813 | deb_print_reg(45); 3814 | printf(" MA I: "); 3815 | deb_print_reg(47); 3816 | printf(" WB I: "); 3817 | deb_print_reg(49); 3818 | printf("\n"); 3819 | 3820 | printf("\n"); 3821 | printf(" Count: "); 3822 | deb_print_reg(38); 3823 | printf(" Exec: "); 3824 | deb_print_reg(52); 3825 | printf(" Branch: "); 3826 | deb_print_reg(53); 3827 | printf(" Mispred: "); 3828 | deb_print_reg(54); 3829 | printf("\n"); 3830 | 3831 | return (0); 3832 | } 3833 | 3834 | 3835 | static void 3836 | debug_help(void) 3837 | { 3838 | 3839 | printf( 3840 | " r show registers\n" 3841 | " R show registers until a key is pressed\n" 3842 | " s execute a single clock cycle\n" 3843 | " s N execute at most N clock cycles\n" 3844 | " c continue execution\n" 3845 | " b show breakpoints\n" 3846 | " b N deactivate breakpoint N\n" 3847 | " b N,A set breakpoint N at address A\n" 3848 | " . exit from debugger\n" 3849 | " h get this summary\n" 3850 | " ? get this summary\n" 3851 | ); 3852 | } 3853 | 3854 | 3855 | static void 3856 | debug_cmd(void) 3857 | { 3858 | char cmdbuf[256]; 3859 | int i, j, c, r; 3860 | #ifdef WIN32 3861 | HANDLE cons_out = GetStdHandle(STD_OUTPUT_HANDLE); 3862 | CONSOLE_SCREEN_BUFFER_INFO screen_info; 3863 | #endif 3864 | 3865 | /* Enable debugger */ 3866 | printf("\n*** Entering debug mode ***\n"); 3867 | async_send_uint8(0x9d); 3868 | async_send_uint8(0xed); 3869 | 3870 | /* Flush read buffer */ 3871 | async_read_block(BUFLEN_MAX); 3872 | 3873 | /* Fetch initial sequence number and config register */ 3874 | async_send_uint8(0xa0); /* DEB_CMD_REG_RD */ 3875 | async_send_uint8(55); /* start at reg #55 */ 3876 | async_send_uint8(0); /* fetch 1 value */ 3877 | i = async_read_block(1); 3878 | if (i == 0) { 3879 | printf("Error: got no sequence number\n"); 3880 | printf("Debugger disfunctional, exiting.\n"); 3881 | return; 3882 | } 3883 | deb_seqn = rxbuf[0]; 3884 | i = async_read_block(4); 3885 | if (i != 4) { 3886 | printf("\nError: short read (%d instead of %d)\n", i, 4); 3887 | printf("Debugger disfunctional, exiting.\n"); 3888 | return; 3889 | } 3890 | printf("Detected "); 3891 | if (rxbuf[1] & 0x80) { 3892 | printf("big-endian "); 3893 | deb_big_endian = 1; 3894 | } else { 3895 | printf("little-endian "); 3896 | deb_big_endian = 0; 3897 | } 3898 | if (rxbuf[1] & 0x40) { 3899 | printf("f32c/riscv"); 3900 | deb_riscv = 1; 3901 | } else { 3902 | printf("f32c/mips"); 3903 | deb_riscv = 0; 3904 | } 3905 | printf(" core, clk ticks at %f MHz.\n", 1.0 * 3906 | (((rxbuf[3] & 0xf) << 8) + rxbuf[2]) / ((rxbuf[3] >> 5) + 1)); 3907 | 3908 | do { 3909 | printf("db> "); 3910 | fflush(stdout); 3911 | gets1(cmdbuf, sizeof(cmdbuf)); 3912 | for (i = 0; cmdbuf[i] != 0 ; i++) 3913 | if (cmdbuf[i] != ' ' && cmdbuf[i] != 9) 3914 | break; 3915 | switch (cmdbuf[i]) { 3916 | case 's': /* single step */ 3917 | c = atoi(&cmdbuf[i + 1]); 3918 | if (c < 1) 3919 | c = 1; 3920 | async_send_uint8(0xef); /* DEB_CMD_CLK_STEP */ 3921 | async_send_uint32(0); /* disable clk when done */ 3922 | async_send_uint32(c); /* how many cycles */ 3923 | deb_get_seqn(); 3924 | printf("Single-stepping %d cycle(s)...\n", c); 3925 | /* XXX ugly hack, wait for cycles to pass... */ 3926 | ms_sleep(c / 50000); 3927 | deb_print_registers(); 3928 | break; 3929 | case 'b': /* set / clear breakpoints */ 3930 | i++; 3931 | while (cmdbuf[i] == ' ' || cmdbuf[i] == 8) 3932 | i++; 3933 | if (cmdbuf[i] == 0) { 3934 | deb_print_breakpoints(); 3935 | break; 3936 | } 3937 | j = i; 3938 | while (isnumber(cmdbuf[j])) 3939 | j++; 3940 | r = atoi(&cmdbuf[i]); 3941 | i = j; 3942 | while (cmdbuf[i] == ' ' || cmdbuf[i] == 8 || 3943 | cmdbuf[i] == ',') 3944 | i++; 3945 | c = strtoul(&cmdbuf[i], NULL, 16); 3946 | c &= ~3; /* Word align */ 3947 | if (cmdbuf[i] != 0) 3948 | c |= 1; /* Set breakpoint enable flag */ 3949 | async_send_uint8(0xe1); /* DEB_CMD_BREAKPOINT_WR */ 3950 | async_send_uint32(r); /* dst reg */ 3951 | async_send_uint32(c); /* value */ 3952 | deb_get_seqn(); 3953 | break; 3954 | case 'c': /* continue */ 3955 | async_send_uint8(0xef); /* DEB_CMD_CLK_STEP */ 3956 | async_send_uint32(1); /* enable clk */ 3957 | async_send_uint32(0); /* don't wait */ 3958 | deb_get_seqn(); 3959 | break; 3960 | case 'r': /* print registers */ 3961 | deb_print_registers(); 3962 | break; 3963 | case 'R': /* continuously print registers */ 3964 | do { 3965 | if (deb_print_registers() != 0) 3966 | break; 3967 | #ifdef WIN32 3968 | if (kbhit()) { 3969 | c = getch(); 3970 | #else 3971 | if (read(0, &c, 1) > 0) { 3972 | #endif 3973 | break; 3974 | } 3975 | #ifdef WIN32 3976 | GetConsoleScreenBufferInfo(cons_out, 3977 | &screen_info); 3978 | screen_info.dwCursorPosition.X = 0; 3979 | screen_info.dwCursorPosition.Y -= 15; 3980 | SetConsoleCursorPosition(cons_out, 3981 | screen_info.dwCursorPosition); 3982 | #else 3983 | printf("\r\033[15A"); 3984 | #endif 3985 | } while (1); 3986 | break; 3987 | case 'q': 3988 | cmdbuf[i] = '.'; 3989 | break; 3990 | case '.': 3991 | case 0: 3992 | break; 3993 | case 'h': 3994 | case '?': 3995 | debug_help(); 3996 | break; 3997 | default: 3998 | printf("Unknown command\n"); 3999 | break; 4000 | } 4001 | } while (cmdbuf[i] != '.'); 4002 | 4003 | /* Exit debugger */ 4004 | printf("*** Exiting debug mode ***\n"); 4005 | async_send_uint8(0x9d); 4006 | async_send_uint8(0xdd); 4007 | async_read_block(1); 4008 | } 4009 | 4010 | 4011 | static int 4012 | term_emul(void) 4013 | { 4014 | #ifdef WIN32 4015 | DWORD saved_cons_mode; 4016 | DWORD rx_cnt, tx_cnt, ev_stat, sent; 4017 | HANDLE cons_in = GetStdHandle(STD_INPUT_HANDLE); 4018 | HANDLE cons_out = GetStdHandle(STD_OUTPUT_HANDLE); 4019 | CONSOLE_CURSOR_INFO cursor_info; 4020 | CONSOLE_SCREEN_BUFFER_INFO screen_info; 4021 | COORD cursor_pos, saved_cursor_pos; 4022 | int color0, cons_color; 4023 | int rx_esc_seqn = 0; 4024 | int tx_esc_seqn = 0; 4025 | int esc_arg, esc_arg0; 4026 | int prev_char = 0; 4027 | char *keystr; 4028 | char vt100buf[20]; 4029 | #else 4030 | int rx_cnt, tx_cnt, sent; 4031 | #endif 4032 | int key_phase = 1; /* 0 .. normal; 1 .. CR; 2 .. CR + ~ */ 4033 | int c, res; 4034 | int infile = -1; 4035 | int sleep_t = 0; 4036 | char argbuf[256]; 4037 | int i; 4038 | 4039 | #ifdef WIN32 4040 | if (cable_hw == CABLE_HW_USB) { 4041 | FT_SetLatencyTimer(ftHandle, 20); 4042 | FT_SetBaudRate(ftHandle, bauds); 4043 | FT_SetDataCharacteristics(ftHandle, FT_BITS_8, FT_STOP_BITS_1, 4044 | FT_PARITY_NONE); 4045 | FT_SetFlowControl(ftHandle, FT_FLOW_NONE, 0, 0); 4046 | if (port_mode != PORT_MODE_UART) { 4047 | set_port_mode(PORT_MODE_UART); 4048 | do {} while (FT_StopInTask(ftHandle) != FT_OK); 4049 | ms_sleep(50); 4050 | FT_Purge(ftHandle, FT_PURGE_RX); 4051 | do {} while (FT_RestartInTask(ftHandle) != FT_OK); 4052 | } 4053 | } 4054 | 4055 | /* Disable CTRL-C, XON/XOFF etc. processing on console input. */ 4056 | GetConsoleMode(cons_in, &saved_cons_mode); 4057 | SetConsoleMode(cons_in, 0x40); /* ENABLE_QUICK_EDIT_MODE */ 4058 | GetConsoleScreenBufferInfo(cons_out, &screen_info); 4059 | color0 = screen_info.wAttributes; 4060 | color0 = FOREGROUND_GREEN | FOREGROUND_INTENSITY; 4061 | cursor_info.bVisible = 1; 4062 | cursor_info.dwSize = 100; 4063 | SetConsoleCursorInfo(cons_out, &cursor_info); 4064 | SetConsoleTextAttribute(cons_out, color0); 4065 | #else 4066 | if (cable_hw == CABLE_HW_USB) { 4067 | if (port_mode != PORT_MODE_UART) { 4068 | set_port_mode(PORT_MODE_UART); 4069 | ftdi_usb_purge_buffers(&fc); 4070 | } 4071 | ftdi_set_latency_timer(&fc, 20); 4072 | ftdi_set_baudrate(&fc, bauds); 4073 | ftdi_set_line_property(&fc, BITS_8, STOP_BIT_1, NONE); 4074 | ftdi_setflowctrl(&fc, SIO_DISABLE_FLOW_CTRL); 4075 | } 4076 | 4077 | /* Disable CTRL-C, XON/XOFF etc. processing on console input. */ 4078 | fcntl(0, F_SETFL, O_NONBLOCK); 4079 | system("stty -echo -isig -icanon -iexten -ixon -ixoff -icrnl"); 4080 | #endif 4081 | 4082 | printf("Terminal emulation mode, using %d bauds\n", bauds); 4083 | printf("Press ENTER, ~, ? for help\n"); 4084 | 4085 | do { 4086 | tx_cnt = 0; 4087 | if (infile > 0) { 4088 | i = bauds / 300; 4089 | if (bauds < 4800) 4090 | i = 16; 4091 | res = read(infile, txbuf, i); 4092 | if (res <= 0) { 4093 | close(infile); 4094 | infile = -1; 4095 | tx_cnt = 0; 4096 | } else 4097 | tx_cnt = res; 4098 | #ifdef WIN32 4099 | if (kbhit()) { 4100 | c = getch(); 4101 | #else 4102 | if (read(0, &c, 1) > 0) { 4103 | #endif 4104 | if (c == 3) { 4105 | close(infile); 4106 | infile = -1; 4107 | tx_cnt = 0; 4108 | printf("\nTransfer interrupted!\n\n"); 4109 | } 4110 | } 4111 | } else 4112 | #ifdef WIN32 4113 | while (kbhit()) { 4114 | c = getch(); 4115 | txbuf[tx_cnt] = c; 4116 | #else 4117 | while (read(0, &txbuf[tx_cnt], 1) > 0) { 4118 | c = txbuf[tx_cnt]; 4119 | #endif 4120 | #ifdef WIN32 4121 | /* 4122 | * Translate cursor / function keys to vt100 sequences. 4123 | */ 4124 | if (c == 224) { 4125 | tx_esc_seqn = 1; /* Cursor keys */ 4126 | continue; 4127 | } 4128 | if (c == 0) { 4129 | tx_esc_seqn = 2; /* FN keys */ 4130 | continue; 4131 | } 4132 | if (tx_esc_seqn == 1) { 4133 | keystr = ""; 4134 | switch (c) { 4135 | case 75: /* cursor left */ 4136 | keystr = "\x1b[D"; 4137 | break; 4138 | case 77: /* cursor right */ 4139 | keystr = "\x1b[C"; 4140 | break; 4141 | case 72: /* cursor up */ 4142 | keystr = "\x1b[A"; 4143 | break; 4144 | case 80: /* cursor down */ 4145 | keystr = "\x1b[B"; 4146 | break; 4147 | case 82: /* INS */ 4148 | keystr = "\x1b[2\x7e"; 4149 | break; 4150 | case 83: /* DEL */ 4151 | keystr = "\x1b[3\x7e"; 4152 | break; 4153 | case 73: /* PgUP */ 4154 | break; 4155 | case 81: /* PgDOWN */ 4156 | break; 4157 | case 71: /* Home */ 4158 | keystr = "\x1b[H"; 4159 | break; 4160 | case 79: /* End */ 4161 | keystr = "\x1b[F"; 4162 | break; 4163 | default: 4164 | break; 4165 | } 4166 | tx_cnt += sprintf(&txbuf[tx_cnt], "%s", keystr); 4167 | tx_esc_seqn = 0; 4168 | continue; 4169 | } 4170 | if (tx_esc_seqn == 2) { 4171 | /* Ignore FN keys for now */ 4172 | tx_esc_seqn = 0; 4173 | continue; 4174 | } 4175 | #endif 4176 | 4177 | /* 4178 | * Catch and process ~ escape sequences. 4179 | */ 4180 | if (key_phase == 2) { 4181 | switch (c) { 4182 | case '?': 4183 | printf("~?\n"); 4184 | terminal_help(); 4185 | key_phase = 0; 4186 | continue; 4187 | case '#': 4188 | genbrk(); 4189 | key_phase = 0; 4190 | continue; 4191 | case 'r': 4192 | reload = 1; 4193 | res = 0; 4194 | goto done; 4195 | case 'a': 4196 | txbuf[tx_cnt] = c = 1; 4197 | break; 4198 | case 'k': 4199 | case '.': 4200 | res = 1; 4201 | goto done; 4202 | case 'b': 4203 | printf("~>New baudrate? "); 4204 | fflush(stdout); 4205 | gets1(argbuf, sizeof(argbuf)); 4206 | c = atoi(argbuf); 4207 | if (c > 0 && 4208 | cable_hw == CABLE_HW_USB) { 4209 | #ifdef WIN32 4210 | res = FT_SetBaudRate(ftHandle, 4211 | c); 4212 | if (res == FT_OK) { 4213 | #else 4214 | res = ftdi_set_baudrate(&fc, 4215 | c); 4216 | if (res == 0) { 4217 | #endif 4218 | bauds = c; 4219 | printf("new" 4220 | " baudrate: %d\n", 4221 | bauds); 4222 | } else 4223 | printf("%d: invalid" 4224 | " baudrate\n", c); 4225 | } 4226 | key_phase = 0; 4227 | continue; 4228 | case '>': 4229 | printf("~>Local file name? "); 4230 | fflush(stdout); 4231 | gets1(argbuf, sizeof(argbuf)); 4232 | infile = open(argbuf, 4233 | #ifdef WIN32 4234 | O_RDONLY | O_BINARY 4235 | #else 4236 | O_RDONLY 4237 | #endif 4238 | ); 4239 | if (infile < 0) 4240 | printf("%s: cannot open\n", 4241 | argbuf); 4242 | key_phase = 0; 4243 | continue; 4244 | case 'd': 4245 | debug_cmd(); 4246 | key_phase = 0; 4247 | continue; 4248 | default: 4249 | if (c != '~') { 4250 | txbuf[tx_cnt] = '~'; 4251 | tx_cnt++; 4252 | txbuf[tx_cnt] = c; 4253 | } 4254 | key_phase = 0; 4255 | break; 4256 | } 4257 | } 4258 | if (c == 1) { 4259 | if (key_phase < 2) { 4260 | key_phase = 2; 4261 | continue; 4262 | } else { 4263 | key_phase = 0; 4264 | } 4265 | } 4266 | if (key_phase == 1 && c == '~') { 4267 | key_phase = 2; 4268 | continue; 4269 | } 4270 | if (c == 13) 4271 | key_phase = 1; 4272 | else 4273 | key_phase = 0; 4274 | tx_cnt++; 4275 | if (tx_cnt >= 16) 4276 | break; 4277 | } 4278 | if (tx_cnt) { 4279 | if (cable_hw == CABLE_HW_USB) { 4280 | #ifdef WIN32 4281 | FT_Write(ftHandle, txbuf, tx_cnt, &sent); 4282 | #else 4283 | sent = 0; 4284 | for(int i=0; i BUFLEN_MAX) 4313 | rx_cnt = BUFLEN_MAX; 4314 | if (rx_cnt) 4315 | FT_Read(ftHandle, txbuf, rx_cnt, &rx_cnt); 4316 | } else { 4317 | rx_cnt = 32; 4318 | ReadFile(com_port, txbuf, rx_cnt, 4319 | (DWORD *) &rx_cnt, NULL); 4320 | } 4321 | #else 4322 | rx_cnt = 1; 4323 | if (cable_hw == CABLE_HW_USB) { 4324 | if (rx_cnt < fc.readbuffer_remaining) 4325 | rx_cnt = fc.readbuffer_remaining; 4326 | if (rx_cnt > BUFLEN_MAX) 4327 | rx_cnt = BUFLEN_MAX; 4328 | rx_cnt = ftdi_read_data(&fc, txbuf, rx_cnt); 4329 | } else { 4330 | rx_cnt = read(com_port, txbuf, rx_cnt); 4331 | if (rx_cnt == -1) 4332 | rx_cnt = 0; 4333 | } 4334 | #endif 4335 | if (rx_cnt) { 4336 | if (rx_cnt < 0) { 4337 | res = 1; 4338 | goto done; 4339 | } 4340 | #ifdef WIN32 4341 | for (i = 0; i < rx_cnt; i++) { 4342 | c = txbuf[i]; 4343 | /* 4344 | * Interpret selected VT-100 control sequences 4345 | */ 4346 | if (c == 27) { 4347 | prev_char = 27; 4348 | continue; 4349 | } 4350 | if (prev_char == 27 && c == '[') { 4351 | rx_esc_seqn = 1; 4352 | esc_arg = 0; 4353 | esc_arg0 = 0; 4354 | continue; 4355 | } 4356 | if (rx_esc_seqn) { 4357 | if (c >= '0' && c <= '9') { 4358 | esc_arg = esc_arg * 10 + 4359 | c - '0'; 4360 | continue; 4361 | } 4362 | if (c == ';') { 4363 | esc_arg0 = esc_arg; 4364 | esc_arg = 0; 4365 | continue; 4366 | } 4367 | switch (c) { 4368 | case 's': /* Save cursor position */ 4369 | break; 4370 | case 'u': /* Restore cursor position */ 4371 | break; 4372 | case 'n': /* Query cursor position */ 4373 | if (esc_arg != 6) 4374 | break; 4375 | break; 4376 | GetConsoleScreenBufferInfo( 4377 | cons_out, &screen_info); 4378 | c = sprintf(vt100buf, 4379 | "\x1b[%d;%dR", 4380 | screen_info.dwCursorPosition.Y 4381 | - screen_info.srWindow.Top, 4382 | screen_info.dwCursorPosition.X 4383 | - screen_info.srWindow.Left); 4384 | FT_Write(ftHandle, vt100buf, 4385 | c, &sent); 4386 | break; 4387 | case 'C': /* Set cursor hpos */ 4388 | break; 4389 | case 'H': /* Cursor home */ 4390 | break; 4391 | case 'A': /* Cursor up */ 4392 | break; 4393 | case 'K': /* Erase to end of line */ 4394 | break; 4395 | case 'J': /* Clear screen */ 4396 | GetConsoleScreenBufferInfo( 4397 | cons_out, &screen_info); 4398 | cursor_pos.X = 4399 | screen_info.srWindow.Left; 4400 | cursor_pos.Y = 4401 | screen_info.srWindow.Top; 4402 | FillConsoleOutputCharacter( 4403 | cons_out, ' ', 4404 | (screen_info.srWindow.Bottom 4405 | - screen_info.srWindow.Top) * 4406 | (screen_info.srWindow.Right 4407 | - screen_info.srWindow.Left), 4408 | cursor_pos, &sent); 4409 | SetConsoleCursorPosition( 4410 | cons_out, cursor_pos); 4411 | break; 4412 | case 'm': /* Set char attribute */ 4413 | cons_color = color0; 4414 | if (esc_arg == 1 || 4415 | esc_arg == 4) { 4416 | cons_color |= 4417 | FOREGROUND_RED; 4418 | } 4419 | SetConsoleTextAttribute( 4420 | cons_out, cons_color); 4421 | break; 4422 | default: 4423 | break; 4424 | } 4425 | rx_esc_seqn = 0; 4426 | continue; 4427 | } 4428 | rx_esc_seqn = 0; 4429 | fwrite(&c, 1, 1, stdout); 4430 | } 4431 | #else 4432 | fwrite(txbuf, 1, rx_cnt, stdout); 4433 | #endif 4434 | fflush(stdout); 4435 | } 4436 | if (tx_cnt == 0 && rx_cnt == 0) { 4437 | ms_sleep(sleep_t); 4438 | if (sleep_t < 5) 4439 | sleep_t++; 4440 | } else 4441 | sleep_t = 0; 4442 | } while (1); 4443 | 4444 | done: 4445 | printf("\n"); 4446 | 4447 | /* Restore special key processing on console input. */ 4448 | #ifdef WIN32 4449 | SetConsoleMode(cons_in, saved_cons_mode); 4450 | cursor_info.bVisible = 1; 4451 | cursor_info.dwSize = 20; 4452 | SetConsoleCursorInfo(cons_out, &cursor_info); 4453 | FT_SetLatencyTimer(ftHandle, 1); 4454 | FT_SetBaudRate(ftHandle, USB_BAUDS); 4455 | #else 4456 | system("stty echo isig icanon iexten ixon ixoff icrnl"); 4457 | ftdi_set_latency_timer(&fc, 1); 4458 | ftdi_set_baudrate(&fc, USB_BAUDS); 4459 | #endif 4460 | 4461 | return (res); 4462 | } 4463 | 4464 | void header(void) { 4465 | printf("%s v%d.%d (git %s built %s %s)\n", verstr, FUJPROG_VERSION_MAJOR, FUJPROG_VERSION_MINOR, FUJPROG_GIT_REVISION, __DATE__, __TIME__); 4466 | printf("%s\n", credstr); 4467 | } 4468 | 4469 | int 4470 | main(int argc, char *argv[]) 4471 | { 4472 | int res = EXIT_FAILURE; 4473 | int jed_target = JED_TGT_SRAM; 4474 | int debug = 0; 4475 | int c; 4476 | #ifdef WIN32 4477 | int had_terminal = 0; 4478 | COMMTIMEOUTS com_to; 4479 | #endif 4480 | force_prog=0; 4481 | serial = NULL; 4482 | 4483 | #ifndef USE_PPI 4484 | #define OPTS "Vqtdzhij:l:T:b:p:x:p:P:a:e:f:D:rs:S:" 4485 | #else 4486 | #define OPTS "Vqtdzhij:l:T:b:p:x:p:P:a:e:f:D:rs:S:c:" 4487 | #endif 4488 | while ((c = getopt(argc, argv, OPTS)) != -1) { 4489 | switch (c) { 4490 | case 'T': 4491 | if (strcasecmp(optarg, "jed") == 0) 4492 | input_type = TYPE_JED; 4493 | else if (strcasecmp(optarg, "img") == 0) 4494 | input_type = TYPE_IMG; 4495 | else if (strcasecmp(optarg, "svf") == 0) 4496 | input_type = TYPE_SVF; 4497 | else if (strcasecmp(optarg, "bit") == 0) 4498 | input_type = TYPE_BIT; 4499 | else { 4500 | usage(); 4501 | exit(EXIT_FAILURE); 4502 | } 4503 | break; 4504 | case 'l': 4505 | display_log = atoi(optarg); 4506 | display_counter = 0; 4507 | break; 4508 | case 'a': 4509 | txfname = optarg; 4510 | tx_binary = 0; 4511 | break; 4512 | case 'b': 4513 | bauds = atoi(optarg); 4514 | break; 4515 | case 'x': 4516 | xbauds = atoi(optarg); 4517 | break; 4518 | #ifdef USE_PPI 4519 | case 'c': 4520 | if (strcasecmp(optarg, "usb") == 0) 4521 | cable_hw = CABLE_HW_USB; 4522 | else if (strcasecmp(optarg, "ppi") == 0) 4523 | cable_hw = CABLE_HW_PPI; 4524 | else { 4525 | usage(); 4526 | exit(EXIT_FAILURE); 4527 | } 4528 | break; 4529 | #endif 4530 | case 'd': 4531 | debug = 1; 4532 | global_debug = 1; 4533 | break; 4534 | case 'D': 4535 | txfu_ms = atoi(optarg); 4536 | break; 4537 | case 'z': 4538 | force_prog = 1; 4539 | break; 4540 | case 'e': 4541 | txfname = optarg; 4542 | tx_binary = 1; 4543 | break; 4544 | case 'i': 4545 | opt_info = 1; 4546 | break; 4547 | case 'j': 4548 | if (strcasecmp(optarg, "sram") == 0) 4549 | jed_target = JED_TGT_SRAM; 4550 | else if (strcasecmp(optarg, "flash") == 0) 4551 | jed_target = JED_TGT_FLASH; 4552 | else { 4553 | usage(); 4554 | exit(EXIT_FAILURE); 4555 | } 4556 | break; 4557 | case 'f': 4558 | if (optarg[0] == '0' && optarg[1] == 'x') 4559 | sscanf(&optarg[2], "%x", &spi_addr); 4560 | else if (isdigit(*optarg)) 4561 | spi_addr = atoi(optarg); 4562 | else { 4563 | printf("Invalid address format\n"); 4564 | exit(EXIT_FAILURE); 4565 | } 4566 | if ((spi_addr & (SPI_SECTOR_SIZE - 1)) != 0) { 4567 | printf("SPI address must be a multiple of %d\n", 4568 | SPI_SECTOR_SIZE); 4569 | exit(EXIT_FAILURE); 4570 | } 4571 | break; 4572 | case 'p': 4573 | port_index = atoi(optarg); 4574 | break; 4575 | case 'P': 4576 | com_name = optarg; 4577 | cable_hw = CABLE_HW_COM; 4578 | break; 4579 | case 'S': 4580 | serial = optarg; 4581 | break; 4582 | case 'q': 4583 | quiet = 1; 4584 | break; 4585 | case 'r': 4586 | reload = 1; 4587 | break; 4588 | case 's': 4589 | svf_name = optarg; 4590 | break; 4591 | case 't': 4592 | terminal = 1; 4593 | #ifdef WIN32 4594 | had_terminal = 1; 4595 | #endif 4596 | break; 4597 | case 'V': 4598 | header(); 4599 | exit(0); 4600 | case '?': 4601 | case 'h': 4602 | header(); 4603 | usage(); 4604 | exit(0); 4605 | default: 4606 | header(); 4607 | usage(); 4608 | exit(EXIT_FAILURE); 4609 | } 4610 | } 4611 | argc -= optind; 4612 | argv += optind; 4613 | 4614 | #ifdef WIN32 4615 | if (terminal) { 4616 | system("color 0a"); 4617 | system("cls"); 4618 | } 4619 | #endif 4620 | 4621 | if (!quiet) { 4622 | header(); 4623 | } 4624 | 4625 | if (svf_name && opt_info==0) { 4626 | if (terminal || reload || txfname || com_name || argc == 0) { 4627 | usage(); 4628 | exit(EXIT_FAILURE); 4629 | } 4630 | res = exec_bit_file(argv[0], jed_target, debug); 4631 | return(res); 4632 | } 4633 | 4634 | if (com_name && terminal == 0 && txfname == NULL && reload == 0) { 4635 | fprintf(stderr, "error: " 4636 | "option -P must be used with -r, -t or -a\n"); 4637 | exit(EXIT_FAILURE); 4638 | } 4639 | 4640 | if (com_name && cable_hw != CABLE_HW_COM) { 4641 | fprintf(stderr, "error: " 4642 | "options -P and -c are mutually exclusive\n"); 4643 | exit(EXIT_FAILURE); 4644 | } 4645 | 4646 | if (spi_addr && jed_target != JED_TGT_FLASH) { 4647 | fprintf(stderr, "error: " 4648 | "-f may be specified only with -j flash\n"); 4649 | exit(EXIT_FAILURE); 4650 | } 4651 | 4652 | switch (cable_hw) { 4653 | case CABLE_HW_UNKNOWN: 4654 | case CABLE_HW_USB: 4655 | res = setup_usb(); 4656 | if (res == 0) 4657 | cable_hw = CABLE_HW_USB; 4658 | if (cable_hw == CABLE_HW_USB) { 4659 | if (xbauds == 0) 4660 | xbauds = 3000000; 4661 | break; 4662 | } 4663 | #ifdef USE_PPI 4664 | case CABLE_HW_PPI: 4665 | res = setup_ppi(); 4666 | #endif 4667 | break; 4668 | case CABLE_HW_COM: 4669 | if (xbauds == 0) 4670 | xbauds = bauds; 4671 | #ifdef WIN32 4672 | sprintf(txbuf, "\\\\.\\%s", com_name); 4673 | com_port = CreateFile(txbuf, GENERIC_READ | GENERIC_WRITE, 4674 | 0, NULL, OPEN_EXISTING, 0, NULL); 4675 | if (com_port == INVALID_HANDLE_VALUE) { 4676 | fprintf(stderr, "Can't open %s\n", com_name); 4677 | exit(EXIT_FAILURE); 4678 | } 4679 | async_set_baudrate(bauds); 4680 | if (GetCommTimeouts(com_port, &com_to) == 0) { 4681 | fprintf(stderr, "Can't configure %s\n", com_port); 4682 | exit(EXIT_FAILURE); 4683 | } 4684 | com_to.ReadIntervalTimeout = 1; 4685 | com_to.ReadTotalTimeoutConstant = 1; 4686 | com_to.ReadTotalTimeoutMultiplier = 1; 4687 | SetCommTimeouts(com_port, &com_to); 4688 | res = 0; 4689 | #else 4690 | com_port = open(com_name, O_RDWR); 4691 | if (com_port < 0 || tcgetattr(com_port, &tty)) { 4692 | fprintf(stderr, "Can't open %s\n", com_name); 4693 | exit(EXIT_FAILURE); 4694 | } 4695 | tty.c_cflag &= ~(CSIZE|PARENB); 4696 | tty.c_cflag |= CS8; 4697 | tty.c_cflag |= CLOCAL; 4698 | tty.c_cflag &= ~CRTSCTS; 4699 | tty.c_iflag &= ~(ISTRIP|ICRNL); 4700 | tty.c_iflag &= ~(IXON|IXOFF); 4701 | tty.c_oflag &= ~OPOST; 4702 | tty.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); 4703 | tty.c_cc[VMIN] = 1; 4704 | tty.c_cc[VTIME] = 0; 4705 | async_set_baudrate(bauds); 4706 | res = fcntl(com_port, F_SETFL, O_NONBLOCK); 4707 | #if defined(__FreeBSD__) || defined(__linux__) 4708 | /* XXX w/o this a BREAK won't be sent properly on FreeBSD ?!?*/ 4709 | ms_sleep(300); 4710 | #endif 4711 | #endif /* !WIN32 */ 4712 | default: 4713 | /* can't happen, shut up gcc warnings */ 4714 | break; 4715 | } 4716 | 4717 | if (res) { 4718 | fprintf(stderr, "Cannot find JTAG cable.\n"); 4719 | exit(EXIT_FAILURE); 4720 | } 4721 | 4722 | if (!quiet && cable_hw != CABLE_HW_COM) { 4723 | #ifndef WIN32 4724 | if (cable_hw == CABLE_HW_USB) 4725 | printf("Using USB cable: %s\n", hmp->cable_path); 4726 | else 4727 | #ifdef USE_PPI 4728 | printf("Using parallel port JTAG cable.\n"); 4729 | #else 4730 | printf("Parallel port JTAG cable not supported!\n"); 4731 | #endif 4732 | #endif /* !WIN32 */ 4733 | } 4734 | 4735 | if (opt_info) { 4736 | res = exec_info(argv[0], jed_target, debug); 4737 | } else { 4738 | if (argc == 0 && terminal == 0 && txfname == NULL && reload == 0) { 4739 | prog(NULL,jed_target,debug); 4740 | } 4741 | 4742 | do { 4743 | if (reload) { 4744 | genbrk(); 4745 | reload = 0; 4746 | } 4747 | if (argc) 4748 | prog(argv[0], jed_target, debug); 4749 | jed_target = JED_TGT_SRAM; /* for subsequent prog() calls */ 4750 | if (txfname) 4751 | txfile(); 4752 | } while (terminal && term_emul() == 0); 4753 | } 4754 | 4755 | #ifdef WIN32 4756 | if (had_terminal) 4757 | system("color"); 4758 | #endif 4759 | 4760 | if (cable_hw == CABLE_HW_COM) { 4761 | #ifdef WIN32 4762 | CloseHandle(com_port); 4763 | #else 4764 | close(com_port); 4765 | #endif 4766 | } else if (cable_hw == CABLE_HW_USB) { 4767 | ms_sleep(1); // small delay for f32c to start 4768 | shutdown_usb(); 4769 | } 4770 | #ifdef USE_PPI 4771 | else 4772 | shutdown_ppi(); 4773 | #endif 4774 | 4775 | return (res); 4776 | } 4777 | -------------------------------------------------------------------------------- /fujprog.h.in: -------------------------------------------------------------------------------- 1 | #ifndef FUJPROG_H 2 | #define FUJPROG_H 3 | 4 | #define FUJPROG_VERSION_MAJOR @fujprog_VERSION_MAJOR@ 5 | #define FUJPROG_VERSION_MINOR @fujprog_VERSION_MINOR@ 6 | #define FUJPROG_GIT_REVISION "@fujprog_git_version@" 7 | #define FUJPROG_BUILD_TIMESTAMP "@_time_stamp@" 8 | 9 | #endif 10 | 11 | -------------------------------------------------------------------------------- /getopt.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */ 2 | /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 2002 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | * 19 | * Sponsored in part by the Defense Advanced Research Projects 20 | * Agency (DARPA) and Air Force Research Laboratory, Air Force 21 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. 22 | */ 23 | /*- 24 | * Copyright (c) 2000 The NetBSD Foundation, Inc. 25 | * All rights reserved. 26 | * 27 | * This code is derived from software contributed to The NetBSD Foundation 28 | * by Dieter Baron and Thomas Klausner. 29 | * 30 | * Redistribution and use in source and binary forms, with or without 31 | * modification, are permitted provided that the following conditions 32 | * are met: 33 | * 1. Redistributions of source code must retain the above copyright 34 | * notice, this list of conditions and the following disclaimer. 35 | * 2. Redistributions in binary form must reproduce the above copyright 36 | * notice, this list of conditions and the following disclaimer in the 37 | * documentation and/or other materials provided with the distribution. 38 | * 39 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 40 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 41 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 49 | * POSSIBILITY OF SUCH DAMAGE. 50 | */ 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ 61 | 62 | #ifdef REPLACE_GETOPT 63 | int opterr = 1; /* if error message should be printed */ 64 | int optind = 1; /* index into parent argv vector */ 65 | int optopt = '?'; /* character checked for validity */ 66 | #undef optreset /* see getopt.h */ 67 | #define optreset __mingw_optreset 68 | int optreset; /* reset getopt */ 69 | char *optarg; /* argument associated with option */ 70 | #endif 71 | 72 | #define PRINT_ERROR ((opterr) && (*options != ':')) 73 | 74 | #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 75 | #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ 76 | #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ 77 | 78 | /* return values */ 79 | #define BADCH (int)'?' 80 | #define BADARG ((*options == ':') ? (int)':' : (int)'?') 81 | #define INORDER (int)1 82 | 83 | #ifndef __CYGWIN__ 84 | #define __progname __argv[0] 85 | #else 86 | extern char __declspec(dllimport) *__progname; 87 | #endif 88 | 89 | #ifdef __CYGWIN__ 90 | static char EMSG[] = ""; 91 | #else 92 | #define EMSG "" 93 | #endif 94 | 95 | static int getopt_internal(int, char * const *, const char *, 96 | const struct option *, int *, int); 97 | static int parse_long_options(char * const *, const char *, 98 | const struct option *, int *, int); 99 | static int gcd(int, int); 100 | static void permute_args(int, int, int, char * const *); 101 | 102 | static char *place = EMSG; /* option letter processing */ 103 | 104 | /* XXX: set optreset to 1 rather than these two */ 105 | static int nonopt_start = -1; /* first non option argument (for permute) */ 106 | static int nonopt_end = -1; /* first option after non options (for permute) */ 107 | 108 | /* Error messages */ 109 | static const char recargchar[] = "option requires an argument -- %c"; 110 | static const char recargstring[] = "option requires an argument -- %s"; 111 | static const char ambig[] = "ambiguous option -- %.*s"; 112 | static const char noarg[] = "option doesn't take an argument -- %.*s"; 113 | static const char illoptchar[] = "unknown option -- %c"; 114 | static const char illoptstring[] = "unknown option -- %s"; 115 | 116 | static void 117 | _vwarnx(const char *fmt,va_list ap) 118 | { 119 | (void)fprintf(stderr,"%s: ",__progname); 120 | if (fmt != NULL) 121 | (void)vfprintf(stderr,fmt,ap); 122 | (void)fprintf(stderr,"\n"); 123 | } 124 | 125 | static void 126 | warnx(const char *fmt,...) 127 | { 128 | va_list ap; 129 | va_start(ap,fmt); 130 | _vwarnx(fmt,ap); 131 | va_end(ap); 132 | } 133 | 134 | /* 135 | * Compute the greatest common divisor of a and b. 136 | */ 137 | static int 138 | gcd(int a, int b) 139 | { 140 | int c; 141 | 142 | c = a % b; 143 | while (c != 0) { 144 | a = b; 145 | b = c; 146 | c = a % b; 147 | } 148 | 149 | return (b); 150 | } 151 | 152 | /* 153 | * Exchange the block from nonopt_start to nonopt_end with the block 154 | * from nonopt_end to opt_end (keeping the same order of arguments 155 | * in each block). 156 | */ 157 | static void 158 | permute_args(int panonopt_start, int panonopt_end, int opt_end, 159 | char * const *nargv) 160 | { 161 | int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 162 | char *swap; 163 | 164 | /* 165 | * compute lengths of blocks and number and size of cycles 166 | */ 167 | nnonopts = panonopt_end - panonopt_start; 168 | nopts = opt_end - panonopt_end; 169 | ncycle = gcd(nnonopts, nopts); 170 | cyclelen = (opt_end - panonopt_start) / ncycle; 171 | 172 | for (i = 0; i < ncycle; i++) { 173 | cstart = panonopt_end+i; 174 | pos = cstart; 175 | for (j = 0; j < cyclelen; j++) { 176 | if (pos >= panonopt_end) 177 | pos -= nnonopts; 178 | else 179 | pos += nopts; 180 | swap = nargv[pos]; 181 | /* LINTED const cast */ 182 | ((char **) nargv)[pos] = nargv[cstart]; 183 | /* LINTED const cast */ 184 | ((char **)nargv)[cstart] = swap; 185 | } 186 | } 187 | } 188 | 189 | /* 190 | * parse_long_options -- 191 | * Parse long options in argc/argv argument vector. 192 | * Returns -1 if short_too is set and the option does not match long_options. 193 | */ 194 | static int 195 | parse_long_options(char * const *nargv, const char *options, 196 | const struct option *long_options, int *idx, int short_too) 197 | { 198 | char *current_argv, *has_equal; 199 | size_t current_argv_len; 200 | int i, ambiguous, match; 201 | 202 | #define IDENTICAL_INTERPRETATION(_x, _y) \ 203 | (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ 204 | long_options[(_x)].flag == long_options[(_y)].flag && \ 205 | long_options[(_x)].val == long_options[(_y)].val) 206 | 207 | current_argv = place; 208 | match = -1; 209 | ambiguous = 0; 210 | 211 | optind++; 212 | 213 | if ((has_equal = strchr(current_argv, '=')) != NULL) { 214 | /* argument found (--option=arg) */ 215 | current_argv_len = has_equal - current_argv; 216 | has_equal++; 217 | } else 218 | current_argv_len = strlen(current_argv); 219 | 220 | for (i = 0; long_options[i].name; i++) { 221 | /* find matching long option */ 222 | if (strncmp(current_argv, long_options[i].name, 223 | current_argv_len)) 224 | continue; 225 | 226 | if (strlen(long_options[i].name) == current_argv_len) { 227 | /* exact match */ 228 | match = i; 229 | ambiguous = 0; 230 | break; 231 | } 232 | /* 233 | * If this is a known short option, don't allow 234 | * a partial match of a single character. 235 | */ 236 | if (short_too && current_argv_len == 1) 237 | continue; 238 | 239 | if (match == -1) /* partial match */ 240 | match = i; 241 | else if (!IDENTICAL_INTERPRETATION(i, match)) 242 | ambiguous = 1; 243 | } 244 | if (ambiguous) { 245 | /* ambiguous abbreviation */ 246 | if (PRINT_ERROR) 247 | warnx(ambig, (int)current_argv_len, 248 | current_argv); 249 | optopt = 0; 250 | return (BADCH); 251 | } 252 | if (match != -1) { /* option found */ 253 | if (long_options[match].has_arg == no_argument 254 | && has_equal) { 255 | if (PRINT_ERROR) 256 | warnx(noarg, (int)current_argv_len, 257 | current_argv); 258 | /* 259 | * XXX: GNU sets optopt to val regardless of flag 260 | */ 261 | if (long_options[match].flag == NULL) 262 | optopt = long_options[match].val; 263 | else 264 | optopt = 0; 265 | return (BADARG); 266 | } 267 | if (long_options[match].has_arg == required_argument || 268 | long_options[match].has_arg == optional_argument) { 269 | if (has_equal) 270 | optarg = has_equal; 271 | else if (long_options[match].has_arg == 272 | required_argument) { 273 | /* 274 | * optional argument doesn't use next nargv 275 | */ 276 | optarg = nargv[optind++]; 277 | } 278 | } 279 | if ((long_options[match].has_arg == required_argument) 280 | && (optarg == NULL)) { 281 | /* 282 | * Missing argument; leading ':' indicates no error 283 | * should be generated. 284 | */ 285 | if (PRINT_ERROR) 286 | warnx(recargstring, 287 | current_argv); 288 | /* 289 | * XXX: GNU sets optopt to val regardless of flag 290 | */ 291 | if (long_options[match].flag == NULL) 292 | optopt = long_options[match].val; 293 | else 294 | optopt = 0; 295 | --optind; 296 | return (BADARG); 297 | } 298 | } else { /* unknown option */ 299 | if (short_too) { 300 | --optind; 301 | return (-1); 302 | } 303 | if (PRINT_ERROR) 304 | warnx(illoptstring, current_argv); 305 | optopt = 0; 306 | return (BADCH); 307 | } 308 | if (idx) 309 | *idx = match; 310 | if (long_options[match].flag) { 311 | *long_options[match].flag = long_options[match].val; 312 | return (0); 313 | } else 314 | return (long_options[match].val); 315 | #undef IDENTICAL_INTERPRETATION 316 | } 317 | 318 | /* 319 | * getopt_internal -- 320 | * Parse argc/argv argument vector. Called by user level routines. 321 | */ 322 | static int 323 | getopt_internal(int nargc, char * const *nargv, const char *options, 324 | const struct option *long_options, int *idx, int flags) 325 | { 326 | const char *oli; /* option letter list index */ 327 | int optchar, short_too; 328 | static int posixly_correct = -1; 329 | 330 | if (options == NULL) 331 | return (-1); 332 | 333 | /* 334 | * XXX Some GNU programs (like cvs) set optind to 0 instead of 335 | * XXX using optreset. Work around this braindamage. 336 | */ 337 | if (optind == 0) 338 | optind = optreset = 1; 339 | 340 | /* 341 | * Disable GNU extensions if POSIXLY_CORRECT is set or options 342 | * string begins with a '+'. 343 | * 344 | * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or 345 | * optreset != 0 for GNU compatibility. 346 | */ 347 | if (posixly_correct == -1 || optreset != 0) 348 | posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 349 | if (*options == '-') 350 | flags |= FLAG_ALLARGS; 351 | else if (posixly_correct || *options == '+') 352 | flags &= ~FLAG_PERMUTE; 353 | if (*options == '+' || *options == '-') 354 | options++; 355 | 356 | optarg = NULL; 357 | if (optreset) 358 | nonopt_start = nonopt_end = -1; 359 | start: 360 | if (optreset || !*place) { /* update scanning pointer */ 361 | optreset = 0; 362 | if (optind >= nargc) { /* end of argument vector */ 363 | place = EMSG; 364 | if (nonopt_end != -1) { 365 | /* do permutation, if we have to */ 366 | permute_args(nonopt_start, nonopt_end, 367 | optind, nargv); 368 | optind -= nonopt_end - nonopt_start; 369 | } 370 | else if (nonopt_start != -1) { 371 | /* 372 | * If we skipped non-options, set optind 373 | * to the first of them. 374 | */ 375 | optind = nonopt_start; 376 | } 377 | nonopt_start = nonopt_end = -1; 378 | return (-1); 379 | } 380 | if (*(place = nargv[optind]) != '-' || 381 | (place[1] == '\0' && strchr(options, '-') == NULL)) { 382 | place = EMSG; /* found non-option */ 383 | if (flags & FLAG_ALLARGS) { 384 | /* 385 | * GNU extension: 386 | * return non-option as argument to option 1 387 | */ 388 | optarg = nargv[optind++]; 389 | return (INORDER); 390 | } 391 | if (!(flags & FLAG_PERMUTE)) { 392 | /* 393 | * If no permutation wanted, stop parsing 394 | * at first non-option. 395 | */ 396 | return (-1); 397 | } 398 | /* do permutation */ 399 | if (nonopt_start == -1) 400 | nonopt_start = optind; 401 | else if (nonopt_end != -1) { 402 | permute_args(nonopt_start, nonopt_end, 403 | optind, nargv); 404 | nonopt_start = optind - 405 | (nonopt_end - nonopt_start); 406 | nonopt_end = -1; 407 | } 408 | optind++; 409 | /* process next argument */ 410 | goto start; 411 | } 412 | if (nonopt_start != -1 && nonopt_end == -1) 413 | nonopt_end = optind; 414 | 415 | /* 416 | * If we have "-" do nothing, if "--" we are done. 417 | */ 418 | if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { 419 | optind++; 420 | place = EMSG; 421 | /* 422 | * We found an option (--), so if we skipped 423 | * non-options, we have to permute. 424 | */ 425 | if (nonopt_end != -1) { 426 | permute_args(nonopt_start, nonopt_end, 427 | optind, nargv); 428 | optind -= nonopt_end - nonopt_start; 429 | } 430 | nonopt_start = nonopt_end = -1; 431 | return (-1); 432 | } 433 | } 434 | 435 | /* 436 | * Check long options if: 437 | * 1) we were passed some 438 | * 2) the arg is not just "-" 439 | * 3) either the arg starts with -- we are getopt_long_only() 440 | */ 441 | if (long_options != NULL && place != nargv[optind] && 442 | (*place == '-' || (flags & FLAG_LONGONLY))) { 443 | short_too = 0; 444 | if (*place == '-') 445 | place++; /* --foo long option */ 446 | else if (*place != ':' && strchr(options, *place) != NULL) 447 | short_too = 1; /* could be short option too */ 448 | 449 | optchar = parse_long_options(nargv, options, long_options, 450 | idx, short_too); 451 | if (optchar != -1) { 452 | place = EMSG; 453 | return (optchar); 454 | } 455 | } 456 | 457 | if ((optchar = (int)*place++) == (int)':' || 458 | (optchar == (int)'-' && *place != '\0') || 459 | (oli = strchr(options, optchar)) == NULL) { 460 | /* 461 | * If the user specified "-" and '-' isn't listed in 462 | * options, return -1 (non-option) as per POSIX. 463 | * Otherwise, it is an unknown option character (or ':'). 464 | */ 465 | if (optchar == (int)'-' && *place == '\0') 466 | return (-1); 467 | if (!*place) 468 | ++optind; 469 | if (PRINT_ERROR) 470 | warnx(illoptchar, optchar); 471 | optopt = optchar; 472 | return (BADCH); 473 | } 474 | if (long_options != NULL && optchar == 'W' && oli[1] == ';') { 475 | /* -W long-option */ 476 | if (*place) /* no space */ 477 | /* NOTHING */; 478 | else if (++optind >= nargc) { /* no arg */ 479 | place = EMSG; 480 | if (PRINT_ERROR) 481 | warnx(recargchar, optchar); 482 | optopt = optchar; 483 | return (BADARG); 484 | } else /* white space */ 485 | place = nargv[optind]; 486 | optchar = parse_long_options(nargv, options, long_options, 487 | idx, 0); 488 | place = EMSG; 489 | return (optchar); 490 | } 491 | if (*++oli != ':') { /* doesn't take argument */ 492 | if (!*place) 493 | ++optind; 494 | } else { /* takes (optional) argument */ 495 | optarg = NULL; 496 | if (*place) /* no white space */ 497 | optarg = place; 498 | else if (oli[1] != ':') { /* arg not optional */ 499 | if (++optind >= nargc) { /* no arg */ 500 | place = EMSG; 501 | if (PRINT_ERROR) 502 | warnx(recargchar, optchar); 503 | optopt = optchar; 504 | return (BADARG); 505 | } else 506 | optarg = nargv[optind]; 507 | } 508 | place = EMSG; 509 | ++optind; 510 | } 511 | /* dump back option letter */ 512 | return (optchar); 513 | } 514 | 515 | #ifdef REPLACE_GETOPT 516 | /* 517 | * getopt -- 518 | * Parse argc/argv argument vector. 519 | * 520 | * [eventually this will replace the BSD getopt] 521 | */ 522 | int 523 | getopt(int nargc, char * const *nargv, const char *options) 524 | { 525 | 526 | /* 527 | * We don't pass FLAG_PERMUTE to getopt_internal() since 528 | * the BSD getopt(3) (unlike GNU) has never done this. 529 | * 530 | * Furthermore, since many privileged programs call getopt() 531 | * before dropping privileges it makes sense to keep things 532 | * as simple (and bug-free) as possible. 533 | */ 534 | return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); 535 | } 536 | #endif /* REPLACE_GETOPT */ 537 | 538 | /* 539 | * getopt_long -- 540 | * Parse argc/argv argument vector. 541 | */ 542 | int 543 | getopt_long(int nargc, char * const *nargv, const char *options, 544 | const struct option *long_options, int *idx) 545 | { 546 | 547 | return (getopt_internal(nargc, nargv, options, long_options, idx, 548 | FLAG_PERMUTE)); 549 | } 550 | 551 | /* 552 | * getopt_long_only -- 553 | * Parse argc/argv argument vector. 554 | */ 555 | int 556 | getopt_long_only(int nargc, char * const *nargv, const char *options, 557 | const struct option *long_options, int *idx) 558 | { 559 | 560 | return (getopt_internal(nargc, nargv, options, long_options, idx, 561 | FLAG_PERMUTE|FLAG_LONGONLY)); 562 | } 563 | -------------------------------------------------------------------------------- /getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef __GETOPT_H__ 2 | /** 3 | * DISCLAIMER 4 | * This file has no copyright assigned and is placed in the Public Domain. 5 | * This file is a part of the w64 mingw-runtime package. 6 | * 7 | * The w64 mingw-runtime package and its code is distributed in the hope that it 8 | * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR 9 | * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to 10 | * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 | */ 12 | 13 | #define __GETOPT_H__ 14 | 15 | /* All the headers include this file. */ 16 | #include 17 | 18 | #if defined( WINGETOPT_SHARED_LIB ) 19 | # if defined( BUILDING_WINGETOPT_DLL ) 20 | # define WINGETOPT_API __declspec(dllexport) 21 | # else 22 | # define WINGETOPT_API __declspec(dllimport) 23 | # endif 24 | #else 25 | # define WINGETOPT_API 26 | #endif 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | WINGETOPT_API extern int optind; /* index of first non-option in argv */ 33 | WINGETOPT_API extern int optopt; /* single option character, as parsed */ 34 | WINGETOPT_API extern int opterr; /* flag to enable built-in diagnostics... */ 35 | /* (user may set to zero, to suppress) */ 36 | 37 | WINGETOPT_API extern char *optarg; /* pointer to argument of current option */ 38 | 39 | extern int getopt(int nargc, char * const *nargv, const char *options); 40 | 41 | #ifdef _BSD_SOURCE 42 | /* 43 | * BSD adds the non-standard `optreset' feature, for reinitialisation 44 | * of `getopt' parsing. We support this feature, for applications which 45 | * proclaim their BSD heritage, before including this header; however, 46 | * to maintain portability, developers are advised to avoid it. 47 | */ 48 | # define optreset __mingw_optreset 49 | extern int optreset; 50 | #endif 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | /* 55 | * POSIX requires the `getopt' API to be specified in `unistd.h'; 56 | * thus, `unistd.h' includes this header. However, we do not want 57 | * to expose the `getopt_long' or `getopt_long_only' APIs, when 58 | * included in this manner. Thus, close the standard __GETOPT_H__ 59 | * declarations block, and open an additional __GETOPT_LONG_H__ 60 | * specific block, only when *not* __UNISTD_H_SOURCED__, in which 61 | * to declare the extended API. 62 | */ 63 | #endif /* !defined(__GETOPT_H__) */ 64 | 65 | #if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) 66 | #define __GETOPT_LONG_H__ 67 | 68 | #ifdef __cplusplus 69 | extern "C" { 70 | #endif 71 | 72 | struct option /* specification for a long form option... */ 73 | { 74 | const char *name; /* option name, without leading hyphens */ 75 | int has_arg; /* does it take an argument? */ 76 | int *flag; /* where to save its status, or NULL */ 77 | int val; /* its associated status value */ 78 | }; 79 | 80 | enum /* permitted values for its `has_arg' field... */ 81 | { 82 | no_argument = 0, /* option never takes an argument */ 83 | required_argument, /* option always requires an argument */ 84 | optional_argument /* option may take an argument */ 85 | }; 86 | 87 | extern int getopt_long(int nargc, char * const *nargv, const char *options, 88 | const struct option *long_options, int *idx); 89 | extern int getopt_long_only(int nargc, char * const *nargv, const char *options, 90 | const struct option *long_options, int *idx); 91 | /* 92 | * Previous MinGW implementation had... 93 | */ 94 | #ifndef HAVE_DECL_GETOPT 95 | /* 96 | * ...for the long form API only; keep this for compatibility. 97 | */ 98 | # define HAVE_DECL_GETOPT 1 99 | #endif 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ 106 | -------------------------------------------------------------------------------- /images/ULX3S-as-FTDI-device.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/ULX3S-as-FTDI-device.PNG -------------------------------------------------------------------------------- /images/ULX3S-as-libusbK-device.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/ULX3S-as-libusbK-device.PNG -------------------------------------------------------------------------------- /images/Uninstall-libusbK-device-step2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/Uninstall-libusbK-device-step2.PNG -------------------------------------------------------------------------------- /images/Uninstall-libusbK-device.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/Uninstall-libusbK-device.PNG -------------------------------------------------------------------------------- /images/Zadig-FTDI-to-libusbK.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/Zadig-FTDI-to-libusbK.PNG -------------------------------------------------------------------------------- /images/Zadig-success.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/Zadig-success.PNG -------------------------------------------------------------------------------- /images/securityblock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kost/fujprog/cc3ea93f2b8d36515a752c8d70be389bf0ed29e8/images/securityblock.png -------------------------------------------------------------------------------- /ulx2s_prep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/csh 2 | 3 | ft232r_flash -p $1 4 | ujprog -p $1 -e fprog.bin ulx2s_8e.jed 5 | ujprog -p $1 -j flash ulx2s_8e.jed 6 | --------------------------------------------------------------------------------