| #include <absl/strings/str_split.h> | 
 | #include <algorithm> | 
 | #include <bitset> | 
 | #include <fstream> | 
 | #include <iomanip> | 
 | #include <iostream> | 
 | #include <stdexcept> | 
 | #include <string> | 
 |  | 
 | #include "configuration_packets.h" | 
 | #include "crc.h" | 
 | #include "ecc.h" | 
 | #include "header.h" | 
 |  | 
 | ConfigurationPackets::ConfigurationPackets(const std::string& arch) | 
 |     : words_per_frame_(words_in_architecture.at(arch)), | 
 |       architecture_(arch), | 
 |       ecc_(arch, words_per_frame_) {} | 
 |  | 
 | const std::unordered_map<std::string, size_t> | 
 |     ConfigurationPackets::words_in_architecture = {{"Series7", 101}, | 
 |                                                    {"UltraScale", 123}, | 
 |                                                    {"UltraScalePlus", 93}}; | 
 |  | 
 | std::shared_ptr<ConfigurationPackets> ConfigurationPackets::InitFromFile( | 
 |     const std::string& file, | 
 |     const std::string& arch) { | 
 | 	std::ifstream ifs(file, std::ifstream::in); | 
 | 	if (!ifs.good()) { | 
 | 		throw std::runtime_error("Couldn't open bits file\n"); | 
 | 	} | 
 | 	if (words_in_architecture.find(arch) == words_in_architecture.end()) { | 
 | 		throw std::runtime_error("Error: Unrecognized architecture " + | 
 | 		                         arch + "\n"); | 
 | 	} | 
 | 	std::shared_ptr<ConfigurationPackets> packets = | 
 | 	    std::make_shared<ConfigurationPackets>(arch); | 
 | 	packets->SetBits(ifs); | 
 | 	packets->UpdateECCs(); | 
 | 	return packets; | 
 | } | 
 |  | 
 | void ConfigurationPackets::SetBits(std::ifstream& ifs) { | 
 | 	while (!ifs.eof()) { | 
 | 		std::string line; | 
 | 		getline(ifs, line); | 
 | 		SetBit(line); | 
 | 	} | 
 | } | 
 |  | 
 | void ConfigurationPackets::WriteBits(std::ostream& out) { | 
 | 	header_->Write(out); | 
 | 	WriteFpgaConfiguration(out, fpga_configuration_head_); | 
 | 	WriteConfiguration(out); | 
 | 	WriteFpgaConfiguration(out, fpga_configuration_tail_); | 
 | } | 
 |  | 
 | void ConfigurationPackets::WriteFpgaConfiguration( | 
 |     std::ostream& out, | 
 |     const std::vector<uint32_t>& vect) { | 
 | 	for (auto& word : vect) { | 
 | 		out << std::bitset<32>(word) << std::endl; | 
 | 	} | 
 | } | 
 |  | 
 | void ConfigurationPackets::WriteConfiguration(std::ostream& out) { | 
 | 	for (auto packet = configuration_data_packets_.cbegin(); | 
 | 	     packet != configuration_data_packets_.cend(); ++packet) { | 
 | 		WritePacket(out, packet); | 
 | 		if (IsDifferentRow(packet, std::next(packet))) { | 
 | 			// Write the zero frame at the end of each row | 
 | 			WritePacket(out, packet); | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | void ConfigurationPackets::WritePacket( | 
 |     std::ostream& out, | 
 |     ConfigurationFrames::const_iterator frame_citr) const { | 
 | 	bool is_new_row(false); | 
 | 	if ((frame_citr == configuration_data_packets_.cbegin()) || | 
 | 	    IsDifferentRow(frame_citr, std::prev(frame_citr))) { | 
 | 		// Write the WCFG command followed by a FAR write with address | 
 | 		// of the next frame WCFG command write | 
 | 		out << std::bitset<32>(kCmdWrite | 0x1) << std::endl; | 
 | 		out << std::bitset<32>(0x1) << std::endl; | 
 | 		out << std::bitset<32>(kNop) << std::endl; | 
 | 		// FAR Write of the next frame followed by frame address | 
 | 		out << std::bitset<32>(kFarWrite | 0x1) << std::endl; | 
 | 		out << std::bitset<32>(frame_citr->first) << std::endl; | 
 | 		if (architecture_ == "Series7") { | 
 | 			out << std::bitset<32>(kNop) << std::endl; | 
 | 		} | 
 | 		is_new_row = true; | 
 | 	} | 
 | 	uint32_t crc(GetCRC(frame_citr, is_new_row)); | 
 | 	// FDRI Write | 
 | 	out << std::bitset<32>(kFdriWrite | words_per_frame_) << std::endl; | 
 | 	// Declared number of configuration words | 
 | 	for (auto& word : frame_citr->second) { | 
 | 		out << std::bitset<32>(word) << std::endl; | 
 | 	} | 
 | 	// FAR Write followed by frame address | 
 | 	out << std::bitset<32>(kFarWrite | 0x1) << std::endl; | 
 | 	out << std::bitset<32>(frame_citr->first) << std::endl; | 
 | 	// CRC Write followed by packet CRC | 
 | 	out << std::bitset<32>(kCrcWrite | 0x1) << std::endl; | 
 | 	out << std::bitset<32>(crc) << std::endl; | 
 | } | 
 |  | 
 | void ConfigurationPackets::SetBit(const std::string& line) { | 
 | 	if (line.empty()) { | 
 | 		return; | 
 | 	} | 
 | 	uint32_t frame_address, word, bit; | 
 | 	sscanf(line.c_str(), "bit_%08x_%03u_%02u", &frame_address, &word, &bit); | 
 | 	if (configuration_data_packets_.find(frame_address) == | 
 | 	    configuration_data_packets_.end()) { | 
 | 		configuration_data_packets_[frame_address] = | 
 | 		    std::vector<uint32_t>(words_per_frame_, 0x0); | 
 | 	} | 
 | 	configuration_data_packets_[frame_address].at(word) |= (1 << bit); | 
 | } | 
 |  | 
 | void ConfigurationPackets::Line2Vector(const std::string& line, | 
 |                                        std::vector<uint32_t>& vect) { | 
 | 	static std::function<uint32_t(const std::string& str)> str_to_uint = | 
 | 	    [](const std::string& str) -> uint32_t { | 
 | 		assert(!str.empty()); | 
 | 		return std::stoul(str, nullptr, 16); | 
 | 	}; | 
 | 	// Skip the line content description before the conversion | 
 | 	std::vector<std::string> str_vector = | 
 | 	    absl::StrSplit(line.substr(line.find(":") + 2), " "); | 
 | 	std::transform(str_vector.begin(), str_vector.end(), | 
 | 	               std::back_inserter(vect), str_to_uint); | 
 | } | 
 |  | 
 | void ConfigurationPackets::AddAuxData(const std::string& file) { | 
 | 	std::ifstream ifs(file, std::ifstream::in); | 
 | 	if (!ifs.good()) { | 
 | 		throw std::runtime_error("Couldn't open auxiliary data file\n"); | 
 | 	} | 
 |  | 
 | 	std::string line; | 
 | 	getline(ifs, line); | 
 | 	InitializeHeader(line); | 
 | 	getline(ifs, line); | 
 | 	InitializeFpgaConfigurationHead(line); | 
 | 	getline(ifs, line); | 
 | 	InitializeFpgaConfigurationTail(line); | 
 | 	getline(ifs, line); | 
 | 	InitializeConfigurationData(line); | 
 | } | 
 |  | 
 | uint32_t ConfigurationPackets::GetFpgaConfigurationCRC() const { | 
 | 	uint32_t crc(0); | 
 | 	auto far = std::search(fpga_configuration_head_.begin(), | 
 | 	                       fpga_configuration_head_.end(), kRCrcCmd.begin(), | 
 | 	                       kRCrcCmd.end()); | 
 | 	for (auto itr = far + kRCrcCmd.size(); | 
 | 	     itr != fpga_configuration_head_.end(); ++itr) { | 
 | 		if (*itr == kNop) | 
 | 			continue; | 
 | 		// Check if it is a write packet | 
 | 		assert(*itr & 0x30000000); | 
 | 		// Get the packet address | 
 | 		uint32_t addr = (*itr >> 13) & 0x1F; | 
 | 		std::advance(itr, 1); | 
 | 		assert(itr != fpga_configuration_head_.end()); | 
 | 		crc = icap_crc(addr, *itr, crc); | 
 | 	} | 
 | 	return crc; | 
 | } | 
 |  | 
 | uint32_t ConfigurationPackets::GetCRC( | 
 |     ConfigurationFrames::const_iterator frame_citr, | 
 |     bool is_new_row) const { | 
 | 	uint32_t crc = 0; | 
 | 	if (is_new_row) { | 
 | 		if (frame_citr == configuration_data_packets_.begin()) { | 
 | 			crc = GetFpgaConfigurationCRC(); | 
 | 		} | 
 | 		crc = icap_crc(kCmdReg, kWcfgCmd, crc); | 
 | 		crc = icap_crc(kFarReg, frame_citr->first, crc); | 
 | 	} | 
 | 	for (const auto& word : frame_citr->second) { | 
 | 		crc = icap_crc(kFdriReg, word, crc); | 
 | 	} | 
 | 	crc = icap_crc(kFarReg, frame_citr->first, crc); | 
 | 	return crc; | 
 | } | 
 |  | 
 | void ConfigurationPackets::UpdateECCs() { | 
 | 	for (auto& packet : configuration_data_packets_) { | 
 | 		auto& data = packet.second; | 
 | 		ecc_.UpdateFrameECC(data); | 
 | 	} | 
 | } | 
 |  | 
 | void ConfigurationPackets::InitializeConfigurationData( | 
 |     const std::string& line) { | 
 | 	std::function<void(const uint32_t&)> update_packets = | 
 | 	    [this](const uint32_t& addr) { | 
 | 		    if (configuration_data_packets_.find(addr) == | 
 | 		        configuration_data_packets_.end()) { | 
 | 			    configuration_data_packets_[addr] = | 
 | 			        std::vector<uint32_t>(words_per_frame_, 0x0); | 
 | 		    } | 
 | 	    }; | 
 | 	std::vector<uint32_t> frames_addr; | 
 | 	Line2Vector(line, frames_addr); | 
 | 	std::for_each(frames_addr.begin(), frames_addr.end(), update_packets); | 
 | } | 
 |  | 
 | void ConfigurationPackets::InitializeFpgaConfigurationHead( | 
 |     const std::string& line) { | 
 | 	Line2Vector(line, fpga_configuration_head_); | 
 | } | 
 |  | 
 | void ConfigurationPackets::InitializeFpgaConfigurationTail( | 
 |     const std::string& line) { | 
 | 	Line2Vector(line, fpga_configuration_tail_); | 
 | } | 
 |  | 
 | void ConfigurationPackets::InitializeHeader(const std::string& line) { | 
 | 	// FIXME Remove the configuration data head part once the aux data is | 
 | 	// fixed | 
 | 	header_ = std::make_unique<Header>(line, fpga_configuration_head_); | 
 | } | 
 |  | 
 | bool ConfigurationPackets::IsDifferentRow( | 
 |     ConfigurationFrames::const_iterator frame_citr1, | 
 |     ConfigurationFrames::const_iterator frame_citr2) const { | 
 | 	auto get_row = [this](const uint32_t& address) { | 
 | 		size_t row_shift = | 
 | 		    (architecture_ == "UltraScalePlus") ? 18 : 17; | 
 | 		return (address >> row_shift) & 0x3FF; | 
 | 	}; | 
 | 	return (get_row(frame_citr1->first) != get_row(frame_citr2->first)); | 
 | } |