From 533cd64f37cefc851b134525d26ed2aa5a5c84b9 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 24 Nov 2021 07:35:10 +0100 Subject: [PATCH 1/4] lattice: if unknown file type, fails only for SRAM --- src/lattice.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index c2797b4..57cdbf7 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -149,8 +149,11 @@ Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type, _mode = Device::FLASH_MODE; else _mode = Device::MEM_MODE; - } else { - throw std::runtime_error("incompatible file format"); + } else { /* unknown type: */ + if (prg_type == Device::WR_FLASH) /* to flash: OK */ + _mode = Device::FLASH_MODE; + else /* otherwise: KO */ + throw std::runtime_error("incompatible file format"); } } /* check device family */ From 70e9671b3a3becd7276c2ff9d16385215e38c779 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 24 Nov 2021 07:35:33 +0100 Subject: [PATCH 2/4] device: if filename has no extension -> use raw type --- src/device.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/device.cpp b/src/device.cpp index f70c118..cc05ebf 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -19,6 +19,9 @@ Device::Device(Jtag *jtag, string filename, const string &file_type, { if (!file_type.empty()) _file_extension = file_type; + else if (!filename.empty() && (filename.find_last_of(".")) == string::npos) + _file_extension = "raw"; + _jtag = jtag; if (verbose > 0) cout << "File type : " << _file_extension << endl; From 7a19f94f19a164e88e6f68da6d4a35e6e70e8d8b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 25 Nov 2021 08:11:50 +0100 Subject: [PATCH 3/4] add zlib support (currently limited to altera spiOverJtag) --- .github/workflows/Test.yml | 6 +- CMakeLists.txt | 11 +++- scripts/msys2/PKGBUILD | 5 +- src/altera.cpp | 4 ++ src/configBitstreamParser.cpp | 103 ++++++++++++++++++++++++++++++++-- src/configBitstreamParser.hpp | 10 ++++ 6 files changed, 131 insertions(+), 8 deletions(-) diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index 1eb3d7c..0391df3 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -34,7 +34,8 @@ jobs: libhidapi-dev \ libudev-dev \ pkg-config \ - tree + tree \ + zlib1g-dev - name: '🚧 Build tarball' run: | @@ -86,7 +87,8 @@ jobs: sudo apt install -y \ libftdi1-2 \ libhidapi-hidraw0 \ - udev + udev \ + zlib1g - name: '📥 Download artifact: package' uses: actions/download-artifact@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 97e064a..9f5bdcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ if(USE_PKGCONFIG) pkg_check_modules(LIBFTDI REQUIRED libftdi1) pkg_check_modules(LIBUSB REQUIRED libusb-1.0) pkg_check_modules(HIDAPI hidapi-hidraw) + pkg_check_modules(ZLIB zlib) # if hidraw not found try with libusb if(NOT HIDAPI_FOUND) pkg_check_modules(HIDAPI hidapi-libusb) @@ -198,6 +199,13 @@ else() endif() endif(ENABLE_CMSISDAP) +if (ZLIB_FOUND) + include_directories(${ZLIB_INCLUDE_DIRS}) + target_link_libraries(openFPGALoader ${ZLIB_LIBRARIES}) + add_definitions(-DHAS_ZLIB=1) +else() + message("zlib library not found: can't flash intel/altera devices") +endif() endif() if (LINK_CMAKE_THREADS) @@ -205,7 +213,6 @@ if (LINK_CMAKE_THREADS) target_link_libraries(openFPGALoader Threads::Threads) endif() - # libftdi < 1.4 as no usb_addr # libftdi >= 1.5 as purge_buffer obsolete string(REPLACE "." ";" VERSION_LIST ${LIBFTDI_VERSION}) @@ -218,9 +225,11 @@ add_definitions(-DFTDI_VERSION=${FTDI_VAL}) install(TARGETS openFPGALoader DESTINATION bin) file(GLOB BITS_FILES spiOverJtag/spiOverJtag_*.bit) file(GLOB RBF_FILES spiOverJtag/spiOverJtag_*.rbf) +file(GLOB GZ_FILES spiOverJtag/spiOverJtag_*.rbf.gz) install(FILES test_sfl.svf ${BITS_FILES} ${RBF_FILES} + ${GZ_FILES} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/openFPGALoader ) diff --git a/scripts/msys2/PKGBUILD b/scripts/msys2/PKGBUILD index 5812176..08818a4 100644 --- a/scripts/msys2/PKGBUILD +++ b/scripts/msys2/PKGBUILD @@ -7,7 +7,10 @@ pkgdesc="openFPGALoader: universal utility for programming FPGA (mingw-w64)" arch=('any') url="https://github.com/trabucayre/openFPGALoader" license=('Apache-2.0') -depends=("${MINGW_PACKAGE_PREFIX}-libftdi") +depends=( + "${MINGW_PACKAGE_PREFIX}-libftdi" + "${MINGW_PACKAGE_PREFIX}-zlib" +) makedepends=( "${MINGW_PACKAGE_PREFIX}-gcc" "${MINGW_PACKAGE_PREFIX}-cmake" diff --git a/src/altera.cpp b/src/altera.cpp index ca19178..0da83ce 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -156,7 +156,11 @@ bool Altera::load_bridge() // DATA_DIR is defined at compile time. std::string bitname = DATA_DIR "/openFPGALoader/spiOverJtag_"; +#ifdef HAS_ZLIB + bitname += _device_package + ".rbf.gz"; +#else bitname += _device_package + ".rbf"; +#endif std::cout << "use: " << bitname << std::endl; diff --git a/src/configBitstreamParser.cpp b/src/configBitstreamParser.cpp index 67acba8..3cb9289 100644 --- a/src/configBitstreamParser.cpp +++ b/src/configBitstreamParser.cpp @@ -10,6 +10,10 @@ #include #include +#ifdef HAS_ZLIB +#include +#endif + #include "display.hpp" #include "configBitstreamParser.hpp" @@ -23,21 +27,49 @@ ConfigBitstreamParser::ConfigBitstreamParser(const string &filename, int mode, { (void) mode; if (!filename.empty()) { + uint32_t offset = filename.find_last_of("."); + FILE *_fd = fopen(filename.c_str(), "rb"); - if (!_fd) - throw std::runtime_error("Error: fail to open " + _filename); + if (!_fd) { + printf("1\n"); + /* if file not found it's maybe a gz -> try without gz */ + if (offset != string::npos) { + printf("2\n"); + _filename = filename.substr(0, offset); + printf("%s\n", _filename.c_str()); + _fd = fopen(_filename.c_str(), "rb"); + } + + /* test again */ + if (!_fd) + throw std::runtime_error("Error: fail to open " + filename); + } fseek(_fd, 0, SEEK_END); _file_size = ftell(_fd); fseek(_fd, 0, SEEK_SET); _raw_data.resize(_file_size); - _bit_data.reserve(_file_size); int ret = fread((char *)&_raw_data[0], sizeof(char), _file_size, _fd); + fclose(_fd); if (ret != _file_size) throw std::runtime_error("Error: fail to read " + _filename); - fclose(_fd); + + if (offset != string::npos) { + string extension = _filename.substr(_filename.find_last_of(".") +1); + if (extension == "gz" || extension == "gzip") { + string tmp; + tmp.reserve(_file_size); + if (!decompress_bitstream(_raw_data, &tmp)) + throw std::runtime_error("Error: decompress failed"); + _raw_data.clear(); + _raw_data.append(std::move(tmp)); + _file_size = _raw_data.size(); + } + } + _bit_data.reserve(_file_size); + } else if (!isatty(fileno(stdin))) { _file_size = 0; string tmp; @@ -119,3 +151,66 @@ uint8_t ConfigBitstreamParser::reverseByte(uint8_t src) return revertByteArr[src]; #endif } + +bool ConfigBitstreamParser::decompress_bitstream(string source, string *dest) +{ +#ifndef HAS_ZLIB + (void)source; + (void)dest; + printError("openFPGALoader is build without zlib support\n" + "can't uncompress file\n"); + return false; +#else +#define CHUNK 16384 + int ret; + unsigned have; + z_stream strm; + unsigned char *in = (unsigned char *)&source[0]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 15+16); + if (ret != Z_OK) + return ret; + + uint32_t pos = source.size(); + uint32_t xfer = CHUNK; + + /* decompress until deflate stream ends or end of file */ + do { + /* if buffer has a size < CHUNK */ + if (pos < CHUNK) + xfer = pos; + strm.next_in = in; // chunk to uncompress + strm.avail_in = xfer; // chunk size + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; // specify buffer size + strm.next_out = out; // buffer + ret = inflate(&strm, Z_BLOCK); + if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR + || ret == Z_MEM_ERROR) { + (void)inflateEnd(&strm); + return false; + } + have = CHUNK - strm.avail_out; // compute data size + // after uncompress + dest->append((const char*)out, have); // store + } while (strm.avail_in != 0); + in += xfer; // update input buffer position + pos -= xfer; // update len to decompress + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END; +#endif +} diff --git a/src/configBitstreamParser.hpp b/src/configBitstreamParser.hpp index eb518bb..fe7a66c 100644 --- a/src/configBitstreamParser.hpp +++ b/src/configBitstreamParser.hpp @@ -47,6 +47,16 @@ class ConfigBitstreamParser { static uint8_t reverseByte(uint8_t src); + private: + /** + * \brief decompress bitstream in gzip format + * \param[in] source: raw compressed data + * \param[out] dest: raw uncompressed data + * \return false if openFPGALoader is build without zlib or + * if uncompress fails + */ + bool decompress_bitstream(std::string source, std::string *dest); + protected: std::string _filename; int _bit_length; From 801f6b1eb2eda48aa3c8a89f48326092fabcf274 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 25 Nov 2021 08:38:35 +0100 Subject: [PATCH 4/4] INSTALL.md: add zlib1g-dev --- INSTALL.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index 8596914..eb8f04f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -24,7 +24,8 @@ sudo dnf install openFPGALoader This application uses **libftdi1**, so this library must be installed (and, depending of the distribution, headers too) ```bash -apt-get install libftdi1-2 libftdi1-dev libhidapi-hidraw0 libhidapi-dev libudev-dev cmake pkg-config make g++ +apt-get install libftdi1-2 libftdi1-dev libhidapi-hidraw0 libhidapi-dev libudev-dev \ + zlib1g-dev cmake pkg-config make g++ ``` **libudev-dev** is optional, may be replaced by **eudev-dev** or just not installed.