posParser: introducing intel/altera POF file parser
This commit is contained in:
parent
d5190a3bd4
commit
2df7606300
|
|
@ -89,9 +89,10 @@ set(OPENFPGALOADER_SOURCE
|
|||
src/fx2_ll.cpp
|
||||
src/ice40.cpp
|
||||
src/ihexParser.cpp
|
||||
src/pofParser.cpp
|
||||
src/rawParser.cpp
|
||||
src/spiFlash.cpp
|
||||
src/spiInterface.cpp
|
||||
src/rawParser.cpp
|
||||
src/usbBlaster.cpp
|
||||
src/epcq.cpp
|
||||
src/svf_jtag.cpp
|
||||
|
|
@ -137,6 +138,7 @@ set(OPENFPGALOADER_HEADERS
|
|||
src/fx2_ll.hpp
|
||||
src/ice40.hpp
|
||||
src/ihexParser.hpp
|
||||
src/pofParser.hpp
|
||||
src/progressBar.hpp
|
||||
src/rawParser.hpp
|
||||
src/usbBlaster.hpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
// 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();
|
||||
return mem_section[section_name].data;
|
||||
}
|
||||
|
||||
int POFParser::getLength(const std::string §ion_name)
|
||||
{
|
||||
if (section_name == "")
|
||||
return _bit_length;
|
||||
return mem_section[section_name].len;
|
||||
}
|
||||
|
||||
void POFParser::displayHeader()
|
||||
{
|
||||
ConfigBitstreamParser::displayHeader();
|
||||
for (auto it = mem_section.begin(); it != mem_section.end(); it++) {
|
||||
memory_section_t v = (*it).second;
|
||||
char mess[1024];
|
||||
snprintf(mess, 1024, "%02x %4s: ", v.flag, v.section.c_str());
|
||||
printInfo(mess, false);
|
||||
snprintf(mess, 1024, "%08x %08x", v.offset, v.len);
|
||||
printSuccess(mess);
|
||||
}
|
||||
}
|
||||
|
||||
int POFParser::parse()
|
||||
{
|
||||
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) {
|
||||
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) {
|
||||
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 < static_cast<uint32_t>(_file_size)) {
|
||||
uint16_t flag = ARRAY2INT16((&_raw_data.data()[pos]));
|
||||
pos += 2;
|
||||
uint32_t size = ARRAY2INT32((&_raw_data.data()[pos]));
|
||||
pos += 4;
|
||||
pos += parseSection(flag, pos, size);
|
||||
}
|
||||
|
||||
/* update pointers to memory area */
|
||||
ptr = (uint8_t *)_bit_data.data();
|
||||
mem_section["CFM0"].data = &ptr[mem_section["CFM0"].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;
|
||||
|
||||
if (_verbose)
|
||||
printf("%d %u\n", flag, size);
|
||||
|
||||
/* 0x01: software name/version */
|
||||
/* 0x02: full FPGAs model */
|
||||
/* 0x03: bitstream name ? */
|
||||
/* 0x3b: ? */
|
||||
/* 0x12: ? */
|
||||
/* 0x13: containts 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);
|
||||
break;
|
||||
case 0x03: // bitstream/design/xxx name
|
||||
_hdr["design_name"] = _raw_data.substr(pos, size);
|
||||
break;
|
||||
case 0x08: // last packet: CRC ?
|
||||
_hdr["maybeCRC"] = std::to_string(ARRAY2INT16((&_raw_data.data()[pos])));
|
||||
break;
|
||||
case 0x11: // cfg data
|
||||
// 12 Bytes unknown
|
||||
// followed by UFM/CFM/DSM data
|
||||
_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 %lu\n", size, _bit_data.size());
|
||||
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:
|
||||
char mess[1024];
|
||||
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}));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
/*
|
||||
* Copyright (C) 2022 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||
*/
|
||||
|
||||
#ifndef SRC_POFPARSER_HPP_
|
||||
#define SRC_POFPARSER_HPP_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "configBitstreamParser.hpp"
|
||||
|
||||
#define ARRAY2INT16(_array_) ( \
|
||||
(static_cast<uint16_t>(_array_[0] & 0x00ff) << 0) | \
|
||||
(static_cast<uint16_t>(_array_[1] & 0x00ff) << 8))
|
||||
|
||||
#define ARRAY2INT32(_array_) ( \
|
||||
(static_cast<uint16_t>(_array_[0] & 0x00ff) << 0) | \
|
||||
(static_cast<uint16_t>(_array_[1] & 0x00ff) << 8) | \
|
||||
(static_cast<uint16_t>(_array_[2] & 0x00ff) << 16) | \
|
||||
(static_cast<uint16_t>(_array_[3] & 0x00ff) << 24))
|
||||
|
||||
/*!
|
||||
* \file pofParser.hpp
|
||||
* \class POFParser
|
||||
* \brief basic implementation for intel/altera POF format
|
||||
* \author Gwenhael Goavec-Merou
|
||||
*/
|
||||
class POFParser: public ConfigBitstreamParser {
|
||||
public:
|
||||
POFParser(const std::string &filename, bool verbose = false);
|
||||
~POFParser();
|
||||
|
||||
int parse() override;
|
||||
|
||||
/**
|
||||
* \brief return pointer to cfg data section when name is provided
|
||||
* when "" -> return full cfg_data
|
||||
* \return a pointer
|
||||
*/
|
||||
uint8_t *getData(const std::string §ion_name);
|
||||
|
||||
/**
|
||||
* \brief return length (bits) to a cfg data section when name is
|
||||
* provided or full cfg_data length when ""
|
||||
* \return size in bits
|
||||
*/
|
||||
int getLength(const std::string §ion_name);
|
||||
|
||||
/**
|
||||
* \brief display header informations
|
||||
*/
|
||||
void displayHeader() override;
|
||||
|
||||
|
||||
private:
|
||||
/* packet 0x1A content */
|
||||
typedef struct {
|
||||
uint8_t flag; // 1 Byte before section name
|
||||
std::string section; // UFM/CFM/ICB
|
||||
uint32_t offset; // start offset in packet 17 area
|
||||
uint8_t *data; // memory pointer
|
||||
uint32_t len; // area length (bits)
|
||||
} memory_section_t;
|
||||
|
||||
std::map<std::string, memory_section_t> mem_section;
|
||||
|
||||
/*!
|
||||
* \brief parse a section 0x1A (list of sections)
|
||||
* \param[in] flag: 16Bits flag
|
||||
* \param[in] pos : 32bits _raw_data's offset
|
||||
* \param[in] size: 32bits content's size
|
||||
*/
|
||||
void parseFlag26(uint16_t flag, uint32_t pos,
|
||||
uint32_t size, const std::string &payload);
|
||||
|
||||
/*!
|
||||
* \brief parse a section (flag + pos + size)
|
||||
* \param[in] flag: 16Bits flag
|
||||
* \param[in] pos : 32bits _raw_data's offset
|
||||
* \param[in] size: 32bits content's size
|
||||
* \return size
|
||||
*/
|
||||
uint32_t parseSection(uint16_t flag, uint32_t pos, uint32_t size);
|
||||
};
|
||||
#endif // SRC_POFPARSER_HPP_
|
||||
Loading…
Reference in New Issue