/* * 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; }