From 89d874d15604613db234261bfc74146df359be65 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Mon, 18 Nov 2019 16:03:36 +0100 Subject: [PATCH] add parser for jed file (lattice) --- jedParser.cpp | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++ jedParser.hpp | 64 ++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 jedParser.cpp create mode 100644 jedParser.hpp diff --git a/jedParser.cpp b/jedParser.cpp new file mode 100644 index 0000000..34fda62 --- /dev/null +++ b/jedParser.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2019 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "jedParser.hpp" + +/* GGM: TODO + * - use NOTE for Lxxx + * - be less lattice compliant + */ + +using namespace std; + +JedParser::JedParser(string filename): + ConfigBitstreamParser(filename, ConfigBitstreamParser::BIN_MODE), + _fuse_count(0), _pin_count(0), _featuresRow(0), _feabits(0), _checksum(0) +{ +} + +/* fill a vector with consecutive lines until '*' + */ +vector JedParser::readJEDLine() +{ + string buffer; + vector lines; + bool inLine = true; + + do { + std::getline(_fd, buffer, '\n'); + if (buffer.size() == 0) + break; + + if (buffer[buffer.size()-1] == '*') { + inLine = false; + buffer.pop_back(); + } + lines.push_back(buffer); + } while (inLine); + return lines; +} + +/* convert one serie ASCII 1/0 to a vector of + * unsigned char + */ +void JedParser::buildDataArray(const string &content, struct jed_data &jed) +{ + size_t data_len = content.size(); + string tmp_buff; + uint8_t data = 0; + for (size_t i = 0; i < content.size(); i+=8) { + data = 0; + for (int ii = 0; ii < 8; ii++) { + uint8_t val = (content[i+ii] == '1'?1:0); + data |= val << ii; + } + tmp_buff += data; + } + jed.data.push_back(std::move(tmp_buff)); + jed.len += data_len; +} + +void JedParser::display() +{ + printf("feabits :\n"); + printf("%04x <-> %d\n", _feabits, _feabits); + /* 15-14: always 0 */ + printf("\tBoot Mode : "); + switch ((_feabits>>11)&0x07) { + case 0: + printf("Single Boot from Configuration Flash\n"); + break; + case 1: + printf("Dual Boot from Configuration Flash then External if there is a failure\n"); + break; + case 3: + printf("Single Boot from External Flash\n"); + break; + default: + printf("Error\n"); + } + + printf("\tMaster Mode SPI : %s\n", + (((_feabits>>11)&0x01)?"enable":"disable")); + printf("\tI2c port : %s\n", + (((_feabits>>10)&0x01)?"disable":"enable")); + printf("\tSlave SPI port : %s\n", + (((_feabits>>9)&0x01)?"disable":"enable")); + printf("\tJTAG port : %s\n", + (((_feabits>>8)&0x01)?"disable":"enable")); + printf("\tDONE : %s\n", + (((_feabits>>7)&0x01)?"enable":"disable")); + printf("\tINITN : %s\n", + (((_feabits>>6)&0x01)?"enable":"disable")); + printf("\tPROGRAMN : %s\n", + (((_feabits>>5)&0x01)?"disable":"enable")); + printf("\tMy_ASSP : %s\n", + (((_feabits>>4)&0x01)?"enable":"disable")); + /* 3-0: always 0 */ + + printf("Pin Count : %d\n", _pin_count); + printf("Fuse Count : %d\n", _fuse_count); +} + +/* E field, for latice contains two sub-field + * 1: Exxxx\n : feature Row + * 2: yyyy*\n : feabits + */ +void JedParser::parseEField(vector content) +{ + _featuresRow = 0; + string featuresRow = content[0].substr(1); + for (size_t i = 0; i < featuresRow.size(); i++) + _featuresRow |= ((featuresRow[i] - '0') << i); + string feabits = content[1]; + _feabits = 0; + for (size_t i = 0; i < feabits.size(); i++) { + _feabits |= ((feabits[i] - '0') << i); + } +} + +void JedParser::parseLField(vector content) +{ + int start_offset; + sscanf(content[0].substr(1).c_str(), "%d", &start_offset); + /* two possibilities + * current line finish with '*' : Lxxxx YYYYY* + * or current line is only offset and next(s) line(s) are data : + * Lxxxx + */ + struct jed_data d; + string buffer; + d.offset = start_offset; + d.len = 0; + if (content.size() > 1) { + for (size_t i = 1; i < content.size(); i++) { + if (content[i].size() != 0) + buildDataArray((content[i]), d); + } + } else { + // search space + std::istringstream iss(content[0]); + vector myList((std::istream_iterator(iss)), + std::istream_iterator()); + myList[1].pop_back(); + buildDataArray(myList[1], d); + } + _data_list.push_back(std::move(d)); +} + +int JedParser::parse() +{ + if (!_fd.is_open()) { + _fd.open(_filename); + if (!_fd.is_open()) { + cerr << "error to opening jed file " << _filename << endl; + return EXIT_FAILURE; + } + } + + string content; + + _fd.seekg(0, _fd.beg); + + /* First line must STX (0x02) */ + std::getline(_fd, content, '\n'); + if (content[0] != 0x02) { + printf("wrong file\n"); + return 0; + } + + /* read full content + * JED file end fix ETX (0x03) + file checksum + \n + */ + std::vectorlines; + do { + lines = readJEDLine(); + if (lines.size() == 0) { + printf("a un problem\n"); + break; + } + + switch (lines[0][0]) { + case 'N': // note + break; + case 'Q': + int count; + sscanf(lines[0].c_str()+2, "%d", &count); + switch (lines[0][1]) { + case 'F': // fuse count + _fuse_count = count; + break; + case 'P': // pin count + _pin_count = count; + break; + default: + cerr << "Error for 'Q' unknown qualifier " << lines[1] << endl; + return EXIT_FAILURE; + } + break; + case 'G': + cout << lines[0] << endl; + break; + case 'F': + cout << lines[0] << endl; + break; + case 'C': + sscanf(lines[0].c_str() + 1, "%hx", &_checksum); + cout << "fuse checksum " << lines[0]; + printf(" AA %x\n", _checksum); + break; + case 0x03: + cout << "end" << endl; + break; + case 'E': + parseEField(lines); + break; + case 'L': // fuse offset + parseLField(lines); + break; + default: + printf("inconnu\n"); + cout << lines[0]<< endl; + } + } while (lines[0][0] != 0x03); + + int size = 0; + for (size_t i = 0; i < _data_list.size(); i++) { + printf("area[%ld] %d %d\n", i, _data_list[i].offset, _data_list[i].len); + size += _data_list[i].len; + } + + uint16_t checksum = 0; + for (size_t line = 0; line < _data_list[0].data.size(); line++) { + for (size_t col = 0; col < _data_list[0].data[line].size(); col++) + checksum += (uint8_t)_data_list[0].data[line][col]; + } + + printf("theorical checksum %x -> %x\n", _checksum, checksum); + + FILE *fd = fopen("toto.txt", "w+"); + for (size_t line = 0; line < _data_list[0].data.size(); line++) { + for (size_t col = 0; col < _data_list[0].data[line].size(); col++) + fprintf(fd, "%02x ", (unsigned char)_data_list[0].data[line][col]); + fprintf(fd, "\n"); + } + fclose(fd); + printf("array size %ld\n", _data_list[0].data.size()); + + if (_fuse_count != size) + cerr << "Not all fuses are programmed" << endl; + + + return EXIT_SUCCESS; +} diff --git a/jedParser.hpp b/jedParser.hpp new file mode 100644 index 0000000..b3bf02e --- /dev/null +++ b/jedParser.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2019 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JEDPARSER_HPP_ +#define JEDPARSER_HPP_ + +#include + +#include +#include +#include +#include + +#include "configBitstreamParser.hpp" + +class JedParser: public ConfigBitstreamParser { + private: + struct jed_data { + int offset; + std::vector data; + int len; + }; + + public: + JedParser(std::string filename); + int parse(); + void display(); + + size_t nb_section() { return _data_list.size();} + size_t offset_for_section(int id) {return _data_list[id].offset;} + std::vector data_for_section(int id) { + return _data_list[id].data; + } + uint32_t feabits() {return _feabits;} + uint64_t featuresRow() {return _featuresRow;} + + private: + std::vectorreadJEDLine(); + void buildDataArray(const std::string &content, struct jed_data &jed); + void parseEField(const std::vector content); + void parseLField(const std::vector content); + + std::vector _data_list; + int _fuse_count; + int _pin_count; + uint64_t _featuresRow; + uint16_t _feabits; + uint16_t _checksum; +}; + +#endif // JEDPARSER_HPP_