ihexParser: new parser for (i)hex files
This commit is contained in:
parent
bbc1c4dde4
commit
c09bc0662b
|
|
@ -49,6 +49,7 @@ set(OPENFPGALOADER_SOURCE
|
|||
src/efinix.cpp
|
||||
src/efinixHexParser.cpp
|
||||
src/ice40.cpp
|
||||
src/ihexParser.cpp
|
||||
src/spiFlash.cpp
|
||||
src/rawParser.cpp
|
||||
src/usbBlaster.cpp
|
||||
|
|
@ -85,7 +86,8 @@ set(OPENFPGALOADER_HEADERS
|
|||
src/dirtyJtag.hpp
|
||||
src/efinix.hpp
|
||||
src/efinixHexParser.hpp
|
||||
src/ice40.cpp
|
||||
src/ice40.hpp
|
||||
src/ihexParser.hpp
|
||||
src/progressBar.hpp
|
||||
src/rawParser.hpp
|
||||
src/usbBlaster.hpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
// SPDX-License-Identifier: GPL-v3
|
||||
/*
|
||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "configBitstreamParser.hpp"
|
||||
#include "display.hpp"
|
||||
#include "ihexParser.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* line format
|
||||
* :LLAAAATTHH...HHCC
|
||||
* LL : nb octets de data dans la ligne (hexa)
|
||||
* AAAA : addresse du debut de la ligne ou mettre les data
|
||||
* TT : type de la ligne (cf. plus bas)
|
||||
* HH : le champ de data
|
||||
* CC : Checksum (cf. plus bas)
|
||||
*/
|
||||
/* type : 00 -> data + addr 16b
|
||||
* 01 -> end of file
|
||||
* 02 -> extended addr
|
||||
* 03 -> start segment addr record
|
||||
* 04 -> extented linear addr record
|
||||
* 05 -> start linear addr record
|
||||
*/
|
||||
|
||||
#define LEN_BASE 1
|
||||
#define ADDR_BASE 3
|
||||
#define TYPE_BASE 7
|
||||
#define DATA_BASE 9
|
||||
|
||||
IhexParser::IhexParser(const string &filename, bool reverseOrder, bool verbose):
|
||||
ConfigBitstreamParser(filename, ConfigBitstreamParser::ASCII_MODE,
|
||||
verbose),
|
||||
_base_addr(0), _reverseOrder(reverseOrder)
|
||||
{}
|
||||
|
||||
int IhexParser::parse()
|
||||
{
|
||||
string str;
|
||||
istringstream lineStream(_raw_data);
|
||||
|
||||
uint16_t next_addr = 0;
|
||||
bool is_first = true;
|
||||
data_line_t cnt;
|
||||
cnt.length = 0;
|
||||
|
||||
while (std::getline(lineStream, str, '\n')) {
|
||||
char *ptr;
|
||||
uint8_t sum = 0;
|
||||
uint16_t tmp, byteLen, type, checksum;
|
||||
uint32_t addr, loc_addr;
|
||||
|
||||
/* if '\r' is present -> drop */
|
||||
if (str.back() == '\r')
|
||||
str.pop_back();
|
||||
|
||||
if (str[0] == '#') // comment
|
||||
continue;
|
||||
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;
|
||||
/* if this is the first line
|
||||
* prepare structure with base address
|
||||
* if previous address + line length didn't match new addr
|
||||
* -> break -> store and start a new section
|
||||
*/
|
||||
if (next_addr != addr || is_first) {
|
||||
if (!is_first)
|
||||
_array_content.push_back(cnt);
|
||||
cnt.addr = loc_addr;
|
||||
cnt.length = 0;
|
||||
cnt.line_data.clear();
|
||||
is_first = false;
|
||||
}
|
||||
|
||||
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;
|
||||
cnt.line_data.push_back(_bit_data[loc_addr+i]);
|
||||
}
|
||||
cnt.length += byteLen;
|
||||
next_addr = addr + byteLen;
|
||||
_bit_length += (byteLen * 8);
|
||||
break;
|
||||
case 1:
|
||||
if (cnt.length != 0)
|
||||
_array_content.push_back(cnt);
|
||||
return EXIT_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
printError("Error: unknown type");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (checksum != (0xff&((~sum)+1))) {
|
||||
printError("Error: wrong checksum");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
#ifndef SRC_IHEXPARSER_HPP_
|
||||
#define SRC_IHEXPARSER_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "configBitstreamParser.hpp"
|
||||
|
||||
/*!
|
||||
* \file ihexParser
|
||||
* \brief IhexParser
|
||||
* \brief class used to read a (i)hex data file
|
||||
* \author Gwenhael Goavec-Merou
|
||||
*/
|
||||
class IhexParser: public ConfigBitstreamParser {
|
||||
public:
|
||||
/*!
|
||||
* \brief constructor
|
||||
* \param[in] filename: file path
|
||||
* \param[in] reverseOrder: MSB or LSB storage
|
||||
* \param[in] verbose: verbosity level
|
||||
*/
|
||||
IhexParser(const std::string &filename, bool reverseOrder, bool verbose);
|
||||
/*!
|
||||
* \brief read full content of the file, fill sections
|
||||
*/
|
||||
int parse() override;
|
||||
|
||||
/*!
|
||||
* structure to store file content by section
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t addr;
|
||||
uint16_t length;
|
||||
std::vector<uint8_t> line_data;
|
||||
} data_line_t;
|
||||
|
||||
/*!
|
||||
* \brief return list of sections
|
||||
*/
|
||||
std::vector<data_line_t> getDataArray() {return _array_content;}
|
||||
|
||||
private:
|
||||
int _base_addr;
|
||||
bool _reverseOrder;
|
||||
std::vector<uint32_t> _data;
|
||||
std::vector<data_line_t> _array_content; /**< list of sections */
|
||||
};
|
||||
|
||||
#endif // SRC_IHEXPARSER_HPP_
|
||||
|
||||
Loading…
Reference in New Issue