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;