Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
389d9edc5This 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) 2022 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*/
#include "pofParser.hpp"
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <regex>
#include <stdexcept>
#include <utility>
#include <vector>
#include "display.hpp"
POFParser::POFParser(const std::string &filename, bool verbose):
ConfigBitstreamParser(filename, ConfigBitstreamParser::BIN_MODE,
verbose)
{}
POFParser::~POFParser()
{}
uint8_t *POFParser::getData(const std::string §ion_name)
{
if (section_name == "")
return (uint8_t*)_bit_data.data();
auto section = mem_section.find(section_name);
if (section == mem_section.end())
return NULL;
return (*section).second.data;
}
int POFParser::getLength(const std::string §ion_name)
{
if (section_name == "")
return _bit_length;
auto section = mem_section.find(section_name);
if (section == mem_section.end())
return -1;
return (*section).second.len;
}
void POFParser::displayHeader()
{
ConfigBitstreamParser::displayHeader();
char mess[1024];
snprintf(mess, 1024, "Flag section offset len end");
printInfo(mess);
for (auto it = mem_section.begin(); it != mem_section.end(); it++) {
memory_section_t v = (*it).second;
snprintf(mess, 1024, "%02x %4s: ", v.flag, v.section.c_str());
printInfo(mess, false);
// start address + len (in bits) + end addr
snprintf(mess, 1024, " %08x %08x %08x", v.offset, v.len, v.offset + ((v.len/8)-1));
/* Note: for CFM0 end address is displayed with another value in () */
printSuccess(mess);
}
}
int POFParser::parse()
{
const uint32_t file_size = static_cast<uint32_t>(_file_size);
uint8_t *ptr = (uint8_t *)_raw_data.data();
uint32_t pos = 0;
if (_verbose)
printf("[%08x:%08x] %s\n", 0, 3, ptr);
/* [0:3]: POF\0 */
ptr += 4;
pos += 4;
/* unknown */
if (_verbose) {
if ((pos + 4) > file_size) {
printError("POFParser: Can't read first section");
return -1;
}
uint32_t first_section = ARRAY2INT32(ptr);
printf("first section: %08x %4u\n", first_section, first_section);
}
ptr += 4;
pos += 4;
/* number of packets */
if (_verbose) {
if ((pos + 4) > file_size) {
printError("POFParser: Can't read first section");
return -1;
}
uint32_t num_packets = ARRAY2INT32(ptr);
printf("number of packets: %08x %4u\n", num_packets, num_packets);
}
pos += 4;
/* 16bit code + 32bits size + content */
while (pos < file_size) {
if ((pos + 2) > file_size) {
printError("POFParser: Bound check failure: can't read flag");
return -1;
}
uint16_t flag = ARRAY2INT16((&_raw_data.data()[pos]));
pos += 2;
if ((pos + 4) > file_size) {
printError("POFParser: Bound check failure: can't read size");
return -1;
}
uint32_t size = ARRAY2INT32((&_raw_data.data()[pos]));
pos += 4;
if ((pos >= file_size) || ((pos + size) > file_size)) {
printError("POFParser: Bound check: can't parse section");
return -1;
}
uint32_t ret = parseSection(flag, pos, size);
if (ret != size) {
printError("POFParser: parseSection Failed");
return -1;
}
pos += ret;
}
/* update pointers to memory area */
ptr = (uint8_t *)_bit_data.data();
mem_section["CFM0"].data = &ptr[mem_section["CFM0"].offset + 0x0C];
if (mem_section.find("CFM1") != mem_section.end())
mem_section["CFM1"].data = &ptr[mem_section["CFM1"].offset + 0x0C];
if (mem_section.find("CFM2") != mem_section.end())
mem_section["CFM2"].data = &ptr[mem_section["CFM2"].offset + 0x0C];
mem_section["UFM"].data = &ptr[mem_section["UFM"].offset + 0x0C];
mem_section["ICB"].data = &ptr[mem_section["ICB"].offset + 0x0C];
return EXIT_SUCCESS;
}
uint32_t POFParser::parseSection(uint16_t flag, uint32_t pos, uint32_t size)
{
std::string content;
std::string t;
char mess[1024];
if (_verbose) {
snprintf(mess, 1024, "Flag: %02x (%d) Size: %u", flag, flag, size);
printInfo(mess);
}
/* 0x01: software name/version */
/* 0x02: full FPGAs model */
/* 0x03: bitstream name ? */
/* 0x3b: ? */
/* 0x12: ? */
/* 0x13: contains usercode / checksum */
/* 0x24: ? */
/* 0x11: ? */
/* 0x18: ? */
/* 0x15: ? */
/* 0x34: ? */
/* 0x35: ? */
/* 0x38: ? */
/* 0x08: ? CRC ? */
switch (flag) {
case 0x01: // software name/version
_hdr["tool"] = _raw_data.substr(pos, size);
break;
case 0x02: // full FPGA part name
_hdr["part_name"] = _raw_data.substr(pos, size-1); // -1 because '\0'
break;
case 0x03: // bitstream/design/xxx name
_hdr["design_name"] = _raw_data.substr(pos, size);
break;
case 0x08: // last packet: CRC ?
if (size < 2) {
printError("POFParser: flag 0x08 failed size too small");
return 0;
}
_hdr["maybeCRC"] = std::to_string(ARRAY2INT16((&_raw_data.data()[pos])));
break;
case 0x11: // cfg data
// 12 Bytes unknown
// followed by UFM/CFM/DSM data
if (_verbose) {
content = _raw_data.substr(pos, size);
if ((3 * 4) > size) {
printError("POFParser: can't display 0x11 area");
return -1;
}
uint32_t val0 = ARRAY2INT32((&content.c_str()[0]));
uint32_t val1 = ARRAY2INT32((&content.c_str()[4]));
uint32_t val2 = ARRAY2INT32((&content.c_str()[8]));
printf("Flag 0x11: Unknown %08x %08x %08x\n", val0, val1, val2);
}
_bit_data.resize(size);
std::copy(_raw_data.begin() + pos, _raw_data.begin() + pos + size,
_bit_data.begin());
_bit_length = size * 8;
if (_verbose)
printf("size %u %zu\n", size, _bit_data.size());
break;
case 0x13: // contains usercode / checksum
_hdr["usercode"] = std::to_string(ARRAY2INT32((&_raw_data.data()[pos+size-4])));
if (_verbose) {
if (size < 12) {
printf("POFParser: Can't display flag 0x13 area");
return -1;
}
t = _raw_data.substr(pos, size);
for (size_t i = 0; i < t.size(); i++)
printf("%02x ", static_cast<uint8_t>(t[i]));
printf("\n");
printf("%s\n", t.c_str());
/* 4 x 32bits */
uint32_t sec0, sec1, sec2, sec3;
sec0 = (t[0] << 24) | (t[1] << 16) | (t[2] << 8) | (t[3] << 0);
sec1 = (t[4] << 24) | (t[5] << 16) | (t[6] << 8) | (t[7] << 0);
sec2 = (t[8] << 24) | (t[9] << 16) | (t[10] << 8) | (t[11] << 0);
sec3 = ((unsigned char)t[size-4] << 24) |
((unsigned char)t[size-3] << 16) |
((unsigned char)t[size-2] << 8) |
((unsigned char)t[size-1] << 0);
printf("sec0: %08x\n", sec0);
printf("sec1: %08x\n", sec1);
printf("sec2: %08x\n", sec2);
printf("sec3: %08x\n", sec3);
}
break;
case 0x1a: // flash sections
// 12Bytes ?
// followed by flash sections separates by ';'
// 1B + name + ' ' + cfg data offset (bits) + size (bits)
content = _raw_data.substr(pos, size);
parseFlag26(flag, pos, size, content);
break;
default:
snprintf(mess, 1024, "unknown flag 0x%02x: offset %u length %u",
flag, pos - 6, size);
printWarn(mess);
break;
}
return size;
}
/* section with flag 0x11A */
/* 3 x 32bits -> unknown
* followed by flash sections separates by ';'
* 1B + name + ' ' + cfg data offset (bits) + size (bits)
*/
void POFParser::parseFlag26(uint16_t flag, uint32_t pos,
uint32_t size, const std::string &payload)
{
if (_verbose)
printf("%04x %08x %08x\n", flag, pos, size);
if (size != payload.size())
printf("mismatch size\n");
if (_verbose) {
uint32_t val0 = ARRAY2INT32((&payload.c_str()[0]));
uint32_t val1 = ARRAY2INT32((&payload.c_str()[4]));
uint32_t val2 = ARRAY2INT32((&payload.c_str()[8]));
printf("%08x %08x %08x\n", val0, val1, val2);
}
std::regex regex{R"([;]+)"}; // split on space
std::sregex_token_iterator it{payload.begin() + 12, payload.end(),
regex, -1};
std::vector<std::string> words{it, {}};
std::regex sp_reg{R"([\s]+)"}; // split on space
for (size_t i = 0; i < words.size(); i++) {
std::sregex_token_iterator it{words[i].begin(), words[i].end(),
sp_reg, -1};
std::vector<std::string> sect{it, {}};
uint32_t start = stoul(sect[1], nullptr, 16);
uint32_t length = stoul(sect[2], nullptr, 16);
uint8_t id = static_cast<uint8_t>(sect[0][0]);
std::string name = sect[0].substr(1);
mem_section.insert(std::pair<std::string, memory_section_t>(
name, {id, name, start, NULL, length}));
}
}