diff --git a/README.md b/README.md index 4927f12..2c6c854 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,7 @@ openFPGALoader -- a program to flash FPGA --spi SPI mode (only for FTDI in serial mode) -v, --verbose Produce verbose output -h, --help Give this help list + --verify Verify write operation (SPI Flash only) -V, --Version Print program version Mandatory or optional arguments to long options are also mandatory or optional diff --git a/src/altera.cpp b/src/altera.cpp index 1f677a7..7a135b2 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -18,7 +18,7 @@ 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) + Device(jtag, filename, file_type, false, verbose), _svf(_jtag, _verbose) { if (!_file_extension.empty()) { if (_file_extension == "svf" || _file_extension == "rbf") diff --git a/src/anlogic.cpp b/src/anlogic.cpp index 527a5f6..4a29661 100644 --- a/src/anlogic.cpp +++ b/src/anlogic.cpp @@ -40,7 +40,7 @@ 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, file_type, verbose), _svf(_jtag, _verbose) + Device(jtag, filename, file_type, false, verbose), _svf(_jtag, _verbose) { if (!_file_extension.empty()) { if (_file_extension == "svf") diff --git a/src/device.cpp b/src/device.cpp index 2bc40b4..401a822 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -6,10 +6,11 @@ using namespace std; Device::Device(Jtag *jtag, string filename, const string &file_type, - int8_t verbose): + bool verify, int8_t verbose): _filename(filename), _file_extension(filename.substr(filename.find_last_of(".") +1)), - _mode(NONE_MODE), _verbose(verbose > 0), _quiet(verbose < 0) + _mode(NONE_MODE), _verify(verify), _verbose(verbose > 0), + _quiet(verbose < 0) { if (!file_type.empty()) _file_extension = file_type; diff --git a/src/device.hpp b/src/device.hpp index 36d04d5..bc2ba88 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -26,7 +26,7 @@ class Device { } prog_type_t; Device(Jtag *jtag, std::string filename, const std::string &file_type, - int8_t verbose = false); + bool verify, int8_t verbose = false); virtual ~Device(); virtual void program(unsigned int offset = 0) = 0; virtual int idCode() = 0; @@ -37,6 +37,7 @@ class Device { std::string _filename; std::string _file_extension; enum prog_mode _mode; + bool _verify; /**< verify flash write */ bool _verbose; bool _quiet; }; diff --git a/src/efinix.cpp b/src/efinix.cpp index 9798677..d7c6dd6 100644 --- a/src/efinix.cpp +++ b/src/efinix.cpp @@ -34,7 +34,7 @@ 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, file_type, verbose), _rst_pin(rst_pin), + Device(NULL, filename, file_type, false, verbose), _rst_pin(rst_pin), _done_pin(done_pin) { _spi = spi; diff --git a/src/gowin.cpp b/src/gowin.cpp index 4e76e00..ab5c36b 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -71,7 +71,7 @@ using namespace std; 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), + int8_t verbose): Device(jtag, filename, file_type, false, verbose), is_gw1n1(false) { _fs = NULL; diff --git a/src/ice40.cpp b/src/ice40.cpp index 8f3c241..56bb6ed 100644 --- a/src/ice40.cpp +++ b/src/ice40.cpp @@ -33,7 +33,7 @@ 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, file_type, verbose), _rst_pin(rst_pin), + Device(NULL, filename, file_type, false, verbose), _rst_pin(rst_pin), _done_pin(done_pin) { _spi = spi; diff --git a/src/lattice.cpp b/src/lattice.cpp index 9ae998e..ff3918c 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -69,8 +69,9 @@ using namespace std; # define REG_STATUS_EXEC_ERR (1 << 26) Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type, - Device::prog_type_t prg_type, int8_t verbose): - Device(jtag, filename, file_type, verbose), _fpga_family(UNKNOWN_FAMILY) + Device::prog_type_t prg_type, bool verify, int8_t verbose): + Device(jtag, filename, file_type, verify, verbose), + _fpga_family(UNKNOWN_FAMILY) { if (!_file_extension.empty()) { if (_file_extension == "jed" || _file_extension == "mcs") { @@ -358,8 +359,10 @@ bool Lattice::program_intFlash() return false; } /* verify write */ - if (Verify(cfg_data) == false) - return false; + if (_verify) { + if (Verify(cfg_data) == false) + return false; + } /* missing usercode update */ @@ -454,6 +457,31 @@ bool Lattice::program_extFlash(unsigned int offset) flash.read_status_reg(); flash.erase_and_prog(offset, data, length); + if (_verify) { + printInfo("Verifying write"); + string verify_data; + verify_data.resize(length); + printInfo("Read flash ", false); + if (0 != flash.read(offset, (uint8_t*)&verify_data[0], length)) { + printError("FAIL"); + return false; + } else { + printSuccess("DONE"); + } + + ProgressBar progress("Check", length, 50, _quiet); + for (int i = 0; i < length; i++) { + if ((uint8_t)verify_data[i] != data[i]) { + progress.fail(); + printError("Verification failed at " + + std::to_string(offset + i)); + return false; + } + progress.display(i); + } + progress.done(); + } + delete _bit; return true; } diff --git a/src/lattice.hpp b/src/lattice.hpp index fe523ab..8dfcdb2 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -32,7 +32,7 @@ class Lattice: public Device, SPIInterface { public: Lattice(Jtag *jtag, std::string filename, const std::string &file_type, - Device::prog_type_t prg_type, + Device::prog_type_t prg_type, bool verify, int8_t verbose); int idCode() override; int userCode(); diff --git a/src/main.cpp b/src/main.cpp index a957cd6..5d055b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,7 +46,7 @@ using namespace std; struct arguments { int8_t verbose; - bool reset, detect; + bool reset, detect, verify; unsigned int offset; string bit_file; string device; @@ -80,9 +80,9 @@ int main(int argc, char **argv) jtag_pins_conf_t pins_config = {0, 0, 0, 0}; /* command line args. */ - struct arguments args = {0, false, false, 0, "", "", "-", "", -1, 6000000, "-", - false, false, false, false, Device::WR_SRAM, false, false, false, "", - "", "", -1}; + struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, + 6000000, "-", false, false, false, false, Device::WR_SRAM, false, + false, false, "", "", "", -1}; /* parse arguments */ try { if (parse_opt(argc, argv, &args, &pins_config)) @@ -355,7 +355,7 @@ int main(int argc, char **argv) try { if (fab == "xilinx") { fpga = new Xilinx(jtag, args.bit_file, args.file_type, - args.prg_type, args.fpga_part, args.verbose); + args.prg_type, args.fpga_part, args.verify, args.verbose); } else if (fab == "altera") { fpga = new Altera(jtag, args.bit_file, args.file_type, args.verbose); @@ -367,7 +367,7 @@ int main(int argc, char **argv) args.prg_type, args.verbose); } else if (fab == "lattice") { fpga = new Lattice(jtag, args.bit_file, args.file_type, - args.prg_type, args.verbose); + args.prg_type, args.verify, args.verbose); } else { printError("Error: manufacturer " + fab + " not supported"); delete(jtag); @@ -485,6 +485,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p cxxopts::value(args->spi)) ("v,verbose", "Produce verbose output", cxxopts::value(verbose)) ("h,help", "Give this help list") + ("verify", "Verify write operation (SPI Flash only)", + cxxopts::value(args->verify)) ("V,Version", "Print program version"); options.parse_positional({"bitstream"}); diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 571eabe..834dfff 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -17,8 +17,9 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename, const std::string &file_type, Device::prog_type_t prg_type, - std::string device_package, int8_t verbose): - Device(jtag, filename, file_type, verbose),_device_package(device_package) + std::string device_package, bool verify, int8_t verbose): + Device(jtag, filename, file_type, verify, verbose), + _device_package(device_package) { if (!_file_extension.empty()) { if (_file_extension == "mcs") { @@ -146,11 +147,44 @@ void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset) throw std::runtime_error(e.what()); } + uint8_t *data = bit->getData(); + int length = bit->getLength() / 8; + SPIFlash spiFlash(this, (_verbose ? 1 : (_quiet ? -1 : 0))); spiFlash.reset(); spiFlash.read_id(); spiFlash.read_status_reg(); - spiFlash.erase_and_prog(offset, bit->getData(), bit->getLength()/8); + spiFlash.erase_and_prog(offset, data, length); + + /* verify write if required */ + if (_verify) { + std::string verify_data; + verify_data.resize(256); + + ProgressBar progress("Verifying write", length, 50, _quiet); + int rd_length = 256; + for (int i = 0; i < length; i+=rd_length) { + if (rd_length + i > length) + rd_length = length - i; + if (0 != spiFlash.read(offset + i, (uint8_t*)&verify_data[0], + rd_length)) { + progress.fail(); + printError("Failed to read flash"); + return; + } + + for (int ii = 0; ii < rd_length; ii++) { + if ((uint8_t)verify_data[ii] != data[i + ii]) { + progress.fail(); + printError("Verification failed at " + + std::to_string(offset + i + ii)); + return; + } + } + progress.display(i); + } + progress.done(); + } } void Xilinx::program_mem(ConfigBitstreamParser *bitfile) diff --git a/src/xilinx.hpp b/src/xilinx.hpp index 5304c1d..ed1c3c7 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -13,7 +13,8 @@ class Xilinx: public Device, SPIInterface { Xilinx(Jtag *jtag, const std::string &filename, const std::string &file_type, Device::prog_type_t prg_type, - std::string device_package, int8_t verbose); + std::string device_package, + bool verify, int8_t verbose); ~Xilinx(); void program(unsigned int offset = 0) override;