From df52d523bfa6016665bc4bd344ec9b28bdf99608 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Sun, 21 Feb 2021 18:30:13 +0100 Subject: [PATCH] All devices: new CLI argument to bypass file type autodetection --- README.md | 7 +++++++ src/altera.cpp | 7 ++++--- src/altera.hpp | 3 ++- src/anlogic.cpp | 10 +++++++--- src/anlogic.hpp | 1 + src/device.cpp | 5 ++++- src/device.hpp | 3 ++- src/efinix.cpp | 5 +++-- src/efinix.hpp | 1 + src/gowin.cpp | 10 ++++++---- src/gowin.hpp | 3 ++- src/ice40.cpp | 5 +++-- src/ice40.hpp | 1 + src/lattice.cpp | 18 ++++++++++-------- src/lattice.hpp | 3 ++- src/main.cpp | 37 +++++++++++++++++++++---------------- src/xilinx.cpp | 9 +++++---- src/xilinx.hpp | 1 + 18 files changed, 82 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index f14acd1..ec372a3 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,8 @@ openFPGALoader -- a program to flash FPGA --ftdi-channel arg FTDI chip channel number (channels 0-3 map to A-D) -d, --device arg device to use (/dev/ttyUSBx) --detect detect FPGA + --file-type arg provides file type instead of let's deduced by + using extension --freq arg jtag frequency (Hz) -f, --write-flash write bitstream in flash (default: false, only for Gowin and ECP5 devices) @@ -205,6 +207,11 @@ openFPGALoader [options] -r openFPGALoader [options] /path/to/bitstream.ext ``` +#### Automatic file type detection bypass + +Default behavior is to use file extension to determine file parser. To avoid +this mecanism `--file-type type` must be used. + #### bitbang mode and pins configuration *FT232R* and *ft231X* may be used as JTAG programmer. JTAG communications are diff --git a/src/altera.cpp b/src/altera.cpp index 5061cc9..04c3824 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -16,10 +16,11 @@ // DATA_DIR is defined at compile time. #define BIT_FOR_FLASH (DATA_DIR "/openFPGALoader/test_sfl.svf") -Altera::Altera(Jtag *jtag, const std::string &filename, int8_t verbose): - Device(jtag, filename, verbose), _svf(_jtag, _verbose) +Altera::Altera(Jtag *jtag, const std::string &filename, + const std::string &file_type, int8_t verbose): + Device(jtag, filename, file_type, verbose), _svf(_jtag, _verbose) { - if (_filename != "") { + if (!_file_extension.empty()) { if (_file_extension == "svf" || _file_extension == "rbf") _mode = Device::MEM_MODE; else diff --git a/src/altera.hpp b/src/altera.hpp index 0a9aaaf..68baf5e 100644 --- a/src/altera.hpp +++ b/src/altera.hpp @@ -9,7 +9,8 @@ class Altera: public Device { public: - Altera(Jtag *jtag, const std::string &filename, int8_t verbose); + Altera(Jtag *jtag, const std::string &filename, + const std::string &file_type, int8_t verbose); ~Altera(); void programMem(); diff --git a/src/anlogic.cpp b/src/anlogic.cpp index 8b53983..496f3e4 100644 --- a/src/anlogic.cpp +++ b/src/anlogic.cpp @@ -16,6 +16,9 @@ */ #include + +#include + #include "anlogic.hpp" #include "anlogicBitParser.hpp" #include "jtag.hpp" @@ -34,10 +37,11 @@ #define IRLENGTH 8 Anlogic::Anlogic(Jtag *jtag, const std::string &filename, + const std::string &file_type, Device::prog_type_t prg_type, int8_t verbose): - Device(jtag, filename, verbose), _svf(_jtag, _verbose) + Device(jtag, filename, file_type, verbose), _svf(_jtag, _verbose) { - if (_filename != "") { + if (!_file_extension.empty()) { if (_file_extension == "svf") _mode = Device::MEM_MODE; else if (_file_extension == "bit") { @@ -46,7 +50,7 @@ Anlogic::Anlogic(Jtag *jtag, const std::string &filename, else _mode = Device::SPI_MODE; } else - throw std::exception(); + throw std::runtime_error("incompatible file format"); } } Anlogic::~Anlogic() diff --git a/src/anlogic.hpp b/src/anlogic.hpp index 7e20db8..0031227 100644 --- a/src/anlogic.hpp +++ b/src/anlogic.hpp @@ -29,6 +29,7 @@ class Anlogic: public Device, SPIInterface { public: Anlogic(Jtag *jtag, const std::string &filename, + const std::string &file_type, Device::prog_type_t prg_type, int8_t verbose); ~Anlogic(); diff --git a/src/device.cpp b/src/device.cpp index def41ee..2bc40b4 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -5,11 +5,14 @@ using namespace std; -Device::Device(Jtag *jtag, string filename, int8_t verbose): +Device::Device(Jtag *jtag, string filename, const string &file_type, + int8_t verbose): _filename(filename), _file_extension(filename.substr(filename.find_last_of(".") +1)), _mode(NONE_MODE), _verbose(verbose > 0), _quiet(verbose < 0) { + if (!file_type.empty()) + _file_extension = file_type; _jtag = jtag; if (verbose > 0) cout << "File type : " << _file_extension << endl; diff --git a/src/device.hpp b/src/device.hpp index fe9ddaa..36d04d5 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -25,7 +25,8 @@ class Device { WR_FLASH = 1 } prog_type_t; - Device(Jtag *jtag, std::string filename, int8_t verbose = false); + Device(Jtag *jtag, std::string filename, const std::string &file_type, + int8_t verbose = false); virtual ~Device(); virtual void program(unsigned int offset = 0) = 0; virtual int idCode() = 0; diff --git a/src/efinix.cpp b/src/efinix.cpp index 09f4d58..52c99ed 100644 --- a/src/efinix.cpp +++ b/src/efinix.cpp @@ -31,9 +31,10 @@ #include "spiFlash.hpp" Efinix::Efinix(FtdiSpi* spi, const std::string &filename, + const std::string &file_type, uint16_t rst_pin, uint16_t done_pin, int8_t verbose): - Device(NULL, filename, verbose), _rst_pin(rst_pin), + Device(NULL, filename, file_type, verbose), _rst_pin(rst_pin), _done_pin(done_pin) { _spi = spi; @@ -65,7 +66,7 @@ void Efinix::program(unsigned int offset) { uint32_t timeout = 1000; - if (_filename == "") + if (_file_extension.empty()) return; ConfigBitstreamParser *bit; diff --git a/src/efinix.hpp b/src/efinix.hpp index 219f788..62de308 100644 --- a/src/efinix.hpp +++ b/src/efinix.hpp @@ -26,6 +26,7 @@ class Efinix: public Device { public: Efinix(FtdiSpi *spi, const std::string &filename, + const std::string &file_type, uint16_t rst_pin, uint16_t done_pin, int8_t verbose); ~Efinix(); diff --git a/src/gowin.cpp b/src/gowin.cpp index 70bdfe8..cfb00a4 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -69,11 +69,13 @@ using namespace std; #define EF_PROGRAM 0x71 #define EFLASH_ERASE 0x75 -Gowin::Gowin(Jtag *jtag, const string filename, Device::prog_type_t prg_type, - int8_t verbose): Device(jtag, filename, verbose), is_gw1n1(false) +Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, + Device::prog_type_t prg_type, + int8_t verbose): Device(jtag, filename, file_type, verbose), + is_gw1n1(false) { _fs = NULL; - if (_filename != "") { + if (!_file_extension.empty()) { if (_file_extension == "fs") { if (prg_type == Device::WR_FLASH) _mode = Device::FLASH_MODE; @@ -161,7 +163,7 @@ void Gowin::program(unsigned int offset) uint32_t status; int length; - if (_filename == "" || !_fs) + if (_mode == NONE_MODE || !_fs) return; if (_mode == FLASH_MODE) { diff --git a/src/gowin.hpp b/src/gowin.hpp index b1559d3..ab29f9c 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -30,7 +30,8 @@ class Gowin: public Device { public: - Gowin(Jtag *jtag, std::string filename, Device::prog_type_t prg_type, + Gowin(Jtag *jtag, std::string filename, const std::string &file_type, + Device::prog_type_t prg_type, int8_t verbose); ~Gowin(); int idCode() override; diff --git a/src/ice40.cpp b/src/ice40.cpp index 4ebe39f..8f3c241 100644 --- a/src/ice40.cpp +++ b/src/ice40.cpp @@ -30,9 +30,10 @@ #include "spiFlash.hpp" Ice40::Ice40(FtdiSpi* spi, const std::string &filename, + const std::string &file_type, uint16_t rst_pin, uint16_t done_pin, int8_t verbose): - Device(NULL, filename, verbose), _rst_pin(rst_pin), + Device(NULL, filename, file_type, verbose), _rst_pin(rst_pin), _done_pin(done_pin) { _spi = spi; @@ -64,7 +65,7 @@ void Ice40::program(unsigned int offset) { uint32_t timeout = 1000; - if (_filename == "") + if (_file_extension.empty()) return; RawParser bit(_filename, false); diff --git a/src/ice40.hpp b/src/ice40.hpp index 1f5b81a..a28097e 100644 --- a/src/ice40.hpp +++ b/src/ice40.hpp @@ -26,6 +26,7 @@ class Ice40: public Device { public: Ice40(FtdiSpi *spi, const std::string &filename, + const std::string &file_type, uint16_t rst_pin, uint16_t done_pin, int8_t verbose); ~Ice40(); diff --git a/src/lattice.cpp b/src/lattice.cpp index 8a98b16..c3738df 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "jtag.hpp" #include "lattice.hpp" @@ -67,11 +68,11 @@ using namespace std; # define REG_STATUS_CNF_CHK_MASK (0x7 << 23) # define REG_STATUS_EXEC_ERR (1 << 26) -Lattice::Lattice(Jtag *jtag, const string filename, +Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type, Device::prog_type_t prg_type, int8_t verbose): - Device(jtag, filename, verbose), _fpga_family(UNKNOWN_FAMILY) + Device(jtag, filename, file_type, verbose), _fpga_family(UNKNOWN_FAMILY) { - if (_filename != "") { + if (!_file_extension.empty()) { if (_file_extension == "jed" || _file_extension == "mcs") { _mode = Device::FLASH_MODE; } else if (_file_extension == "bit") { @@ -83,7 +84,7 @@ Lattice::Lattice(Jtag *jtag, const string filename, // for raw bin to flash at offset != 0 _mode = Device::FLASH_MODE; } else { - throw std::exception(); + throw std::runtime_error("incompatible file format"); } } /* check device family */ @@ -162,7 +163,7 @@ bool Lattice::program_mem() bool err; LatticeBitParser _bit(_filename, _verbose); - printInfo("Open file " + _filename + " ", false); + printInfo("Open file ", false); printSuccess("DONE"); err = _bit.parse(); @@ -280,12 +281,12 @@ bool Lattice::program_intFlash() bool err; uint64_t featuresRow; uint16_t feabits; - uint8_t eraseMode; + uint8_t eraseMode = 0; vector ufm_data, cfg_data, ebr_data; JedParser _jed(_filename, _verbose); - printInfo("Open file " + _filename + " ", false); + printInfo("Open file ", false); printSuccess("DONE"); err = _jed.parse(); @@ -422,7 +423,7 @@ bool Lattice::program_extFlash(unsigned int offset) _bit = new RawParser(_filename, false); } - printInfo("Open file " + _filename + " ", false); + printInfo("Open file ", false); printSuccess("DONE"); int err = _bit->parse(); @@ -430,6 +431,7 @@ bool Lattice::program_extFlash(unsigned int offset) printInfo("Parse file ", false); if (err == EXIT_FAILURE) { printError("FAIL"); + delete _bit; return false; } else { printSuccess("DONE"); diff --git a/src/lattice.hpp b/src/lattice.hpp index ccf8919..fe523ab 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -31,7 +31,8 @@ class Lattice: public Device, SPIInterface { public: - Lattice(Jtag *jtag, std::string filename, Device::prog_type_t prg_type, + Lattice(Jtag *jtag, std::string filename, const std::string &file_type, + Device::prog_type_t prg_type, int8_t verbose); int idCode() override; int userCode(); diff --git a/src/main.cpp b/src/main.cpp index 6d2498f..31588e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,7 @@ struct arguments { Device::prog_type_t prg_type; bool is_list_command; bool spi; + string file_type; }; int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *pins_config); @@ -75,7 +76,7 @@ int main(int argc, char **argv) /* command line args. */ struct arguments args = {0, false, false, 0, "", "", "-", "", -1, 6000000, "-", - false, false, false, false, Device::WR_SRAM, false, false}; + false, false, false, false, Device::WR_SRAM, false, false, ""}; /* parse arguments */ try { if (parse_opt(argc, argv, &args, &pins_config)) @@ -166,12 +167,12 @@ int main(int argc, char **argv) } if (board->manufacturer == "efinix") { - Efinix target(spi, args.bit_file, board->reset_pin, board->done_pin, - args.verbose); + Efinix target(spi, args.bit_file, args.file_type, + board->reset_pin, board->done_pin, args.verbose); target.program(args.offset); } else if (board->manufacturer == "lattice") { - Ice40 target(spi, args.bit_file, board->reset_pin, board->done_pin, - args.verbose); + Ice40 target(spi, args.bit_file, args.file_type, + board->reset_pin, board->done_pin, args.verbose); target.program(args.offset); } else { RawParser *bit = NULL; @@ -185,7 +186,7 @@ int main(int argc, char **argv) flash.reset(); flash.read_id(); - if (!args.bit_file.empty()) { + if (!args.bit_file.empty() || !args.file_type.empty()) { printInfo("Open file " + args.bit_file + " ", false); try { bit = new RawParser(args.bit_file, false); @@ -267,26 +268,27 @@ int main(int argc, char **argv) Device *fpga; try { if (fab == "xilinx") { - fpga = new Xilinx(jtag, args.bit_file, args.prg_type, - args.verbose); + fpga = new Xilinx(jtag, args.bit_file, args.file_type, + args.prg_type, args.verbose); } else if (fab == "altera") { - fpga = new Altera(jtag, args.bit_file, args.verbose); + fpga = new Altera(jtag, args.bit_file, args.file_type, + args.verbose); } else if (fab == "anlogic") { - fpga = new Anlogic(jtag, args.bit_file, args.prg_type, - args.verbose); + fpga = new Anlogic(jtag, args.bit_file, args.file_type, + args.prg_type, args.verbose); } else if (fab == "Gowin") { - fpga = new Gowin(jtag, args.bit_file, args.prg_type, - args.verbose); + fpga = new Gowin(jtag, args.bit_file, args.file_type, + args.prg_type, args.verbose); } else if (fab == "lattice") { - fpga = new Lattice(jtag, args.bit_file, args.prg_type, - args.verbose); + fpga = new Lattice(jtag, args.bit_file, args.file_type, + args.prg_type, args.verbose); } else { printError("Error: manufacturer " + fab + " not supported"); delete(jtag); return EXIT_FAILURE; } } catch (std::exception &e) { - printError("Error: Failed to claim FPGA device"); + printError("Error: Failed to claim FPGA device: " + string(e.what())); delete(jtag); return EXIT_FAILURE; } @@ -366,6 +368,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p #endif ("detect", "detect FPGA", cxxopts::value(args->detect)) + ("file-type", "provides file type instead of let's deduced by using extension", + cxxopts::value(args->file_type)) ("freq", "jtag frequency (Hz)", cxxopts::value(freqo)) ("f,write-flash", "write bitstream in flash (default: false, only for Gowin and ECP5 devices)") @@ -499,6 +503,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p args->is_list_command = true; if (args->bit_file.empty() && + args->file_type.empty() && !args->is_list_command && !args->detect && !args->reset) { diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 16df4bb..1a70916 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -14,10 +14,11 @@ #include "progressBar.hpp" Xilinx::Xilinx(Jtag *jtag, const std::string &filename, + const std::string &file_type, Device::prog_type_t prg_type, int8_t verbose): - Device(jtag, filename, verbose) + Device(jtag, filename, file_type, verbose) { - if (_filename != ""){ + if (!_file_extension.empty()) { if (_file_extension == "mcs") { _mode = Device::SPI_MODE; } else if (_file_extension == "bit" || _file_extension == "bin") { @@ -83,7 +84,7 @@ void Xilinx::program(unsigned int offset) if (_mode == Device::MEM_MODE) reverse = true; - printInfo("Open file " + _filename + " ", false); + printInfo("Open file ", false); try { if (_file_extension == "bit") bit = new BitParser(_filename, reverse, _verbose); @@ -138,7 +139,7 @@ void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset) void Xilinx::program_mem(ConfigBitstreamParser *bitfile) { - if (_filename == "") return; + if (_file_extension.empty()) return; std::cout << "load program" << std::endl; unsigned char tx_buf, rx_buf; /* comment TDI TMS TCK diff --git a/src/xilinx.hpp b/src/xilinx.hpp index 4a29728..80c543b 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -11,6 +11,7 @@ class Xilinx: public Device, SPIInterface { public: Xilinx(Jtag *jtag, const std::string &filename, + const std::string &file_type, Device::prog_type_t prg_type, int8_t verbose); ~Xilinx();