all parser:

- _raw_data is now filled in configBitstreamParser
- source may be a file or a pipe
- displayHeader become a common method (configBitstreamParser)
- improve/rewrite some parser (efinixHexparser 1s -> 11ms)
This commit is contained in:
Gwenhael Goavec-Merou 2021-02-24 06:36:48 +01:00
parent efbe68c431
commit 16932786db
25 changed files with 370 additions and 341 deletions

View File

@ -205,10 +205,28 @@ openFPGALoader [options] -r
``` ```
#### load bitstream device (memory or flash) #### load bitstream device (memory or flash)
```bash ```bash
openFPGALoader [options] /path/to/bitstream.ext 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 #### Automatic file type detection bypass
Default behavior is to use file extension to determine file parser. To avoid Default behavior is to use file extension to determine file parser. To avoid

View File

@ -23,6 +23,7 @@
#include "anlogicBitParser.hpp" #include "anlogicBitParser.hpp"
#include "jtag.hpp" #include "jtag.hpp"
#include "device.hpp" #include "device.hpp"
#include "display.hpp"
#include "progressBar.hpp" #include "progressBar.hpp"
#include "spiFlash.hpp" #include "spiFlash.hpp"
@ -76,7 +77,18 @@ void Anlogic::program(unsigned int offset)
} }
AnlogicBitParser bit(_filename, (_mode == Device::MEM_MODE), _verbose); 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(); uint8_t *data = bit.getData();
int len = bit.getLength() / 8; int len = bit.getLength() / 8;

View File

