Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
0f0688d80This file is pinned to the selected release. Download the original to open it in your design tool.
// SPDX-License-Identifier: Apache-2.0
/*
* 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 -> extended 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];
if (_bit_data.size() < loc_addr + byteLen)
_bit_data.resize(2*(loc_addr + byteLen));
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;
case 4: // Extended Linear Address Record
if (addr != 0 || byteLen != 2) {
printError("Error: Wrong Extented Linear Address Record instruction");
return EXIT_FAILURE;
}
sscanf((char *)&str[DATA_BASE], "%4hx", &tmp);
_base_addr = ((uint32_t)tmp << 16);
sum += ((tmp >> 0) & 0xff) + ((tmp >> 8) & 0xff);
break;
case 5: // Start Linear Address Record.
if (addr != 0 || byteLen != 4) {
printError("Error: Wrong Start Linear Address Record instruction");
return EXIT_FAILURE;
}
sscanf((char *)&str[DATA_BASE], "%4x", &addr);
_base_addr = addr;
for (uint8_t i = 0; i < 4; i++)
sum += (addr >> (i * 8)) & 0xff;
break;
default:
char mess[256];
snprintf(mess, 256, "Error: unknown type %d %d %d\n", type,
byteLen, addr);
printError(mess);
return EXIT_FAILURE;
}
if (checksum != (0xff&((~sum)+1))) {
char mess[256];
snprintf(mess, 256, "Error: wrong checksum %02x %02x %02x",
checksum, sum, (0xff & ((~sum) + 1)));
printError(mess);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}