All devices: new CLI argument to bypass file type autodetection

This commit is contained in:
Gwenhael Goavec-Merou 2021-02-21 18:30:13 +01:00
parent 7cc5676e8e
commit df52d523bf
18 changed files with 82 additions and 47 deletions

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -16,6 +16,9 @@
*/
#include <string.h>
#include <stdexcept>
#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()

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -23,6 +23,7 @@
#include <unistd.h>
#include <iostream>
#include <stdexcept>
#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<string> 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");

View File

@ -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();

View File

@ -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<bool>(args->detect))
("file-type", "provides file type instead of let's deduced by using extension",
cxxopts::value<string>(args->file_type))
("freq", "jtag frequency (Hz)", cxxopts::value<string>(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) {

View File

@ -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

View File

@ -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();