@ -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 '#' /* read all ascii lines starting with '#'
* stop when an empty line is found * stop when an empty line is found
*/ */
int AnlogicBitParser::parseHeader() int AnlogicBitParser::parseHeader()
{ {
int ret = 0; int ret = 0;
printInfo("parseHeader");
string buffer; string buffer;
istringstream lineStream(_raw_data); istringstream lineStream(_raw_data);
@ -71,7 +62,7 @@ int AnlogicBitParser::parseHeader()
if (buffer[0] != '#') { if (buffer[0] != '#') {
printError("header must start with #\n"); printError("header must start with #\n");
return EXIT_FAILURE; return -1;
} }
string content = buffer.substr(2); // drop '# ' string content = buffer.substr(2); // drop '# '
@ -96,12 +87,6 @@ int AnlogicBitParser::parseHeader()
int AnlogicBitParser::parse() int AnlogicBitParser::parse()
{ {
int end_header = 0; 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 */ /* parse header */
if ((end_header = parseHeader()) == -1) if ((end_header = parseHeader()) == -1)

View File

@ -34,7 +34,6 @@ class AnlogicBitParser: public ConfigBitstreamParser {
bool verbose = false); bool verbose = false);
~AnlogicBitParser(); ~AnlogicBitParser();
int parse() override; int parse() override;
void displayHeader();
private: private:
int parseHeader(); int parseHeader();

View File

@ -3,6 +3,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <iostream> #include <iostream>
#include <sstream>
#include <string>
#include <utility>
#ifndef _WIN32 #ifndef _WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#else #else
@ -20,28 +23,42 @@ BitParser::BitParser(const string &filename, bool reverseOrder, bool verbose):
verbose), _reverseOrder(reverseOrder) verbose), _reverseOrder(reverseOrder)
{ {
} }
BitParser::~BitParser() BitParser::~BitParser()
{ {
} }
int BitParser::parseField() int BitParser::parseHeader()
{ {
int pos_data = 0;
int ret = 1; int ret = 1;
short length; short length;
string tmp(64, ' '); string tmp(64, ' ');
int pos, prev_pos; int pos, prev_pos;
/* Field 1 : misc header */
length = *(uint16_t *)&_raw_data[0];
length = ntohs(length);
pos_data += length + 2;
length = *(uint16_t *)&_raw_data[pos_data];
length = ntohs(length);
pos_data += 2;
while (1) {
/* type */ /* type */
uint8_t type; uint8_t type;
_fd.read((char *)&type, sizeof(uint8_t)); type = (uint8_t)_raw_data[pos_data++];
if (type != 'e') { if (type != 'e') {
_fd.read((char*)&length, sizeof(uint16_t)); length = *(uint16_t *)&_raw_data[pos_data];
length = ntohs(length); length = ntohs(length);
pos_data += 2;
} else { } else {
length = 4; length = 4;
} }
_fd.read(&tmp[0], sizeof(uint8_t)*length); tmp = _raw_data.substr(pos_data, length);
pos_data += length;
switch (type) { switch (type) {
case 'a': /* design name:userid:synthesize tool version */ case 'a': /* design name:userid:synthesize tool version */
@ -56,16 +73,16 @@ int BitParser::parseField()
prev_pos = pos+1; prev_pos = pos+1;
prev_pos = tmp.find("=", prev_pos) + 1; prev_pos = tmp.find("=", prev_pos) + 1;
_hdr["toolVersion"] = tmp.substr(prev_pos); _hdr["toolVersion"] = tmp.substr(prev_pos, length-prev_pos);
break; break;
case 'b': /* FPGA model */ case 'b': /* FPGA model */
_hdr["part_name"] = tmp; _hdr["part_name"] = tmp.substr(0, length);
break; break;
case 'c': /* buildDate */ case 'c': /* buildDate */
_hdr["date"] = tmp; _hdr["date"] = tmp.substr(0, length);
break; break;
case 'd': /* buildHour */ case 'd': /* buildHour */
_hdr["hour"] = tmp; _hdr["hour"] = tmp.substr(0, length);
break; break;
case 'e': /* file size */ case 'e': /* file size */
_bit_length = 0; _bit_length = 0;
@ -73,45 +90,24 @@ int BitParser::parseField()
_bit_length <<= 8; _bit_length <<= 8;
_bit_length |= 0xff & tmp[i]; _bit_length |= 0xff & tmp[i];
} }
ret = 0; return pos_data;
break; break;
} }
return ret;
} }
return ret;
}
int BitParser::parse() 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 */ /* process all field */
do {} while (parseField()); int pos = parseHeader();
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;
}
/* rest of the file is data to send */ /* rest of the file is data to send */
_fd.read((char *)&_bit_data[0], sizeof(uint8_t) * _bit_length); _bit_data.resize(_raw_data.size() - pos);
if (_fd.gcount() != _bit_length) { std::move(_raw_data.begin() + pos, _raw_data.end(), _bit_data.begin());
printError("Error: data read different to asked length ", false); _bit_length = _bit_data.size();
printError(to_string(_fd.gcount()) + " " + to_string(_bit_length));
return -1;
}
if (_reverseOrder) { if (_reverseOrder) {
for (int i = 0; i < _bit_length; i++) { for (int i = 0; i < _bit_length; i++) {

View File

@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <string>
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
@ -13,14 +14,7 @@ class BitParser: public ConfigBitstreamParser {
int parse() override; int parse() override;
private: private:
int parseField(); int parseHeader();
//std::string fieldA;
//std::string part_name;
//std::string date;
//std::string hour;
//std::string design_name;
//std::string userID;
//std::string toolVersion;
bool _reverseOrder; bool _reverseOrder;
}; };

View File

@ -1,32 +1,56 @@
#include <iostream> #include <iostream>
#include <stdexcept>
#include <string>
#include <stdint.h> #include <stdint.h>
#include <strings.h> #include <strings.h>
#include <unistd.h>
#include "display.hpp"
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
using namespace std; using namespace std;
ConfigBitstreamParser::ConfigBitstreamParser(const string &filename, int mode, ConfigBitstreamParser::ConfigBitstreamParser(const string &filename, int mode,
bool verbose): bool verbose): _filename(filename), _bit_length(0),
_filename(filename), _bit_length(0), _file_size(0), _verbose(verbose),
_file_size(0), _verbose(verbose), _fd(filename, _bit_data(), _raw_data(), _hdr()
ifstream::in | (ios_base::openmode)mode), _bit_data(), _raw_data(), _hdr()
{ {
if (!_fd.is_open()) { if (!filename.empty()) {
cerr << "Error: fail to open " << _filename << endl; ifstream _fd(filename, ifstream::in | (ios_base::openmode)mode);
throw std::exception(); if (!_fd.is_open())
} throw std::runtime_error("Error: fail to open " + _filename);
_fd.seekg(0, _fd.end); _fd.seekg(0, _fd.end);
_file_size = _fd.tellg(); _file_size = _fd.tellg();
_fd.seekg(0, _fd.beg); _fd.seekg(0, _fd.beg);
_raw_data.resize(_file_size); _raw_data.resize(_file_size);
_bit_data.reserve(_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() ConfigBitstreamParser::~ConfigBitstreamParser()
{ {
_fd.close();
} }
string ConfigBitstreamParser::getHeaderVal(string key) string ConfigBitstreamParser::getHeaderVal(string key)
@ -37,6 +61,17 @@ string ConfigBitstreamParser::getHeaderVal(string key)
return val->second; 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 ConfigBitstreamParser::reverseByte(uint8_t src)
{ {
uint8_t dst = 0; uint8_t dst = 0;

View File

@ -1,9 +1,11 @@
#ifndef CONFIGBITSTREAMPARSER_H #ifndef CONFIGBITSTREAMPARSER_H
#define CONFIGBITSTREAMPARSER_H #define CONFIGBITSTREAMPARSER_H
#include <stdint.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <stdint.h> #include <string>
#include <map> #include <map>
class ConfigBitstreamParser { class ConfigBitstreamParser {
@ -15,6 +17,11 @@ class ConfigBitstreamParser {
uint8_t *getData() {return (uint8_t*)_bit_data.c_str();} uint8_t *getData() {return (uint8_t*)_bit_data.c_str();}
int getLength() {return _bit_length;} int getLength() {return _bit_length;}
/**
* \brief display header informations
*/
virtual void displayHeader();
/** /**
* \brief get header list of keys/values * \brief get header list of keys/values
* \return list of couple keys/values * \return list of couple keys/values
@ -40,7 +47,6 @@ class ConfigBitstreamParser {
int _bit_length; int _bit_length;
int _file_size; int _file_size;
bool _verbose; bool _verbose;
std::ifstream _fd;
std::string _bit_data; std::string _bit_data;
std::string _raw_data; /**< unprocessed file content */ std::string _raw_data; /**< unprocessed file content */
std::map<std::string, std::string> _hdr; std::map<std::string, std::string> _hdr;

View File

@ -77,14 +77,6 @@ DFUFileParser::DFUFileParser(const string &filename, bool verbose):
_dwCRC(0), _bLength(0) _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 */ /* USB Device firmware Upgrade Specification, Revision 1.1 B */
/* p.40-47 */ /* p.40-47 */
int DFUFileParser::parseHeader() int DFUFileParser::parseHeader()
@ -140,18 +132,12 @@ int DFUFileParser::parseHeader()
int DFUFileParser::parse() 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(); int ret = parseHeader();
if (ret < 0) if (ret < 0)
return EXIT_FAILURE; return EXIT_FAILURE;
_bit_data.resize(_file_size - _bLength); _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 file contains suffix check CRC */
if (ret != 0) { if (ret != 0) {

View File

@ -23,10 +23,6 @@ class DFUFileParser: public ConfigBitstreamParser {
* \param[in] filename: raw file to read * \param[in] filename: raw file to read
*/ */
DFUFileParser(const std::string &filename, bool verbose); DFUFileParser(const std::string &filename, bool verbose);
/*!
* \brief display suffix infos
*/
void displayHeader();
/*! /*!
* \brief read full content of the file, fill the buffer * \brief read full content of the file, fill the buffer
* \return EXIT_SUCCESS is file is fully read, EXIT_FAILURE otherwhise * \return EXIT_SUCCESS is file is fully read, EXIT_FAILURE otherwhise

View File

@ -70,6 +70,7 @@ void Efinix::program(unsigned int offset)
return; return;
ConfigBitstreamParser *bit; ConfigBitstreamParser *bit;
try {
if (_file_extension == "hex") { if (_file_extension == "hex") {
bit = new EfinixHexParser(_filename, _verbose); bit = new EfinixHexParser(_filename, _verbose);
} else { } else {
@ -79,14 +80,23 @@ void Efinix::program(unsigned int offset)
} }
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); printInfo("Parse file ", false);
if (bit->parse() == EXIT_SUCCESS) { if (bit->parse() == EXIT_SUCCESS) {
printSuccess("DONE"); printSuccess("DONE");
} else { } else {
printError("FAIL"); printError("FAIL");
delete bit;
return; return;
} }
if (_verbose)
bit->displayHeader();
_spi->gpio_clear(_rst_pin); _spi->gpio_clear(_rst_pin);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose); SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);

View File

@ -15,6 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <sstream>
#include <stdexcept> #include <stdexcept>
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
@ -30,16 +31,11 @@ EfinixHexParser::EfinixHexParser(const string &filename, bool reverseOrder):
int EfinixHexParser::parse() int EfinixHexParser::parse()
{ {
_fd.read((char *)&_raw_data[0], sizeof(char) * _file_size); string buffer;
if (_fd.gcount() != _file_size) { istringstream lineStream(_raw_data);
printError("Error: fails to read full file content");
return EXIT_FAILURE;
}
for (int offset = 0; offset < _file_size; offset += 3) { while (std::getline(lineStream, buffer, '\n')) {
char val; _bit_data += std::stol(buffer, nullptr, 16);
sscanf(&_raw_data[offset], "%hhx", &val);
_bit_data += val;
} }
_bit_length = _bit_data.size() * 8; _bit_length = _bit_data.size() * 8;

View File

@ -16,6 +16,7 @@
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <vector> #include <vector>
#include <cstdio> #include <cstdio>
@ -46,12 +47,14 @@ uint64_t FsParser::bitToVal(const char *bits, int len)
int FsParser::parseHeader() int FsParser::parseHeader()
{ {
int ret = 1; int ret = 0;
string buffer; string buffer;
int line_index = 0; int line_index = 0;
while (1){ istringstream lineStream(_raw_data);
std::getline(_fd, buffer, '\n');
while (std::getline(lineStream, buffer, '\n')) {
ret += buffer.size() + 1;
if (buffer.empty()) if (buffer.empty())
break; break;
/* drop all comment, base analyze on header */ /* drop all comment, base analyze on header */
@ -67,7 +70,7 @@ int FsParser::parseHeader()
uint64_t val = bitToVal(buffer.c_str(), buffer.size()); uint64_t val = bitToVal(buffer.c_str(), buffer.size());
switch (key) { switch (key) {
case 0x06: case 0x06: /* idCode */
_idcode = (0xffffffff & val); _idcode = (0xffffffff & val);
_hdr["idcode"] = string(8, ' '); _hdr["idcode"] = string(8, ' ');
snprintf(&_hdr["idcode"][0], 9, "%08x", _idcode); snprintf(&_hdr["idcode"][0], 9, "%08x", _idcode);
@ -239,10 +242,3 @@ int FsParser::parse()
return 0; 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;
}

View File

@ -33,8 +33,6 @@ class FsParser: public ConfigBitstreamParser {
uint16_t checksum() {return _checksum;} uint16_t checksum() {return _checksum;}
void displayHeader();
private: private:
int parseHeader(); int parseHeader();
/** /**

View File

@ -81,8 +81,21 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type,
_mode = Device::FLASH_MODE; _mode = Device::FLASH_MODE;
else else
_mode = Device::MEM_MODE; _mode = Device::MEM_MODE;
try {
_fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose); _fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose);
_fs->parse(); } 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) if (_verbose)
_fs->displayHeader(); _fs->displayHeader();
} else { } else {

View File

@ -32,6 +32,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "display.hpp"
#include "jedParser.hpp" #include "jedParser.hpp"
/* GGM: TODO /* GGM: TODO
@ -56,10 +57,10 @@ JedParser::JedParser(string filename, bool verbose):
string JedParser::readline() string JedParser::readline()
{ {
string buffer; string buffer;
std::getline(_fd, buffer, '\n'); std::getline(_ss, buffer, '\n');
if (buffer.size() != 0) { if (!buffer.empty()) {
/* if '\r' is present -> drop */ /* if '\r' is present -> drop */
if (buffer[buffer.size() -1] == '\r') if (buffer.back() == '\r')
buffer.pop_back(); buffer.pop_back();
} }
return buffer; return buffer;
@ -75,10 +76,10 @@ vector<string> JedParser::readJEDLine()
do { do {
buffer = readline(); buffer = readline();
if (buffer.size() == 0) if (buffer.empty())
break; break;
if (buffer[buffer.size()-1] == '*') { if (buffer.back() == '*') {
inLine = false; inLine = false;
buffer.pop_back(); buffer.pop_back();
} }
@ -107,7 +108,7 @@ void JedParser::buildDataArray(const string &content, struct jed_data &jed)
jed.len += data_len; jed.len += data_len;
} }
void JedParser::display() void JedParser::displayHeader()
{ {
printf("feabits :\n"); printf("feabits :\n");
printf("%04x <-> %d\n", _feabits, _feabits); printf("%04x <-> %d\n", _feabits, _feabits);
@ -147,13 +148,18 @@ void JedParser::display()
printf("Pin Count : %d\n", _pin_count); printf("Pin Count : %d\n", _pin_count);
printf("Fuse Count : %d\n", _fuse_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 /* E field, for latice contains two sub-field
* 1: Exxxx\n : feature Row * 1: Exxxx\n : feature Row
* 2: yyyy*\n : feabits * 2: yyyy*\n : feabits
*/ */
void JedParser::parseEField(vector<string> content) void JedParser::parseEField(const vector<string> &content)
{ {
_featuresRow = 0; _featuresRow = 0;
string featuresRow = content[0].substr(1); string featuresRow = content[0].substr(1);
@ -166,7 +172,7 @@ void JedParser::parseEField(vector<string> content)
} }
} }
void JedParser::parseLField(vector<string> content) void JedParser::parseLField(const vector<string> &content)
{ {
int start_offset; int start_offset;
sscanf(content[0].substr(1).c_str(), "%d", &start_offset); sscanf(content[0].substr(1).c_str(), "%d", &start_offset);
@ -176,7 +182,6 @@ void JedParser::parseLField(vector<string> content)
* Lxxxx<EOF> * Lxxxx<EOF>
*/ */
struct jed_data d; struct jed_data d;
string buffer;
d.offset = start_offset; d.offset = start_offset;
d.len = 0; d.len = 0;
if (content.size() > 1) { if (content.size() > 1) {
@ -199,39 +204,31 @@ int JedParser::parse()
{ {
string previousNote; string previousNote;
if (!_fd.is_open()) { _ss.str(_raw_data);
_fd.open(_filename);
if (!_fd.is_open()) {
cerr << "error to opening jed file " << _filename << endl;
return EXIT_FAILURE;
}
}
string content; string content;
_fd.seekg(0, _fd.beg);
/* JED file may have some ASCII line before STX (0x02) /* JED file may have some ASCII line before STX (0x02)
* read until STX or EOF * read until STX or EOF
*/ */
char c; char c;
do { do {
_fd.read(&c, 1); _ss.read(&c, 1);
} while (_fd && c != 0x02); } while (_ss && c != 0x02);
/* if file descriptor == EOF /* if file descriptor == EOF
* return an ERROR * return an ERROR
*/ */
if (!_fd) { if (!_ss) {
cerr << "Error: STX not found: wrong file" << endl; printError("Error: STX not found: wrong file");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* the line starting with STX may contains /* the line starting with STX may contains
* others informations */ * others informations */
_fd.read(&c, 1); _ss.read(&c, 1);
if (c != '*') // something to process if (c != '*') // something to process
_fd.seekg(-1, _fd.cur); _ss.seekg(-1, _ss.cur);
else // STX in a dedicated line else // STX in a dedicated line
content = readline(); content = readline();
@ -307,16 +304,9 @@ int JedParser::parse()
} while (lines[0][0] != 0x03); } while (lines[0][0] != 0x03);
int size = 0; 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; uint16_t checksum = 0;
for (size_t area = 0; area < _data_list.size(); area++) { 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 line = 0; line < _data_list[area].data.size(); line++) {
for (size_t col = 0; col < _data_list[area].data[line].size(); col++) for (size_t col = 0; col < _data_list[area].data[line].size(); col++)
checksum += (uint8_t)_data_list[area].data[line][col]; checksum += (uint8_t)_data_list[area].data[line][col];
@ -326,7 +316,7 @@ int JedParser::parse()
if (_verbose) if (_verbose)
printf("theorical checksum %x -> %x\n", _checksum, checksum); printf("theorical checksum %x -> %x\n", _checksum, checksum);
if (_checksum != checksum) { if (_checksum != checksum) {
cerr << "Error: wrong checksum" << endl; printError("Error: wrong checksum");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -334,7 +324,7 @@ int JedParser::parse()
printf("array size %zd\n", _data_list[0].data.size()); printf("array size %zd\n", _data_list[0].data.size());
if (_fuse_count != size) { if (_fuse_count != size) {
cerr << "Not all fuses are programmed" << endl; printError("Not all fuses are programmed");
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -21,6 +21,7 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
@ -38,7 +39,7 @@ class JedParser: public ConfigBitstreamParser {
public: public:
JedParser(std::string filename, bool verbose = false); JedParser(std::string filename, bool verbose = false);
int parse() override; int parse() override;
void display(); void displayHeader() override;
size_t nb_section() { return _data_list.size();} size_t nb_section() { return _data_list.size();}
size_t offset_for_section(int id) {return _data_list[id].offset;} size_t offset_for_section(int id) {return _data_list[id].offset;}
@ -53,8 +54,8 @@ class JedParser: public ConfigBitstreamParser {
std::string readline(); std::string readline();
std::vector<std::string>readJEDLine(); std::vector<std::string>readJEDLine();
void buildDataArray(const std::string &content, struct jed_data &jed); void buildDataArray(const std::string &content, struct jed_data &jed);
void parseEField(const std::vector<std::string> content); void parseEField(const std::vector<std::string> &content);
void parseLField(const std::vector<std::string> content); void parseLField(const std::vector<std::string> &content);
std::vector<struct jed_data> _data_list; std::vector<struct jed_data> _data_list;
int _fuse_count; int _fuse_count;
@ -65,6 +66,7 @@ class JedParser: public ConfigBitstreamParser {
uint32_t _userCode; uint32_t _userCode;
uint8_t _security_settings; uint8_t _security_settings;
uint8_t _default_fuse_state; uint8_t _default_fuse_state;
std::istringstream _ss;
}; };
#endif // JEDPARSER_HPP_ #endif // JEDPARSER_HPP_

View File

@ -299,6 +299,9 @@ bool Lattice::program_intFlash()
printSuccess("DONE"); printSuccess("DONE");
} }
if (_verbose)
_jed.displayHeader();
/* bypass */ /* bypass */
wr_rd(0xff, NULL, 0, NULL, 0); wr_rd(0xff, NULL, 0, NULL, 0);
/* ISC Enable 0xC6 followed by /* ISC Enable 0xC6 followed by
@ -437,6 +440,9 @@ bool Lattice::program_extFlash(unsigned int offset)
printSuccess("DONE"); printSuccess("DONE");
} }
if (_verbose)
_bit->displayHeader();
/*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE. /*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE.
* thank @GregDavill * thank @GregDavill
* https://twitter.com/GregDavill/status/1251786406441086977 * https://twitter.com/GregDavill/status/1251786406441086977

View File

@ -23,6 +23,10 @@
#include <cctype> #include <cctype>
#include <iostream> #include <iostream>
#include <locale> #include <locale>
#include <sstream>
#include <utility>
#include "display.hpp"
#include "latticeBitParser.hpp" #include "latticeBitParser.hpp"
@ -30,96 +34,75 @@ using namespace std;
LatticeBitParser::LatticeBitParser(const string &filename, bool verbose): LatticeBitParser::LatticeBitParser(const string &filename, bool verbose):
ConfigBitstreamParser(filename, ConfigBitstreamParser::BIN_MODE, verbose), ConfigBitstreamParser(filename, ConfigBitstreamParser::BIN_MODE, verbose),
_attribs(), _endHeader(0) _endHeader(0)
{} {}
LatticeBitParser::~LatticeBitParser() 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 LatticeBitParser::parseHeader()
{ {
int currPos = _fd.tellg(); int currPos = 0;
char tmp[_file_size-currPos];
char field[256];
bool foundEndHeader = false;
uint32_t *d;
_fd.read(tmp, (_file_size-currPos)*sizeof(char)); /* check header signature */
for (int i = 0; i < _file_size-currPos;) { /* radiant .bit start with LSCC */
if ((unsigned char)tmp[i] == 0xff) { if (_raw_data[0] == 'L') {
d = (uint32_t*)(tmp+i); if (_raw_data.substr(0, 4) != "LSCC") {
if (d[0] != 0xBDffffff && (0xffffff00 & d[1]) != 0x3BFFFF00){ printf("Wrong File %s\n", _raw_data.substr(0, 4).c_str());
foundEndHeader = true; return EXIT_FAILURE;
_endHeader = i + currPos -1;
break;
} }
i++; currPos += 4;
} else { }
strcpy(field, tmp+i);
string buff(field); /* bit file comment area start with 0xff00 */
int pos = buff.find_first_of(':', 0); if ((uint8_t)_raw_data[currPos] != 0xff || (uint8_t)_raw_data[currPos + 1] != 0x00) {
if (pos != -1) { 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 key(buff.substr(0, pos));
string val(buff.substr(pos+1, buff.size())); string val(buff.substr(pos+1, buff.size()));
int startPos = val.find_first_not_of(" "); int startPos = val.find_first_not_of(" ");
int endPos = val.find_last_not_of(" ")+1; int endPos = val.find_last_not_of(" ")+1;
_attribs[key] = val.substr(startPos, endPos).c_str(); _hdr[key] = val.substr(startPos, endPos).c_str();
}
i+=strlen(field)+1;
} }
} }
return EXIT_SUCCESS;
return (foundEndHeader) ? EXIT_SUCCESS : EXIT_FAILURE;
} }
int LatticeBitParser::parse() int LatticeBitParser::parse()
{ {
uint8_t dummy[2];
_fd.read(reinterpret_cast<char*>(&dummy), 2*sizeof(uint8_t));
/* radiant .bit start with LSCC */
if (dummy[0] == 'L') {
uint8_t dummy2[2];
_fd.read(reinterpret_cast<char*>(&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<char*>(&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 */ /* until 0xFFFFBDB3 0xFFFF */
if (parseHeader() == EXIT_FAILURE) if (parseHeader() < 0)
return EXIT_FAILURE; return EXIT_FAILURE;
/* check preamble */
if ((*(uint32_t *)&_raw_data[_endHeader+1]) != 0xb3bdffff) {
printError("Error: missing preamble\n");
return EXIT_FAILURE;
}
/* read All data */ /* read All data */
_fd.seekg(_endHeader, _fd.beg); _bit_data.resize(_raw_data.size() - _endHeader);
char buffer[_file_size]; std::move(_raw_data.begin()+_endHeader, _raw_data.end(), _bit_data.begin());
int end = _file_size-_endHeader;
_fd.read(buffer, end);
for (int i = 0; i < end; i++)
_bit_data+=(buffer[i]);
_bit_length = _bit_data.size() * 8; _bit_length = _bit_data.size() * 8;
return 0; return 0;
} }

View File

@ -29,12 +29,10 @@ class LatticeBitParser: public ConfigBitstreamParser {
LatticeBitParser(const std::string &filename, bool verbose = false); LatticeBitParser(const std::string &filename, bool verbose = false);
~LatticeBitParser(); ~LatticeBitParser();
int parse() override; int parse() override;
void displayHeader();
private: private:
int parseHeader(); int parseHeader();
std::map<std::string, std::string> _attribs; size_t _endHeader;
int _endHeader;
}; };
#endif // LATTICEBITPARSER_HPP_ #endif // LATTICEBITPARSER_HPP_

View File

@ -293,7 +293,7 @@ int main(int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!args.bit_file.empty()) { if (!args.bit_file.empty() || !args.file_type.empty()) {
try { try {
fpga->program(args.offset); fpga->program(args.offset);
} catch (std::exception &e) { } catch (std::exception &e) {

View File

@ -15,7 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <sstream>
#include <string>
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
#include "display.hpp"
#include "mcsParser.hpp" #include "mcsParser.hpp"
using namespace std; using namespace std;
@ -50,61 +54,62 @@ McsParser::McsParser(const string &filename, bool reverseOrder, bool verbose):
int McsParser::parse() int McsParser::parse()
{ {
string str; string str;
int ret; istringstream lineStream(_raw_data);
do { while (std::getline(lineStream, str, '\n')) {
getline(_fd, str); char *ptr;
ret = parseLine(str); uint8_t sum = 0;
} while (ret == 0);
return (ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
}
int McsParser::parseLine(string buffer)
{
const char *buff = buffer.c_str();
uint16_t tmp, byteLen, type, checksum; uint16_t tmp, byteLen, type, checksum;
uint32_t addr, loc_addr; uint32_t addr, loc_addr;
uint8_t sum = 0;
if (buff[0] != ':') { /* if '\r' is present -> drop */
cout << "Error: a line must start with ':'" << endl; if (str.back() == '\r')
return -1; str.pop_back();
if (str[0] != ':') {
printError("Error: a line must start with ':'");
return EXIT_FAILURE;
} }
/* len */ /* len */
sscanf(buff + LEN_BASE, "%2hx", &byteLen); sscanf((char *)&str[LEN_BASE], "%2hx", &byteLen);
/* address */ /* address */
sscanf(buff + ADDR_BASE, "%4x", &addr); sscanf((char *)&str[ADDR_BASE], "%4x", &addr);
/* type */ /* type */
sscanf(buff + TYPE_BASE, "%2hx", &type); sscanf((char *)&str[TYPE_BASE], "%2hx", &type);
/* checksum */ /* checksum */
sscanf(buff + DATA_BASE + byteLen * 2, "%2hx", &checksum); sscanf((char *)&str[DATA_BASE + byteLen * 2], "%2hx", &checksum);
sum = byteLen + type + (addr & 0xff) + ((addr >> 8) & 0xff); sum = byteLen + type + (addr & 0xff) + ((addr >> 8) & 0xff);
if (type == 0) { switch (type) {
case 0:
loc_addr = _base_addr + addr; loc_addr = _base_addr + addr;
char *ptr = (char *)(buff + DATA_BASE); ptr = (char *)&str[DATA_BASE];
for (int i = 0; i < byteLen; i++, ptr += 2) { for (int i = 0; i < byteLen; i++, ptr += 2) {
sscanf(ptr, "%2hx", &tmp); sscanf(ptr, "%2hx", &tmp);
_bit_data[loc_addr + i] = (_reverseOrder)? reverseByte(tmp):tmp; _bit_data[loc_addr + i] = (_reverseOrder)? reverseByte(tmp):tmp;
sum += tmp; sum += tmp;
} }
_bit_length += (byteLen * 8); _bit_length += (byteLen * 8);
} else if (type == 1) { break;
return 1; case 1:
} else if (type == 4) { return EXIT_SUCCESS;
sscanf(buff + DATA_BASE, "%4x", &loc_addr); break;
case 4:
sscanf((char*)&str[DATA_BASE], "%4x", &loc_addr);
_base_addr = (loc_addr << 16); _base_addr = (loc_addr << 16);
sum += (loc_addr & 0xff) + ((loc_addr >> 8) & 0xff); sum += (loc_addr & 0xff) + ((loc_addr >> 8) & 0xff);
} else { break;
cerr << "Error: unknown type" << endl; default:
return -1; printError("Error: unknown type");
return EXIT_FAILURE;
} }
if (checksum != (0xff&((~sum)+1))) { if (checksum != (0xff&((~sum)+1))) {
cerr << "Error: wrong checksum" << endl; printError("Error: wrong checksum");
return -1; return EXIT_FAILURE;
}
} }
return 0; return EXIT_SUCCESS;
} }

View File

@ -18,6 +18,8 @@
#ifndef MCSPARSER_HPP #ifndef MCSPARSER_HPP
#define MCSPARSER_HPP #define MCSPARSER_HPP
#include <string>
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
class McsParser: public ConfigBitstreamParser { class McsParser: public ConfigBitstreamParser {
@ -26,8 +28,6 @@ class McsParser: public ConfigBitstreamParser {
int parse() override; int parse() override;
private: private:
int parseLine(std::string buffer);
int _base_addr; int _base_addr;
bool _reverseOrder; bool _reverseOrder;
}; };

View File

@ -16,6 +16,7 @@
*/ */
#include <stdexcept> #include <stdexcept>
#include <utility>
#include "configBitstreamParser.hpp" #include "configBitstreamParser.hpp"
#include "display.hpp" #include "display.hpp"
@ -30,16 +31,18 @@ RawParser::RawParser(const string &filename, bool reverseOrder):
int RawParser::parse() 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); _bit_data.resize(_file_size);
for (int i = 0; i < _file_size; i++) std::move(_raw_data.begin(), _raw_data.end(), _bit_data.begin());
_bit_data[i] = (_reverseOrder) ? reverseByte(_raw_data[i]): _raw_data[i]; _bit_length = _bit_data.size();
_bit_length = _bit_data.size() * 8;
//cout << "file length " << _bit_length << endl; 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; return EXIT_SUCCESS;
} }

View File

@ -99,9 +99,8 @@ void Xilinx::program(unsigned int offset)
printSuccess("DONE"); printSuccess("DONE");
int err = bit->parse();
printInfo("Parse file ", false); printInfo("Parse file ", false);
if (err == EXIT_FAILURE) { if (bit->parse() == EXIT_FAILURE) {
printError("FAIL"); printError("FAIL");
delete bit; delete bit;
return; return;
@ -109,6 +108,9 @@ void Xilinx::program(unsigned int offset)
printSuccess("DONE"); printSuccess("DONE");
} }
if (_verbose)
bit->displayHeader();
if (_mode == Device::SPI_MODE) { if (_mode == Device::SPI_MODE) {
program_spi(bit, offset); program_spi(bit, offset);
reset(); reset();