|  | #include "header.h" | 
|  | #include <algorithm> | 
|  | #include <ctime> | 
|  | #include <sstream> | 
|  |  | 
|  | Header::Header(const std::string& line, | 
|  | std::vector<uint32_t>& fpga_config_packets) { | 
|  | absl::string_view header_str(line); | 
|  | // Go to tag 'a' of the TLV formatted header | 
|  | header_str.remove_prefix(header_str.find("61")); | 
|  | bool tlv_header_end = false; | 
|  | while (!tlv_header_end) { | 
|  | char tag = char(GetByteAndAdvance(header_str)); | 
|  | switch (tag) { | 
|  | case 'a': | 
|  | design_name_ = GetTLVHeaderValue(header_str); | 
|  | break; | 
|  | case 'b': | 
|  | part_ = GetTLVHeaderValue(header_str); | 
|  | break; | 
|  | case 'c': | 
|  | date_ = GetTLVHeaderValue(header_str); | 
|  | break; | 
|  | case 'd': | 
|  | date_ += " " + GetTLVHeaderValue(header_str); | 
|  | break; | 
|  | case 'e': | 
|  | // Get number of bytes in bitstream and multiply | 
|  | // by 8 to obtain number of bits | 
|  | no_bits_ = GetWord(header_str) * 8; | 
|  | tlv_header_end = true; | 
|  | break; | 
|  | default: | 
|  | assert(false); | 
|  | } | 
|  | } | 
|  | while (!header_str.empty()) { | 
|  | fpga_config_packets.emplace_back(GetWord(header_str)); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string Header::GetDate() { | 
|  | int year, month, day, hour, min, sec; | 
|  | std::replace_if(date_.begin(), date_.end(), | 
|  | [](char c) { return c == '/' or c == ':'; }, ' '); | 
|  | std::istringstream(date_) >> year >> month >> day >> hour >> min >> sec; | 
|  | std::tm time_raw = {sec, min, hour, day, month - 1, year - 1900}; | 
|  | time_t time = mktime(&time_raw); | 
|  | const std::tm* time_out = std::localtime(&time); | 
|  | return std::string(std::asctime(time_out)); | 
|  | } | 
|  |  | 
|  | std::string Header::GetArchitecture() { | 
|  | if (part_.find("xczu") != std::string::npos) { | 
|  | return "zynquplus"; | 
|  | } | 
|  | if (part_.find("7a") != std::string::npos) { | 
|  | return "artix7"; | 
|  | } | 
|  | if (part_.find("xcku") != std::string::npos) { | 
|  | return "kintexu"; | 
|  | } | 
|  | return "Unknown architecture"; | 
|  | } | 
|  |  | 
|  | void Header::Write(std::ostream& out) { | 
|  | out << "Xilinx ASCII Bitstream" << std::endl; | 
|  | out << "Created by" << std::endl; | 
|  | out << "Design name:   " << design_name_ << std::endl; | 
|  | out << "Architecture:  " << GetArchitecture() << std::endl; | 
|  | out << "Part:          " << part_ << std::endl; | 
|  | out << "Date:          " << GetDate(); | 
|  | out << "Bits:          " << no_bits_ << std::endl; | 
|  | } | 
|  |  | 
|  | size_t Header::GetByteAndAdvance(absl::string_view& str_view) { | 
|  | size_t space_pos(str_view.find(" ")); | 
|  | size_t byte = | 
|  | std::stoul(std::string(str_view.substr(0, space_pos)), nullptr, 16); | 
|  | str_view.remove_prefix((space_pos != absl::string_view::npos) | 
|  | ? space_pos + 1 | 
|  | : str_view.size()); | 
|  | return byte; | 
|  | } | 
|  |  | 
|  | size_t Header::GetTLVHeaderLength(absl::string_view& str_view) { | 
|  | return (GetByteAndAdvance(str_view) << 8) | GetByteAndAdvance(str_view); | 
|  | } | 
|  |  | 
|  | std::string Header::GetTLVHeaderValue(absl::string_view& str_view) { | 
|  | size_t length(GetTLVHeaderLength(str_view)); | 
|  | std::string value; | 
|  | for (size_t i = 0; i < length; i++) { | 
|  | value += char(GetByteAndAdvance(str_view)); | 
|  | } | 
|  | // Lose trailing 0x00 | 
|  | value.pop_back(); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | uint32_t Header::GetWord(absl::string_view& str_view) { | 
|  | return (GetByteAndAdvance(str_view) << 24) | | 
|  | (GetByteAndAdvance(str_view) << 16) | | 
|  | (GetByteAndAdvance(str_view) << 8) | GetByteAndAdvance(str_view); | 
|  | } |