diff --git a/README.md b/README.md index b33f12d..b428d30 100644 --- a/README.md +++ b/README.md @@ -205,10 +205,28 @@ openFPGALoader [options] -r ``` #### load bitstream device (memory or flash) + ```bash openFPGALoader [options] /path/to/bitstream.ext ``` +##### Using pipe + +```bash +cat /path/to/bitstream.ext | openFPGALoader --file-type ext [options] +``` + +`--file-type` is required to detect file type + +Note: It's possible to load a bitstream through network: + +```bash +# FPGA side +nc -lp port | openFPGALoader --filetype xxx [option +# Bitstream side +nc -q 0 host port < /path/to/bitstream.ext +``` + #### Automatic file type detection bypass Default behavior is to use file extension to determine file parser. To avoid diff --git a/src/anlogic.cpp b/src/anlogic.cpp index 496f3e4..a718fb2 100644 --- a/src/anlogic.cpp +++ b/src/anlogic.cpp @@ -23,6 +23,7 @@ #include "anlogicBitParser.hpp" #include "jtag.hpp" #include "device.hpp" +#include "display.hpp" #include "progressBar.hpp" #include "spiFlash.hpp" @@ -76,7 +77,18 @@ void Anlogic::program(unsigned int offset) } AnlogicBitParser bit(_filename, (_mode == Device::MEM_MODE), _verbose); - bit.parse(); + + printInfo("Parse file ", false); + if (bit.parse() == EXIT_FAILURE) { + printError("FAIL"); + return; + } else { + printSuccess("DONE"); + } + + if (_verbose) + bit.displayHeader(); + uint8_t *data = bit.getData(); int len = bit.getLength() / 8; diff --git a/src/anlogicBitParser.cpp b/src/anlogicBitParser.cpp index 7eb2069..e403e29 100644 --- a/src/anlogicBitParser.cpp +++ b/src/anlogicBitParser.cpp @@ -42,21 +42,12 @@ AnlogicBitParser::~AnlogicBitParser() { } -void AnlogicBitParser::displayHeader() -{ - cout << "Anlogic bitstream header infos" << endl; - for (auto it = _hdr.begin(); it != _hdr.end(); it++) { - cout << (*it).first << ": " << (*it).second << endl; - } -} - /* read all ascii lines starting with '#' * stop when an empty line is found */ int AnlogicBitParser::parseHeader() { int ret = 0; - printInfo("parseHeader"); string buffer; istringstream lineStream(_raw_data); @@ -71,7 +62,7 @@ int AnlogicBitParser::parseHeader() if (buffer[0] != '#') { printError("header must start with #\n"); - return EXIT_FAILURE; + return -1; } string content = buffer.substr(2); // drop '# ' @@ -96,12 +87,6 @@ int AnlogicBitParser::parseHeader() int AnlogicBitParser::parse() { int end_header = 0; - /* fill raw buffer with file content */ - _fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); - if (_fd.gcount() != _file_size) { - printError("Error: fails to read full file content"); - return EXIT_FAILURE; - } /* parse header */ if ((end_header = parseHeader()) == -1) diff --git a/src/anlogicBitParser.hpp b/src/anlogicBitParser.hpp index ca8e071..6d1f516 100644 --- a/src/anlogicBitParser.hpp +++ b/src/anlogicBitParser.hpp @@ -34,7 +34,6 @@ class AnlogicBitParser: public ConfigBitstreamParser { bool verbose = false); ~AnlogicBitParser(); int parse() override; - void displayHeader(); private: int parseHeader(); diff --git a/src/bitparser.cpp b/src/bitparser.cpp index 349cf20..785725a 100644 --- a/src/bitparser.cpp +++ b/src/bitparser.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #ifndef _WIN32 #include #else @@ -20,98 +23,91 @@ BitParser::BitParser(const string &filename, bool reverseOrder, bool verbose): verbose), _reverseOrder(reverseOrder) { } -BitParser::~BitParser() + +BitParser::~BitParser() { } -int BitParser::parseField() +int BitParser::parseHeader() { + int pos_data = 0; int ret = 1; short length; string tmp(64, ' '); int pos, prev_pos; - /* type */ - uint8_t type; - _fd.read((char *)&type, sizeof(uint8_t)); + /* Field 1 : misc header */ + length = *(uint16_t *)&_raw_data[0]; + length = ntohs(length); + pos_data += length + 2; - if (type != 'e') { - _fd.read((char*)&length, sizeof(uint16_t)); - length = ntohs(length); - } else { - length = 4; + length = *(uint16_t *)&_raw_data[pos_data]; + length = ntohs(length); + pos_data += 2; + + while (1) { + /* type */ + uint8_t type; + type = (uint8_t)_raw_data[pos_data++]; + + if (type != 'e') { + length = *(uint16_t *)&_raw_data[pos_data]; + length = ntohs(length); + pos_data += 2; + } else { + length = 4; + } + tmp = _raw_data.substr(pos_data, length); + pos_data += length; + + switch (type) { + case 'a': /* design name:userid:synthesize tool version */ + prev_pos = 0; + pos = tmp.find(";"); + _hdr["design_name"] = tmp.substr(prev_pos, pos); + prev_pos = pos+1; + + pos = tmp.find(";", prev_pos); + prev_pos = tmp.find("=", prev_pos) + 1; + _hdr["userID"] = tmp.substr(prev_pos, pos-prev_pos); + prev_pos = pos+1; + + prev_pos = tmp.find("=", prev_pos) + 1; + _hdr["toolVersion"] = tmp.substr(prev_pos, length-prev_pos); + break; + case 'b': /* FPGA model */ + _hdr["part_name"] = tmp.substr(0, length); + break; + case 'c': /* buildDate */ + _hdr["date"] = tmp.substr(0, length); + break; + case 'd': /* buildHour */ + _hdr["hour"] = tmp.substr(0, length); + break; + case 'e': /* file size */ + _bit_length = 0; + for (int i = 0; i < 4; i++) { + _bit_length <<= 8; + _bit_length |= 0xff & tmp[i]; + } + return pos_data; + + break; + } } - _fd.read(&tmp[0], sizeof(uint8_t)*length); - switch (type) { - case 'a': /* design name:userid:synthesize tool version */ - prev_pos = 0; - pos = tmp.find(";"); - _hdr["design_name"] = tmp.substr(prev_pos, pos); - prev_pos = pos+1; - - pos = tmp.find(";", prev_pos); - prev_pos = tmp.find("=", prev_pos) + 1; - _hdr["userID"] = tmp.substr(prev_pos, pos-prev_pos); - prev_pos = pos+1; - - prev_pos = tmp.find("=", prev_pos) + 1; - _hdr["toolVersion"] = tmp.substr(prev_pos); - break; - case 'b': /* FPGA model */ - _hdr["part_name"] = tmp; - break; - case 'c': /* buildDate */ - _hdr["date"] = tmp; - break; - case 'd': /* buildHour */ - _hdr["hour"] = tmp; - break; - case 'e': /* file size */ - _bit_length = 0; - for (int i = 0; i < 4; i++) { - _bit_length <<= 8; - _bit_length |= 0xff & tmp[i]; - } - ret = 0; - - break; - } return ret; - } + int BitParser::parse() { - uint16_t length; - display("parser\n\n"); - - /* Field 1 : misc header */ - _fd.read((char*)&length, sizeof(uint16_t)); - length = ntohs(length); - _fd.seekg(length, _fd.cur); - - _fd.read((char*)&length, sizeof(uint16_t)); - length = ntohs(length); - /* process all field */ - do {} while (parseField()); - - if (_verbose) { - cout << "bitstream header infos" << endl; - for (auto it = _hdr.begin(); it != _hdr.end(); it++) { - printInfo((*it).first + ": ", false); - printSuccess((*it).second); - } - cout << endl; - } + int pos = parseHeader(); /* rest of the file is data to send */ - _fd.read((char *)&_bit_data[0], sizeof(uint8_t) * _bit_length); - if (_fd.gcount() != _bit_length) { - printError("Error: data read different to asked length ", false); - printError(to_string(_fd.gcount()) + " " + to_string(_bit_length)); - return -1; - } + _bit_data.resize(_raw_data.size() - pos); + std::move(_raw_data.begin() + pos, _raw_data.end(), _bit_data.begin()); + _bit_length = _bit_data.size(); if (_reverseOrder) { for (int i = 0; i < _bit_length; i++) { diff --git a/src/bitparser.hpp b/src/bitparser.hpp index 5fd85de..120ce3c 100644 --- a/src/bitparser.hpp +++ b/src/bitparser.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "configBitstreamParser.hpp" @@ -13,14 +14,7 @@ class BitParser: public ConfigBitstreamParser { int parse() override; private: - int parseField(); - //std::string fieldA; - //std::string part_name; - //std::string date; - //std::string hour; - //std::string design_name; - //std::string userID; - //std::string toolVersion; + int parseHeader(); bool _reverseOrder; }; diff --git a/src/configBitstreamParser.cpp b/src/configBitstreamParser.cpp index 4dac078..abecba2 100644 --- a/src/configBitstreamParser.cpp +++ b/src/configBitstreamParser.cpp @@ -1,32 +1,56 @@ #include +#include +#include #include #include +#include + +#include "display.hpp" #include "configBitstreamParser.hpp" using namespace std; ConfigBitstreamParser::ConfigBitstreamParser(const string &filename, int mode, - bool verbose): - _filename(filename), _bit_length(0), - _file_size(0), _verbose(verbose), _fd(filename, - ifstream::in | (ios_base::openmode)mode), _bit_data(), _raw_data(), _hdr() + bool verbose): _filename(filename), _bit_length(0), + _file_size(0), _verbose(verbose), + _bit_data(), _raw_data(), _hdr() { - if (!_fd.is_open()) { - cerr << "Error: fail to open " << _filename << endl; - throw std::exception(); - } - _fd.seekg(0, _fd.end); - _file_size = _fd.tellg(); - _fd.seekg(0, _fd.beg); + if (!filename.empty()) { + ifstream _fd(filename, ifstream::in | (ios_base::openmode)mode); + if (!_fd.is_open()) + throw std::runtime_error("Error: fail to open " + _filename); - _raw_data.resize(_file_size); - _bit_data.reserve(_file_size); + _fd.seekg(0, _fd.end); + _file_size = _fd.tellg(); + _fd.seekg(0, _fd.beg); + + _raw_data.resize(_file_size); + _bit_data.reserve(_file_size); + + _fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); + if (_fd.gcount() != _file_size) + throw std::runtime_error("Error: fail to read " + _filename); + _fd.close(); + } else if (!isatty(fileno(stdin))) { + _file_size = 0; + string tmp; + tmp.resize(4096); + size_t size; + + do { + cin.read((char *)&tmp[0], 4096); + size = cin.gcount(); + _raw_data.append(tmp, 0, size); + _file_size += size; + } while (size > 0); + } else { + throw std::runtime_error("Error: fail to parse. No filename or pipe\n"); + } } ConfigBitstreamParser::~ConfigBitstreamParser() { - _fd.close(); } string ConfigBitstreamParser::getHeaderVal(string key) @@ -37,6 +61,17 @@ string ConfigBitstreamParser::getHeaderVal(string key) return val->second; } +void ConfigBitstreamParser::displayHeader() +{ + if (_hdr.empty()) + return; + cout << "bitstream header infos" << endl; + for (auto it = _hdr.begin(); it != _hdr.end(); it++) { + printInfo((*it).first + ": ", false); + printSuccess((*it).second); + } +} + uint8_t ConfigBitstreamParser::reverseByte(uint8_t src) { uint8_t dst = 0; diff --git a/src/configBitstreamParser.hpp b/src/configBitstreamParser.hpp index 0552a4f..8bb8667 100644 --- a/src/configBitstreamParser.hpp +++ b/src/configBitstreamParser.hpp @@ -1,9 +1,11 @@ #ifndef CONFIGBITSTREAMPARSER_H #define CONFIGBITSTREAMPARSER_H +#include + #include #include -#include +#include #include class ConfigBitstreamParser { @@ -15,6 +17,11 @@ class ConfigBitstreamParser { uint8_t *getData() {return (uint8_t*)_bit_data.c_str();} int getLength() {return _bit_length;} + /** + * \brief display header informations + */ + virtual void displayHeader(); + /** * \brief get header list of keys/values * \return list of couple keys/values @@ -27,7 +34,7 @@ class ConfigBitstreamParser { * \return associated value for the key */ std::string getHeaderVal(std::string key); - + enum { ASCII_MODE = 0, BIN_MODE = std::ifstream::binary @@ -40,7 +47,6 @@ class ConfigBitstreamParser { int _bit_length; int _file_size; bool _verbose; - std::ifstream _fd; std::string _bit_data; std::string _raw_data; /**< unprocessed file content */ std::map _hdr; diff --git a/src/dfuFileParser.cpp b/src/dfuFileParser.cpp index fae25c5..2feecdb 100644 --- a/src/dfuFileParser.cpp +++ b/src/dfuFileParser.cpp @@ -77,14 +77,6 @@ DFUFileParser::DFUFileParser(const string &filename, bool verbose): _dwCRC(0), _bLength(0) {} -void DFUFileParser::displayHeader() -{ - cout << "bitstream header infos" << endl; - for (auto it = _hdr.begin(); it != _hdr.end(); it++) { - cout << (*it).first << ": " << (*it).second << endl; - } -} - /* USB Device firmware Upgrade Specification, Revision 1.1 B */ /* p.40-47 */ int DFUFileParser::parseHeader() @@ -140,18 +132,12 @@ int DFUFileParser::parseHeader() int DFUFileParser::parse() { - _fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); - if (_fd.gcount() != _file_size) { - printError("Error: fail to read " + _filename); - return EXIT_FAILURE; - } - int ret = parseHeader(); if (ret < 0) return EXIT_FAILURE; _bit_data.resize(_file_size - _bLength); - copy(_raw_data.begin(), _raw_data.end() - _bLength, _bit_data.begin()); + std::move(_raw_data.begin(), _raw_data.end(), _bit_data.begin()); /* If file contains suffix check CRC */ if (ret != 0) { diff --git a/src/dfuFileParser.hpp b/src/dfuFileParser.hpp index 1d2fbb1..ab6cb58 100644 --- a/src/dfuFileParser.hpp +++ b/src/dfuFileParser.hpp @@ -23,10 +23,6 @@ class DFUFileParser: public ConfigBitstreamParser { * \param[in] filename: raw file to read */ DFUFileParser(const std::string &filename, bool verbose); - /*! - * \brief display suffix infos - */ - void displayHeader(); /*! * \brief read full content of the file, fill the buffer * \return EXIT_SUCCESS is file is fully read, EXIT_FAILURE otherwhise diff --git a/src/efinix.cpp b/src/efinix.cpp index 52c99ed..9798677 100644 --- a/src/efinix.cpp +++ b/src/efinix.cpp @@ -70,23 +70,33 @@ void Efinix::program(unsigned int offset) return; ConfigBitstreamParser *bit; - if (_file_extension == "hex") { - bit = new EfinixHexParser(_filename, _verbose); - } else { - if (offset == 0) { - printError("Error: can't write raw data at the beginning of the flash"); - throw std::exception(); + try { + if (_file_extension == "hex") { + bit = new EfinixHexParser(_filename, _verbose); + } else { + if (offset == 0) { + printError("Error: can't write raw data at the beginning of the flash"); + throw std::exception(); + } + bit = new RawParser(_filename, false); } - bit = new RawParser(_filename, false); + } catch (std::exception &e) { + printError("FAIL: " + std::string(e.what())); + return; } + printInfo("Parse file ", false); if (bit->parse() == EXIT_SUCCESS) { printSuccess("DONE"); } else { printError("FAIL"); + delete bit; return; } + if (_verbose) + bit->displayHeader(); + _spi->gpio_clear(_rst_pin); SPIFlash flash(reinterpret_cast(_spi), _verbose); diff --git a/src/efinixHexParser.cpp b/src/efinixHexParser.cpp index 5d1221e..799f7c2 100644 --- a/src/efinixHexParser.cpp +++ b/src/efinixHexParser.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include "configBitstreamParser.hpp" @@ -30,16 +31,11 @@ EfinixHexParser::EfinixHexParser(const string &filename, bool reverseOrder): int EfinixHexParser::parse() { - _fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); - if (_fd.gcount() != _file_size) { - printError("Error: fails to read full file content"); - return EXIT_FAILURE; - } + string buffer; + istringstream lineStream(_raw_data); - for (int offset = 0; offset < _file_size; offset += 3) { - char val; - sscanf(&_raw_data[offset], "%hhx", &val); - _bit_data += val; + while (std::getline(lineStream, buffer, '\n')) { + _bit_data += std::stol(buffer, nullptr, 16); } _bit_length = _bit_data.size() * 8; diff --git a/src/fsparser.cpp b/src/fsparser.cpp index cdce09c..c5fd0e7 100644 --- a/src/fsparser.cpp +++ b/src/fsparser.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -46,12 +47,14 @@ uint64_t FsParser::bitToVal(const char *bits, int len) int FsParser::parseHeader() { - int ret = 1; + int ret = 0; string buffer; int line_index = 0; - while (1){ - std::getline(_fd, buffer, '\n'); + istringstream lineStream(_raw_data); + + while (std::getline(lineStream, buffer, '\n')) { + ret += buffer.size() + 1; if (buffer.empty()) break; /* drop all comment, base analyze on header */ @@ -67,7 +70,7 @@ int FsParser::parseHeader() uint64_t val = bitToVal(buffer.c_str(), buffer.size()); switch (key) { - case 0x06: + case 0x06: /* idCode */ _idcode = (0xffffffff & val); _hdr["idcode"] = string(8, ' '); snprintf(&_hdr["idcode"][0], 9, "%08x", _idcode); @@ -239,10 +242,3 @@ int FsParser::parse() return 0; } - -void FsParser::displayHeader() -{ - cout << "bitstream header infos" << endl; - for (auto it = _hdr.begin(); it != _hdr.end(); it++) - cout << (*it).first << ": " << (*it).second << endl; -} diff --git a/src/fsparser.hpp b/src/fsparser.hpp index ecade99..2e66cc5 100644 --- a/src/fsparser.hpp +++ b/src/fsparser.hpp @@ -33,8 +33,6 @@ class FsParser: public ConfigBitstreamParser { uint16_t checksum() {return _checksum;} - void displayHeader(); - private: int parseHeader(); /** diff --git a/src/gowin.cpp b/src/gowin.cpp index cfb00a4..42b2635 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -81,8 +81,21 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, _mode = Device::FLASH_MODE; else _mode = Device::MEM_MODE; - _fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose); - _fs->parse(); + try { + _fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose); + } catch (std::exception &e) { + throw std::runtime_error(e.what()); + } + + printInfo("Parse file ", false); + if (_fs->parse() == EXIT_FAILURE) { + printError("FAIL"); + delete _fs; + throw std::runtime_error("can't parse file"); + } else { + printSuccess("DONE"); + } + if (_verbose) _fs->displayHeader(); } else { diff --git a/src/jedParser.cpp b/src/jedParser.cpp index d1eb43f..706fd6a 100644 --- a/src/jedParser.cpp +++ b/src/jedParser.cpp @@ -32,6 +32,7 @@ #include #include +#include "display.hpp" #include "jedParser.hpp" /* GGM: TODO @@ -56,10 +57,10 @@ JedParser::JedParser(string filename, bool verbose): string JedParser::readline() { string buffer; - std::getline(_fd, buffer, '\n'); - if (buffer.size() != 0) { + std::getline(_ss, buffer, '\n'); + if (!buffer.empty()) { /* if '\r' is present -> drop */ - if (buffer[buffer.size() -1] == '\r') + if (buffer.back() == '\r') buffer.pop_back(); } return buffer; @@ -75,10 +76,10 @@ vector JedParser::readJEDLine() do { buffer = readline(); - if (buffer.size() == 0) + if (buffer.empty()) break; - if (buffer[buffer.size()-1] == '*') { + if (buffer.back() == '*') { inLine = false; buffer.pop_back(); } @@ -107,7 +108,7 @@ void JedParser::buildDataArray(const string &content, struct jed_data &jed) jed.len += data_len; } -void JedParser::display() +void JedParser::displayHeader() { printf("feabits :\n"); printf("%04x <-> %d\n", _feabits, _feabits); @@ -147,13 +148,18 @@ void JedParser::display() printf("Pin Count : %d\n", _pin_count); printf("Fuse Count : %d\n", _fuse_count); + + for (size_t i = 0; i < _data_list.size(); i++) { + printf("area[%zd] %d %d ", i, _data_list[i].offset, _data_list[i].len); + printf("%s\n", _data_list[i].associatedPrevNote.c_str()); + } } /* E field, for latice contains two sub-field * 1: Exxxx\n : feature Row * 2: yyyy*\n : feabits */ -void JedParser::parseEField(vector content) +void JedParser::parseEField(const vector &content) { _featuresRow = 0; string featuresRow = content[0].substr(1); @@ -166,7 +172,7 @@ void JedParser::parseEField(vector content) } } -void JedParser::parseLField(vector content) +void JedParser::parseLField(const vector &content) { int start_offset; sscanf(content[0].substr(1).c_str(), "%d", &start_offset); @@ -176,7 +182,6 @@ void JedParser::parseLField(vector content) * Lxxxx */ struct jed_data d; - string buffer; d.offset = start_offset; d.len = 0; if (content.size() > 1) { @@ -199,39 +204,31 @@ int JedParser::parse() { string previousNote; - if (!_fd.is_open()) { - _fd.open(_filename); - if (!_fd.is_open()) { - cerr << "error to opening jed file " << _filename << endl; - return EXIT_FAILURE; - } - } + _ss.str(_raw_data); string content; - _fd.seekg(0, _fd.beg); - /* JED file may have some ASCII line before STX (0x02) * read until STX or EOF */ char c; do { - _fd.read(&c, 1); - } while (_fd && c != 0x02); + _ss.read(&c, 1); + } while (_ss && c != 0x02); /* if file descriptor == EOF * return an ERROR */ - if (!_fd) { - cerr << "Error: STX not found: wrong file" << endl; + if (!_ss) { + printError("Error: STX not found: wrong file"); return EXIT_FAILURE; } /* the line starting with STX may contains * others informations */ - _fd.read(&c, 1); + _ss.read(&c, 1); if (c != '*') // something to process - _fd.seekg(-1, _fd.cur); + _ss.seekg(-1, _ss.cur); else // STX in a dedicated line content = readline(); @@ -307,16 +304,9 @@ int JedParser::parse() } while (lines[0][0] != 0x03); int size = 0; - for (size_t i = 0; i < _data_list.size(); i++) { - if (_verbose) { - printf("area[%zd] %d %d ", i, _data_list[i].offset, _data_list[i].len); - printf("%s\n", _data_list[i].associatedPrevNote.c_str()); - } - size += _data_list[i].len; - } - uint16_t checksum = 0; for (size_t area = 0; area < _data_list.size(); area++) { + size += _data_list[area].len; for (size_t line = 0; line < _data_list[area].data.size(); line++) { for (size_t col = 0; col < _data_list[area].data[line].size(); col++) checksum += (uint8_t)_data_list[area].data[line][col]; @@ -326,7 +316,7 @@ int JedParser::parse() if (_verbose) printf("theorical checksum %x -> %x\n", _checksum, checksum); if (_checksum != checksum) { - cerr << "Error: wrong checksum" << endl; + printError("Error: wrong checksum"); return EXIT_FAILURE; } @@ -334,7 +324,7 @@ int JedParser::parse() printf("array size %zd\n", _data_list[0].data.size()); if (_fuse_count != size) { - cerr << "Not all fuses are programmed" << endl; + printError("Not all fuses are programmed"); return EXIT_FAILURE; } diff --git a/src/jedParser.hpp b/src/jedParser.hpp index 422742b..705aec0 100644 --- a/src/jedParser.hpp +++ b/src/jedParser.hpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -38,7 +39,7 @@ class JedParser: public ConfigBitstreamParser { public: JedParser(std::string filename, bool verbose = false); int parse() override; - void display(); + void displayHeader() override; size_t nb_section() { return _data_list.size();} size_t offset_for_section(int id) {return _data_list[id].offset;} @@ -53,8 +54,8 @@ class JedParser: public ConfigBitstreamParser { std::string readline(); std::vectorreadJEDLine(); void buildDataArray(const std::string &content, struct jed_data &jed); - void parseEField(const std::vector content); - void parseLField(const std::vector content); + void parseEField(const std::vector &content); + void parseLField(const std::vector &content); std::vector _data_list; int _fuse_count; @@ -65,6 +66,7 @@ class JedParser: public ConfigBitstreamParser { uint32_t _userCode; uint8_t _security_settings; uint8_t _default_fuse_state; + std::istringstream _ss; }; #endif // JEDPARSER_HPP_ diff --git a/src/lattice.cpp b/src/lattice.cpp index c3738df..f23ad7c 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -299,6 +299,9 @@ bool Lattice::program_intFlash() printSuccess("DONE"); } + if (_verbose) + _jed.displayHeader(); + /* bypass */ wr_rd(0xff, NULL, 0, NULL, 0); /* ISC Enable 0xC6 followed by @@ -437,6 +440,9 @@ bool Lattice::program_extFlash(unsigned int offset) printSuccess("DONE"); } + if (_verbose) + _bit->displayHeader(); + /*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE. * thank @GregDavill * https://twitter.com/GregDavill/status/1251786406441086977 diff --git a/src/latticeBitParser.cpp b/src/latticeBitParser.cpp index e2da220..1cc0466 100644 --- a/src/latticeBitParser.cpp +++ b/src/latticeBitParser.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include + +#include "display.hpp" #include "latticeBitParser.hpp" @@ -30,96 +34,75 @@ using namespace std; LatticeBitParser::LatticeBitParser(const string &filename, bool verbose): ConfigBitstreamParser(filename, ConfigBitstreamParser::BIN_MODE, verbose), - _attribs(), _endHeader(0) + _endHeader(0) {} LatticeBitParser::~LatticeBitParser() { } -void LatticeBitParser::displayHeader() -{ - cout << "Lattice bitstream header infos" << endl; - for (auto it = _attribs.begin(); it != _attribs.end(); it++) { - cout << (*it).first << ": " << (*it).second << endl; - } -} - int LatticeBitParser::parseHeader() { - int currPos = _fd.tellg(); - char tmp[_file_size-currPos]; - char field[256]; - bool foundEndHeader = false; - uint32_t *d; + int currPos = 0; - _fd.read(tmp, (_file_size-currPos)*sizeof(char)); + /* check header signature */ - for (int i = 0; i < _file_size-currPos;) { - if ((unsigned char)tmp[i] == 0xff) { - d = (uint32_t*)(tmp+i); - if (d[0] != 0xBDffffff && (0xffffff00 & d[1]) != 0x3BFFFF00){ - foundEndHeader = true; - _endHeader = i + currPos -1; - break; - } - i++; - } else { - strcpy(field, tmp+i); - string buff(field); - int pos = buff.find_first_of(':', 0); - if (pos != -1) { - string key(buff.substr(0, pos)); - string val(buff.substr(pos+1, buff.size())); - int startPos = val.find_first_not_of(" "); - int endPos = val.find_last_not_of(" ")+1; - _attribs[key] = val.substr(startPos, endPos).c_str(); - } - i+=strlen(field)+1; + /* radiant .bit start with LSCC */ + if (_raw_data[0] == 'L') { + if (_raw_data.substr(0, 4) != "LSCC") { + printf("Wrong File %s\n", _raw_data.substr(0, 4).c_str()); + return EXIT_FAILURE; } + currPos += 4; } - return (foundEndHeader) ? EXIT_SUCCESS : EXIT_FAILURE; + /* bit file comment area start with 0xff00 */ + if ((uint8_t)_raw_data[currPos] != 0xff || (uint8_t)_raw_data[currPos + 1] != 0x00) { + printf("Wrong File %02x%02x\n", (uint8_t) _raw_data[currPos], + (uint8_t)_raw_data[currPos]); + return EXIT_FAILURE; + } + currPos+=2; + + + _endHeader = _raw_data.find(0xff, currPos); + if (_endHeader == string::npos) { + printError("Error: preamble not found\n"); + return EXIT_FAILURE; + } + + /* parse header */ + istringstream lineStream(_raw_data.substr(currPos, _endHeader-currPos)); + string buff; + while (std::getline(lineStream, buff, '\0')) { + size_t pos = buff.find_first_of(':', 0); + if (pos != string::npos) { + string key(buff.substr(0, pos)); + string val(buff.substr(pos+1, buff.size())); + int startPos = val.find_first_not_of(" "); + int endPos = val.find_last_not_of(" ")+1; + _hdr[key] = val.substr(startPos, endPos).c_str(); + } + } + return EXIT_SUCCESS; } int LatticeBitParser::parse() { - uint8_t dummy[2]; - - _fd.read(reinterpret_cast(&dummy), 2*sizeof(uint8_t)); - - /* radiant .bit start with LSCC */ - if (dummy[0] == 'L') { - uint8_t dummy2[2]; - _fd.read(reinterpret_cast(&dummy2), 2*sizeof(uint8_t)); - if (!(dummy[1] == 'S' && dummy2[0] == 'C' && dummy2[1] == 'C')) { - printf("Wrong File %c%c%c%c\n", - dummy[0], dummy[1], - dummy2[0], dummy2[1]); - return EXIT_FAILURE; - } - _fd.read(reinterpret_cast(&dummy), 2*sizeof(uint8_t)); - } - - /* bit file comment area start with 0xff00 */ - if (dummy[0] != 0xff || dummy[1] != 0x00) { - printf("Wrong File %02x%02x\n", dummy[0], dummy[1]); - return EXIT_FAILURE; - } - /* until 0xFFFFBDB3 0xFFFF */ - if (parseHeader() == EXIT_FAILURE) + if (parseHeader() < 0) return EXIT_FAILURE; + /* check preamble */ + if ((*(uint32_t *)&_raw_data[_endHeader+1]) != 0xb3bdffff) { + printError("Error: missing preamble\n"); + return EXIT_FAILURE; + } + /* read All data */ - _fd.seekg(_endHeader, _fd.beg); - char buffer[_file_size]; - int end = _file_size-_endHeader; - _fd.read(buffer, end); - - for (int i = 0; i < end; i++) - _bit_data+=(buffer[i]); - + _bit_data.resize(_raw_data.size() - _endHeader); + std::move(_raw_data.begin()+_endHeader, _raw_data.end(), _bit_data.begin()); _bit_length = _bit_data.size() * 8; + return 0; } diff --git a/src/latticeBitParser.hpp b/src/latticeBitParser.hpp index 19868f4..e836daa 100644 --- a/src/latticeBitParser.hpp +++ b/src/latticeBitParser.hpp @@ -29,12 +29,10 @@ class LatticeBitParser: public ConfigBitstreamParser { LatticeBitParser(const std::string &filename, bool verbose = false); ~LatticeBitParser(); int parse() override; - void displayHeader(); private: int parseHeader(); - std::map _attribs; - int _endHeader; + size_t _endHeader; }; #endif // LATTICEBITPARSER_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 31588e2..4192704 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -293,7 +293,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if (!args.bit_file.empty()) { + if (!args.bit_file.empty() || !args.file_type.empty()) { try { fpga->program(args.offset); } catch (std::exception &e) { diff --git a/src/mcsParser.cpp b/src/mcsParser.cpp index e913494..262ada4 100644 --- a/src/mcsParser.cpp +++ b/src/mcsParser.cpp @@ -15,7 +15,11 @@ * along with this program. If not, see . */ +#include +#include + #include "configBitstreamParser.hpp" +#include "display.hpp" #include "mcsParser.hpp" using namespace std; @@ -50,61 +54,62 @@ McsParser::McsParser(const string &filename, bool reverseOrder, bool verbose): int McsParser::parse() { string str; - int ret; + istringstream lineStream(_raw_data); - do { - getline(_fd, str); - ret = parseLine(str); - } while (ret == 0); - return (ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS; -} + while (std::getline(lineStream, str, '\n')) { + char *ptr; + uint8_t sum = 0; + uint16_t tmp, byteLen, type, checksum; + uint32_t addr, loc_addr; -int McsParser::parseLine(string buffer) -{ - const char *buff = buffer.c_str(); - uint16_t tmp, byteLen, type, checksum; - uint32_t addr, loc_addr; - uint8_t sum = 0; + /* if '\r' is present -> drop */ + if (str.back() == '\r') + str.pop_back(); - if (buff[0] != ':') { - cout << "Error: a line must start with ':'" << endl; - return -1; - } - /* len */ - sscanf(buff + LEN_BASE, "%2hx", &byteLen); - /* address */ - sscanf(buff + ADDR_BASE, "%4x", &addr); - /* type */ - sscanf(buff + TYPE_BASE, "%2hx", &type); - /* checksum */ - sscanf(buff + DATA_BASE + byteLen * 2, "%2hx", &checksum); - - sum = byteLen + type + (addr & 0xff) + ((addr >> 8) & 0xff); - - if (type == 0) { - loc_addr = _base_addr + addr; - char *ptr = (char *)(buff + DATA_BASE); - for (int i = 0; i < byteLen; i++, ptr += 2) { - sscanf(ptr, "%2hx", &tmp); - _bit_data[loc_addr + i] = (_reverseOrder)? reverseByte(tmp):tmp; - sum += tmp; + if (str[0] != ':') { + printError("Error: a line must start with ':'"); + return EXIT_FAILURE; + } + /* len */ + sscanf((char *)&str[LEN_BASE], "%2hx", &byteLen); + /* address */ + sscanf((char *)&str[ADDR_BASE], "%4x", &addr); + /* type */ + sscanf((char *)&str[TYPE_BASE], "%2hx", &type); + /* checksum */ + sscanf((char *)&str[DATA_BASE + byteLen * 2], "%2hx", &checksum); + + sum = byteLen + type + (addr & 0xff) + ((addr >> 8) & 0xff); + + switch (type) { + case 0: + loc_addr = _base_addr + addr; + ptr = (char *)&str[DATA_BASE]; + for (int i = 0; i < byteLen; i++, ptr += 2) { + sscanf(ptr, "%2hx", &tmp); + _bit_data[loc_addr + i] = (_reverseOrder)? reverseByte(tmp):tmp; + sum += tmp; + } + _bit_length += (byteLen * 8); + break; + case 1: + return EXIT_SUCCESS; + break; + case 4: + sscanf((char*)&str[DATA_BASE], "%4x", &loc_addr); + _base_addr = (loc_addr << 16); + sum += (loc_addr & 0xff) + ((loc_addr >> 8) & 0xff); + break; + default: + printError("Error: unknown type"); + return EXIT_FAILURE; + } + + if (checksum != (0xff&((~sum)+1))) { + printError("Error: wrong checksum"); + return EXIT_FAILURE; } - _bit_length += (byteLen * 8); - } else if (type == 1) { - return 1; - } else if (type == 4) { - sscanf(buff + DATA_BASE, "%4x", &loc_addr); - _base_addr = (loc_addr << 16); - sum += (loc_addr & 0xff) + ((loc_addr >> 8) & 0xff); - } else { - cerr << "Error: unknown type" << endl; - return -1; } - if (checksum != (0xff&((~sum)+1))) { - cerr << "Error: wrong checksum" << endl; - return -1; - } - - return 0; + return EXIT_SUCCESS; } diff --git a/src/mcsParser.hpp b/src/mcsParser.hpp index 5998cf3..3071bda 100644 --- a/src/mcsParser.hpp +++ b/src/mcsParser.hpp @@ -18,6 +18,8 @@ #ifndef MCSPARSER_HPP #define MCSPARSER_HPP +#include + #include "configBitstreamParser.hpp" class McsParser: public ConfigBitstreamParser { @@ -26,8 +28,6 @@ class McsParser: public ConfigBitstreamParser { int parse() override; private: - int parseLine(std::string buffer); - int _base_addr; bool _reverseOrder; }; diff --git a/src/rawParser.cpp b/src/rawParser.cpp index 1a4c239..4097192 100644 --- a/src/rawParser.cpp +++ b/src/rawParser.cpp @@ -16,6 +16,7 @@ */ #include +#include #include "configBitstreamParser.hpp" #include "display.hpp" @@ -30,16 +31,18 @@ RawParser::RawParser(const string &filename, bool reverseOrder): int RawParser::parse() { - _fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); - if (_fd.gcount() != _file_size) { - printError("Error: fail to read " + _filename); - return EXIT_FAILURE; - } - //cout << _bit_data << endl; _bit_data.resize(_file_size); - for (int i = 0; i < _file_size; i++) - _bit_data[i] = (_reverseOrder) ? reverseByte(_raw_data[i]): _raw_data[i]; - _bit_length = _bit_data.size() * 8; - //cout << "file length " << _bit_length << endl; + std::move(_raw_data.begin(), _raw_data.end(), _bit_data.begin()); + _bit_length = _bit_data.size(); + + if (_reverseOrder) { + for (int i = 0; i < _bit_length; i++) { + _bit_data[i] = reverseByte(_bit_data[i]); + } + } + + /* convert size to bit */ + _bit_length *= 8; + return EXIT_SUCCESS; } diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 1a70916..92cce5c 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -99,9 +99,8 @@ void Xilinx::program(unsigned int offset) printSuccess("DONE"); - int err = bit->parse(); printInfo("Parse file ", false); - if (err == EXIT_FAILURE) { + if (bit->parse() == EXIT_FAILURE) { printError("FAIL"); delete bit; return; @@ -109,6 +108,9 @@ void Xilinx::program(unsigned int offset) printSuccess("DONE"); } + if (_verbose) + bit->displayHeader(); + if (_mode == Device::SPI_MODE) { program_spi(bit, offset); reset();