mirror of https://github.com/openXC7/prjxray.git
Merge pull request #1090 from antmicro/bitstream_tools_refactor
Bitstream tools: Move template methods from source to header files
This commit is contained in:
commit
05b3de8d93
|
|
@ -5,7 +5,6 @@ add_library(libprjxray
|
|||
xilinx/bitstream_writer.cc
|
||||
xilinx/configuration_packet.cc
|
||||
xilinx/configuration_register.cc
|
||||
xilinx/frames.cc
|
||||
xilinx/configuration.cc
|
||||
# Series-7 specific
|
||||
xilinx/xc7series/frame_address.cc
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@
|
|||
#define PRJXRAY_LIB_XILINX_BITSTREAM_WRITER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/strings/str_cat.h>
|
||||
#include <absl/time/clock.h>
|
||||
#include <absl/time/time.h>
|
||||
#include <absl/types/optional.h>
|
||||
#include <absl/types/span.h>
|
||||
|
||||
|
|
@ -19,6 +23,8 @@
|
|||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
|
||||
uint32_t packet2header(
|
||||
const ConfigurationPacket<Series7ConfigurationRegister>& packet);
|
||||
// Writes out the complete Xilinx bitstream including
|
||||
// header, sync word and configuration sequence.
|
||||
template <typename ArchType>
|
||||
|
|
@ -129,6 +135,287 @@ class BitstreamWriter {
|
|||
const std::string& generator_name);
|
||||
};
|
||||
|
||||
template <typename ArchType>
|
||||
int BitstreamWriter<ArchType>::writeBitstream(
|
||||
const typename ArchType::ConfigurationPackage& packets,
|
||||
const std::string& part_name,
|
||||
const std::string& frames_file,
|
||||
const std::string& generator_name,
|
||||
const std::string& output_file) {
|
||||
std::ofstream out_file(output_file, std::ofstream::binary);
|
||||
if (!out_file) {
|
||||
std::cerr << "Unable to open file for writting: " << output_file
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
BitstreamHeader bit_header(
|
||||
create_header(part_name, frames_file, generator_name));
|
||||
out_file.write(reinterpret_cast<const char*>(bit_header.data()),
|
||||
bit_header.size());
|
||||
|
||||
auto end_of_header_pos = out_file.tellp();
|
||||
auto header_data_length_pos =
|
||||
end_of_header_pos - static_cast<std::ofstream::off_type>(4);
|
||||
|
||||
BitstreamWriter<ArchType> out_bitstream_writer(packets);
|
||||
int bytes_per_word = sizeof(typename ArchType::WordType);
|
||||
for (uint32_t word : out_bitstream_writer) {
|
||||
for (int byte = bytes_per_word - 1; byte >= 0; byte--) {
|
||||
out_file.put((word >> (byte * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t length_of_data = out_file.tellp() - end_of_header_pos;
|
||||
|
||||
out_file.seekp(header_data_length_pos);
|
||||
for (int byte = 3; byte >= 0; byte--) {
|
||||
out_file.put((length_of_data >> (byte * 8)) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::BitstreamHeader
|
||||
BitstreamWriter<ArchType>::create_header(const std::string& part_name,
|
||||
const std::string& frames_file_name,
|
||||
const std::string& generator_name) {
|
||||
// Sync header
|
||||
BitstreamHeader bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
|
||||
0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 'a'};
|
||||
auto build_source =
|
||||
absl::StrCat(frames_file_name, ";Generator=" + generator_name);
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_source.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(build_source.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_source.begin(),
|
||||
build_source.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Source file.
|
||||
bit_header.push_back('b');
|
||||
bit_header.push_back(static_cast<uint8_t>((part_name.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(part_name.size() + 1));
|
||||
bit_header.insert(bit_header.end(), part_name.begin(), part_name.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Build timestamp.
|
||||
auto build_time = absl::Now();
|
||||
auto build_date_string =
|
||||
absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone());
|
||||
auto build_time_string =
|
||||
absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone());
|
||||
|
||||
bit_header.push_back('c');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_date_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_date_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_date_string.begin(),
|
||||
build_date_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
bit_header.push_back('d');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_time_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_time_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_time_string.begin(),
|
||||
build_time_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0});
|
||||
return bit_header;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator
|
||||
BitstreamWriter<ArchType>::iterator::packet_begin() {
|
||||
// itr_packets = packets.begin();
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>& packet =
|
||||
**itr_packets_;
|
||||
|
||||
return BitstreamWriter::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
|
||||
packet.data().begin());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator
|
||||
BitstreamWriter<ArchType>::iterator::packet_end() {
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>& packet =
|
||||
**itr_packets_;
|
||||
|
||||
return BitstreamWriter<ArchType>::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_END,
|
||||
// Essentially ignored
|
||||
packet.data().end());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
BitstreamWriter<ArchType>::packet_iterator::packet_iterator(
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>* packet,
|
||||
state_t state,
|
||||
data_iterator_t itr_data)
|
||||
: state_(state), itr_data_(itr_data), packet_(packet) {}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator&
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator++() {
|
||||
if (state_ == STATE_HEADER) {
|
||||
itr_data_ = packet_->data().begin();
|
||||
if (itr_data_ == packet_->data().end()) {
|
||||
state_ = STATE_END;
|
||||
} else {
|
||||
state_ = STATE_DATA;
|
||||
}
|
||||
} else if (state_ == STATE_DATA) {
|
||||
/// Advance. data must be valid while not at end
|
||||
itr_data_++;
|
||||
// Reached this end of this packet?
|
||||
if (itr_data_ == packet_->data().end()) {
|
||||
state_ = STATE_END;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::packet_iterator::operator==(
|
||||
const packet_iterator& other) const {
|
||||
return state_ == other.state_ && itr_data_ == other.itr_data_;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::packet_iterator::operator!=(
|
||||
const packet_iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator*() const {
|
||||
if (state_ == STATE_HEADER) {
|
||||
return packet2header(*packet_);
|
||||
} else if (state_ == STATE_DATA) {
|
||||
return *itr_data_;
|
||||
}
|
||||
return 0; // XXX: assert or something?
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator->() const {
|
||||
return *(*this);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* BitstreamWriter::iterator
|
||||
*************************************************/
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator
|
||||
BitstreamWriter<ArchType>::begin() {
|
||||
typename packets_t::const_iterator itr_packets = packets_.begin();
|
||||
absl::optional<packet_iterator> op_packet_itr;
|
||||
|
||||
// May have no packets
|
||||
if (itr_packets != packets_.end()) {
|
||||
// op_packet_itr = packet_begin();
|
||||
// FIXME: de-duplicate this
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>&
|
||||
packet = **itr_packets;
|
||||
packet_iterator packet_itr =
|
||||
packet_iterator(&packet, packet_iterator::STATE_HEADER,
|
||||
packet.data().begin());
|
||||
op_packet_itr = packet_itr;
|
||||
}
|
||||
return iterator(header_.begin(), packets_, itr_packets, op_packet_itr);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator BitstreamWriter<ArchType>::end() {
|
||||
return iterator(header_.end(), packets_, packets_.end(),
|
||||
absl::optional<packet_iterator>());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
BitstreamWriter<ArchType>::iterator::iterator(
|
||||
header_t::iterator itr_header,
|
||||
const typename BitstreamWriter<ArchType>::packets_t& packets,
|
||||
typename BitstreamWriter<ArchType>::packets_t::const_iterator itr_packets,
|
||||
absl::optional<packet_iterator> itr_packet)
|
||||
: itr_header_(itr_header),
|
||||
packets_(packets),
|
||||
itr_packets_(itr_packets),
|
||||
op_itr_packet_(itr_packet) {}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator&
|
||||
BitstreamWriter<ArchType>::iterator::operator++() {
|
||||
// Still generating header?
|
||||
if (itr_header_ != header_.end()) {
|
||||
itr_header_++;
|
||||
// Finished header?
|
||||
// Will advance to initialized itr_packets value
|
||||
// XXX: maybe should just overwrite here
|
||||
if (itr_header_ == header_.end()) {
|
||||
itr_packets_ = packets_.begin();
|
||||
if (itr_packets_ != packets_.end()) {
|
||||
op_itr_packet_ = packet_begin();
|
||||
}
|
||||
}
|
||||
// Then somewhere in packets
|
||||
} else {
|
||||
// We are either at end() in which case this operation is
|
||||
// invalid Or there is a packet in progress packet in progress?
|
||||
// Advance it
|
||||
++(*op_itr_packet_);
|
||||
// Done with this packet?
|
||||
if (*op_itr_packet_ == packet_end()) {
|
||||
itr_packets_++;
|
||||
if (itr_packets_ == packets_.end()) {
|
||||
// we are at the very end
|
||||
// invalidate data to be neat
|
||||
op_itr_packet_.reset();
|
||||
} else {
|
||||
op_itr_packet_ = packet_begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::iterator::operator==(
|
||||
const iterator& other) const {
|
||||
return itr_header_ == other.itr_header_ &&
|
||||
itr_packets_ == other.itr_packets_ &&
|
||||
op_itr_packet_ == other.op_itr_packet_;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::iterator::operator!=(
|
||||
const iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::iterator::operator*() const {
|
||||
if (itr_header_ != header_.end()) {
|
||||
return *itr_header_;
|
||||
} else {
|
||||
// Iterating over packets, get data from current packet position
|
||||
return *(*op_itr_packet_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::iterator::operator->() const {
|
||||
return *(*this);
|
||||
}
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
#ifndef PRJXRAY_LIB_XILINX_FRAMES_H
|
||||
#define PRJXRAY_LIB_XILINX_FRAMES_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/strings/str_split.h>
|
||||
#include <prjxray/xilinx/architectures.h>
|
||||
#include <prjxray/xilinx/xc7series/ecc.h>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
|
|
@ -29,15 +33,93 @@ class Frames {
|
|||
const absl::optional<typename ArchType::Part>& part);
|
||||
|
||||
// Returns the map with frame addresses and corresponding data
|
||||
Frames2Data& getFrames();
|
||||
Frames2Data& getFrames() { return frames_data_; }
|
||||
|
||||
private:
|
||||
Frames2Data frames_data_;
|
||||
|
||||
// Updates the ECC information in the frame.
|
||||
// Updates the ECC information in the frame
|
||||
void updateECC(FrameData& data);
|
||||
};
|
||||
|
||||
template <typename ArchType>
|
||||
void Frames<ArchType>::updateECC(typename Frames<ArchType>::FrameData& data) {
|
||||
xc7series::updateECC(data);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
int Frames<ArchType>::readFrames(const std::string& frm_file_str) {
|
||||
assert(!frm_file_str.empty());
|
||||
|
||||
std::ifstream frm_file(frm_file_str);
|
||||
if (!frm_file) {
|
||||
std::cerr << "Unable to open frm file: " << frm_file_str
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string frm_line;
|
||||
|
||||
while (std::getline(frm_file, frm_line)) {
|
||||
if (frm_line[0] == '#')
|
||||
continue;
|
||||
|
||||
std::pair<std::string, std::string> frame_delta =
|
||||
absl::StrSplit(frm_line, ' ');
|
||||
|
||||
uint32_t frame_address =
|
||||
std::stoul(frame_delta.first, nullptr, 16);
|
||||
|
||||
std::vector<std::string> frame_data_strings =
|
||||
absl::StrSplit(frame_delta.second, ',');
|
||||
|
||||
if (frame_data_strings.size() != ArchType::words_per_frame) {
|
||||
std::cerr << "Frame " << std::hex << frame_address
|
||||
<< ": found " << std::dec
|
||||
<< frame_data_strings.size()
|
||||
<< " words instead of "
|
||||
<< ArchType::words_per_frame << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameData frame_data(frame_data_strings.size(), 0);
|
||||
std::transform(frame_data_strings.begin(),
|
||||
frame_data_strings.end(), frame_data.begin(),
|
||||
[](const std::string& val) -> uint32_t {
|
||||
return std::stoul(val, nullptr, 16);
|
||||
});
|
||||
|
||||
updateECC(frame_data);
|
||||
|
||||
// Insert the frame address and corresponding frame data to the
|
||||
// map
|
||||
typename ArchType::FrameAddress frm_addr(frame_address);
|
||||
frames_data_.insert(
|
||||
std::pair<typename ArchType::FrameAddress, FrameData>(
|
||||
frm_addr, frame_data));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
void Frames<ArchType>::addMissingFrames(
|
||||
const absl::optional<typename ArchType::Part>& part) {
|
||||
auto current_frame_address =
|
||||
absl::optional<typename ArchType::FrameAddress>(
|
||||
typename ArchType::FrameAddress(0));
|
||||
do {
|
||||
auto iter = frames_data_.find(*current_frame_address);
|
||||
if (iter == frames_data_.end()) {
|
||||
FrameData frame_data(ArchType::words_per_frame, 0);
|
||||
frames_data_.insert(
|
||||
std::pair<typename ArchType::FrameAddress,
|
||||
FrameData>(*current_frame_address,
|
||||
frame_data));
|
||||
}
|
||||
current_frame_address =
|
||||
part->GetNextFrameAddress(*current_frame_address);
|
||||
} while (current_frame_address);
|
||||
}
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define PRJXRAY_LIB_XILINX_XC7SERIES_ECC_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
|
|
@ -9,9 +10,11 @@ namespace xc7series {
|
|||
|
||||
// Extend the current ECC code with one data word (32 bit) at a given
|
||||
// word index in the configuration frame and return the new ECC code.
|
||||
|
||||
uint32_t icap_ecc(uint32_t idx, uint32_t data, uint32_t ecc);
|
||||
|
||||
// Updates the ECC information in the frame.
|
||||
void updateECC(std::vector<uint32_t>& data);
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <absl/strings/str_cat.h>
|
||||
#include <absl/strings/str_split.h>
|
||||
#include <absl/time/clock.h>
|
||||
#include <absl/time/time.h>
|
||||
|
||||
#include <prjxray/bit_ops.h>
|
||||
#include <prjxray/xilinx/architectures.h>
|
||||
#include <prjxray/xilinx/bitstream_writer.h>
|
||||
|
|
@ -18,162 +12,6 @@ template <>
|
|||
typename BitstreamWriter<Series7>::header_t BitstreamWriter<Series7>::header_{
|
||||
0xFFFFFFFF, 0x000000BB, 0x11220044, 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566};
|
||||
|
||||
template <typename ArchType>
|
||||
int BitstreamWriter<ArchType>::writeBitstream(
|
||||
const typename ArchType::ConfigurationPackage& packets,
|
||||
const std::string& part_name,
|
||||
const std::string& frames_file,
|
||||
const std::string& generator_name,
|
||||
const std::string& output_file) {
|
||||
std::ofstream out_file(output_file, std::ofstream::binary);
|
||||
if (!out_file) {
|
||||
std::cerr << "Unable to open file for writting: " << output_file
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
BitstreamHeader bit_header(
|
||||
create_header(part_name, frames_file, generator_name));
|
||||
out_file.write(reinterpret_cast<const char*>(bit_header.data()),
|
||||
bit_header.size());
|
||||
|
||||
auto end_of_header_pos = out_file.tellp();
|
||||
auto header_data_length_pos =
|
||||
end_of_header_pos - static_cast<std::ofstream::off_type>(4);
|
||||
|
||||
BitstreamWriter<ArchType> out_bitstream_writer(packets);
|
||||
int bytes_per_word = sizeof(typename ArchType::WordType);
|
||||
for (uint32_t word : out_bitstream_writer) {
|
||||
for (int byte = bytes_per_word - 1; byte >= 0; byte--) {
|
||||
out_file.put((word >> (byte * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t length_of_data = out_file.tellp() - end_of_header_pos;
|
||||
|
||||
out_file.seekp(header_data_length_pos);
|
||||
for (int byte = 3; byte >= 0; byte--) {
|
||||
out_file.put((length_of_data >> (byte * 8)) & 0xFF);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::BitstreamHeader
|
||||
BitstreamWriter<ArchType>::create_header(const std::string& part_name,
|
||||
const std::string& frames_file_name,
|
||||
const std::string& generator_name) {
|
||||
// Sync header
|
||||
BitstreamHeader bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
|
||||
0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 'a'};
|
||||
auto build_source =
|
||||
absl::StrCat(frames_file_name, ";Generator=" + generator_name);
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_source.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(build_source.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_source.begin(),
|
||||
build_source.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Source file.
|
||||
bit_header.push_back('b');
|
||||
bit_header.push_back(static_cast<uint8_t>((part_name.size() + 1) >> 8));
|
||||
bit_header.push_back(static_cast<uint8_t>(part_name.size() + 1));
|
||||
bit_header.insert(bit_header.end(), part_name.begin(), part_name.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
// Build timestamp.
|
||||
auto build_time = absl::Now();
|
||||
auto build_date_string =
|
||||
absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone());
|
||||
auto build_time_string =
|
||||
absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone());
|
||||
|
||||
bit_header.push_back('c');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_date_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_date_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_date_string.begin(),
|
||||
build_date_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
|
||||
bit_header.push_back('d');
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>((build_time_string.size() + 1) >> 8));
|
||||
bit_header.push_back(
|
||||
static_cast<uint8_t>(build_time_string.size() + 1));
|
||||
bit_header.insert(bit_header.end(), build_time_string.begin(),
|
||||
build_time_string.end());
|
||||
bit_header.push_back(0x0);
|
||||
bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0});
|
||||
return bit_header;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator
|
||||
BitstreamWriter<ArchType>::iterator::packet_begin() {
|
||||
// itr_packets = packets.begin();
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>& packet =
|
||||
**itr_packets_;
|
||||
|
||||
return BitstreamWriter::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
|
||||
packet.data().begin());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator
|
||||
BitstreamWriter<ArchType>::iterator::packet_end() {
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>& packet =
|
||||
**itr_packets_;
|
||||
|
||||
return BitstreamWriter<ArchType>::packet_iterator(
|
||||
&packet, BitstreamWriter::packet_iterator::STATE_END,
|
||||
// Essentially ignored
|
||||
packet.data().end());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
BitstreamWriter<ArchType>::packet_iterator::packet_iterator(
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>* packet,
|
||||
state_t state,
|
||||
data_iterator_t itr_data)
|
||||
: state_(state), itr_data_(itr_data), packet_(packet) {}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::packet_iterator&
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator++() {
|
||||
if (state_ == STATE_HEADER) {
|
||||
itr_data_ = packet_->data().begin();
|
||||
if (itr_data_ == packet_->data().end()) {
|
||||
state_ = STATE_END;
|
||||
} else {
|
||||
state_ = STATE_DATA;
|
||||
}
|
||||
} else if (state_ == STATE_DATA) {
|
||||
/// Advance. data must be valid while not at end
|
||||
itr_data_++;
|
||||
// Reached this end of this packet?
|
||||
if (itr_data_ == packet_->data().end()) {
|
||||
state_ = STATE_END;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::packet_iterator::operator==(
|
||||
const packet_iterator& other) const {
|
||||
return state_ == other.state_ && itr_data_ == other.itr_data_;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::packet_iterator::operator!=(
|
||||
const packet_iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
uint32_t packet2header(
|
||||
const ConfigurationPacket<Series7ConfigurationRegister>& packet) {
|
||||
uint32_t ret = 0;
|
||||
|
|
@ -206,145 +44,5 @@ uint32_t packet2header(
|
|||
return ret;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator*() const {
|
||||
if (state_ == STATE_HEADER) {
|
||||
return packet2header(*packet_);
|
||||
} else if (state_ == STATE_DATA) {
|
||||
return *itr_data_;
|
||||
}
|
||||
return 0; // XXX: assert or something?
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::packet_iterator::operator->() const {
|
||||
return *(*this);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* BitstreamWriter::iterator
|
||||
*************************************************/
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator
|
||||
BitstreamWriter<ArchType>::begin() {
|
||||
typename packets_t::const_iterator itr_packets = packets_.begin();
|
||||
absl::optional<packet_iterator> op_packet_itr;
|
||||
|
||||
// May have no packets
|
||||
if (itr_packets != packets_.end()) {
|
||||
// op_packet_itr = packet_begin();
|
||||
// FIXME: de-duplicate this
|
||||
const ConfigurationPacket<typename ArchType::ConfRegType>&
|
||||
packet = **itr_packets;
|
||||
packet_iterator packet_itr =
|
||||
packet_iterator(&packet, packet_iterator::STATE_HEADER,
|
||||
packet.data().begin());
|
||||
op_packet_itr = packet_itr;
|
||||
}
|
||||
return iterator(header_.begin(), packets_, itr_packets, op_packet_itr);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator BitstreamWriter<ArchType>::end() {
|
||||
return iterator(header_.end(), packets_, packets_.end(),
|
||||
absl::optional<packet_iterator>());
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
BitstreamWriter<ArchType>::iterator::iterator(
|
||||
header_t::iterator itr_header,
|
||||
const typename BitstreamWriter<ArchType>::packets_t& packets,
|
||||
typename BitstreamWriter<ArchType>::packets_t::const_iterator itr_packets,
|
||||
absl::optional<packet_iterator> itr_packet)
|
||||
: itr_header_(itr_header),
|
||||
packets_(packets),
|
||||
itr_packets_(itr_packets),
|
||||
op_itr_packet_(itr_packet) {}
|
||||
|
||||
template <typename ArchType>
|
||||
typename BitstreamWriter<ArchType>::iterator&
|
||||
BitstreamWriter<ArchType>::iterator::operator++() {
|
||||
// Still generating header?
|
||||
if (itr_header_ != header_.end()) {
|
||||
itr_header_++;
|
||||
// Finished header?
|
||||
// Will advance to initialized itr_packets value
|
||||
// XXX: maybe should just overwrite here
|
||||
if (itr_header_ == header_.end()) {
|
||||
itr_packets_ = packets_.begin();
|
||||
if (itr_packets_ != packets_.end()) {
|
||||
op_itr_packet_ = packet_begin();
|
||||
}
|
||||
}
|
||||
// Then somewhere in packets
|
||||
} else {
|
||||
// We are either at end() in which case this operation is
|
||||
// invalid Or there is a packet in progress packet in progress?
|
||||
// Advance it
|
||||
++(*op_itr_packet_);
|
||||
// Done with this packet?
|
||||
if (*op_itr_packet_ == packet_end()) {
|
||||
itr_packets_++;
|
||||
if (itr_packets_ == packets_.end()) {
|
||||
// we are at the very end
|
||||
// invalidate data to be neat
|
||||
op_itr_packet_.reset();
|
||||
} else {
|
||||
op_itr_packet_ = packet_begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::iterator::operator==(
|
||||
const iterator& other) const {
|
||||
return itr_header_ == other.itr_header_ &&
|
||||
itr_packets_ == other.itr_packets_ &&
|
||||
op_itr_packet_ == other.op_itr_packet_;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
bool BitstreamWriter<ArchType>::iterator::operator!=(
|
||||
const iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::iterator::operator*() const {
|
||||
if (itr_header_ != header_.end()) {
|
||||
return *itr_header_;
|
||||
} else {
|
||||
// Iterating over packets, get data from current packet position
|
||||
return *(*op_itr_packet_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
const typename BitstreamWriter<ArchType>::itr_value_type
|
||||
BitstreamWriter<ArchType>::iterator::operator->() const {
|
||||
return *(*this);
|
||||
}
|
||||
|
||||
template int BitstreamWriter<Series7>::writeBitstream(
|
||||
const Series7::ConfigurationPackage&,
|
||||
const std::string&,
|
||||
const std::string&,
|
||||
const std::string&,
|
||||
const std::string&);
|
||||
template BitstreamWriter<Series7>::iterator BitstreamWriter<Series7>::begin();
|
||||
template BitstreamWriter<Series7>::iterator BitstreamWriter<Series7>::end();
|
||||
template const BitstreamWriter<Series7>::itr_value_type
|
||||
BitstreamWriter<Series7>::iterator::operator*() const;
|
||||
template BitstreamWriter<Series7>::iterator&
|
||||
BitstreamWriter<Series7>::iterator::operator++();
|
||||
template bool BitstreamWriter<Series7>::iterator::operator!=(
|
||||
const BitstreamWriter<Series7>::iterator&) const;
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <absl/strings/str_split.h>
|
||||
|
||||
#include <prjxray/xilinx/frames.h>
|
||||
#include <prjxray/xilinx/xc7series/ecc.h>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
|
||||
template <typename ArchType>
|
||||
typename Frames<ArchType>::Frames2Data& Frames<ArchType>::getFrames() {
|
||||
return frames_data_;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
int Frames<ArchType>::readFrames(const std::string& frm_file_str) {
|
||||
assert(!frm_file_str.empty());
|
||||
|
||||
std::ifstream frm_file(frm_file_str);
|
||||
if (!frm_file) {
|
||||
std::cerr << "Unable to open frm file: " << frm_file_str
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string frm_line;
|
||||
|
||||
while (std::getline(frm_file, frm_line)) {
|
||||
if (frm_line[0] == '#')
|
||||
continue;
|
||||
|
||||
std::pair<std::string, std::string> frame_delta =
|
||||
absl::StrSplit(frm_line, ' ');
|
||||
|
||||
uint32_t frame_address =
|
||||
std::stoul(frame_delta.first, nullptr, 16);
|
||||
|
||||
std::vector<std::string> frame_data_strings =
|
||||
absl::StrSplit(frame_delta.second, ',');
|
||||
|
||||
if (frame_data_strings.size() != ArchType::words_per_frame) {
|
||||
std::cerr << "Frame " << std::hex << frame_address
|
||||
<< ": found " << std::dec
|
||||
<< frame_data_strings.size()
|
||||
<< " words instead of "
|
||||
<< ArchType::words_per_frame << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameData frame_data(frame_data_strings.size(), 0);
|
||||
std::transform(frame_data_strings.begin(),
|
||||
frame_data_strings.end(), frame_data.begin(),
|
||||
[](const std::string& val) -> uint32_t {
|
||||
return std::stoul(val, nullptr, 16);
|
||||
});
|
||||
|
||||
updateECC(frame_data);
|
||||
|
||||
// Insert the frame address and corresponding frame data to the
|
||||
// map
|
||||
typename ArchType::FrameAddress frm_addr(frame_address);
|
||||
frames_data_.insert(
|
||||
std::pair<typename ArchType::FrameAddress, FrameData>(
|
||||
frm_addr, frame_data));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ArchType>
|
||||
void Frames<ArchType>::addMissingFrames(
|
||||
const absl::optional<typename ArchType::Part>& part) {
|
||||
auto current_frame_address =
|
||||
absl::optional<typename ArchType::FrameAddress>(
|
||||
typename ArchType::FrameAddress(0));
|
||||
do {
|
||||
auto iter = frames_data_.find(*current_frame_address);
|
||||
if (iter == frames_data_.end()) {
|
||||
FrameData frame_data(ArchType::words_per_frame, 0);
|
||||
frames_data_.insert(
|
||||
std::pair<typename ArchType::FrameAddress,
|
||||
FrameData>(*current_frame_address,
|
||||
frame_data));
|
||||
}
|
||||
current_frame_address =
|
||||
part->GetNextFrameAddress(*current_frame_address);
|
||||
} while (current_frame_address);
|
||||
}
|
||||
|
||||
static uint32_t calculateECC(const typename Frames<Series7>::FrameData& data) {
|
||||
uint32_t ecc = 0;
|
||||
for (size_t ii = 0; ii < data.size(); ++ii) {
|
||||
ecc = xc7series::icap_ecc(ii, data[ii], ecc);
|
||||
}
|
||||
return ecc;
|
||||
}
|
||||
|
||||
template <>
|
||||
void Frames<Series7>::updateECC(FrameData& data) {
|
||||
assert(data.size() != 0);
|
||||
// Replace the old ECC with the new.
|
||||
data[0x32] &= 0xFFFFE000;
|
||||
data[0x32] |= (calculateECC(data) & 0x1FFF);
|
||||
}
|
||||
|
||||
template Frames<Series7>::Frames2Data& Frames<Series7>::getFrames();
|
||||
template void Frames<Series7>::addMissingFrames(
|
||||
const absl::optional<Series7::Part>& part);
|
||||
template int Frames<Series7>::readFrames(const std::string&);
|
||||
template void Frames<Series7>::updateECC(Frames<Series7>::FrameData&);
|
||||
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
#include <prjxray/xilinx/xc7series/ecc.h>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace prjxray {
|
||||
namespace xilinx {
|
||||
namespace xc7series {
|
||||
|
||||
constexpr size_t kECCFrameNumber = 0x32;
|
||||
|
||||
uint32_t icap_ecc(uint32_t idx, uint32_t data, uint32_t ecc) {
|
||||
uint32_t val = idx * 32; // bit offset
|
||||
|
||||
|
|
@ -36,6 +40,21 @@ uint32_t icap_ecc(uint32_t idx, uint32_t data, uint32_t ecc) {
|
|||
return ecc;
|
||||
}
|
||||
|
||||
static uint32_t calculateECC(const std::vector<uint32_t>& data) {
|
||||
uint32_t ecc = 0;
|
||||
for (size_t ii = 0; ii < data.size(); ++ii) {
|
||||
ecc = xc7series::icap_ecc(ii, data[ii], ecc);
|
||||
}
|
||||
return ecc;
|
||||
}
|
||||
|
||||
void updateECC(std::vector<uint32_t>& data) {
|
||||
assert(data.size() >= kECCFrameNumber);
|
||||
// Replace the old ECC with the new.
|
||||
data[kECCFrameNumber] &= 0xFFFFE000;
|
||||
data[kECCFrameNumber] |= (calculateECC(data) & 0x1FFF);
|
||||
}
|
||||
|
||||
} // namespace xc7series
|
||||
} // namespace xilinx
|
||||
} // namespace prjxray
|
||||
|
|
|
|||
Loading…
Reference in New Issue