blob: 5464a5200b529b938351bf24eb9eb69796714ef1 [file] [log] [blame] [edit]
#ifndef PRJXRAY_LIB_XILINX_BITSTREAM_READER_H
#define PRJXRAY_LIB_XILINX_BITSTREAM_READER_H
#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
#include <absl/types/span.h>
#include <prjxray/big_endian_span.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/configuration_packet.h>
namespace prjxray {
namespace xilinx {
// Constructs a collection of 32-bit big-endian words from a bitstream file.
// Provides an iterator over the configuration packets.
template <typename ArchType>
class BitstreamReader {
public:
using value_type = ConfigurationPacket<typename ArchType::ConfRegType>;
// Implements an iterator over the words grouped in configuration
// packets.
class iterator
: public std::iterator<std::input_iterator_tag, value_type> {
public:
iterator& operator++();
bool operator==(const iterator& other) const;
bool operator!=(const iterator& other) const;
const value_type& operator*() const;
const value_type* operator->() const;
protected:
explicit iterator(absl::Span<uint32_t> words);
private:
friend BitstreamReader;
typename value_type::ParseResult parse_result_;
absl::Span<uint32_t> words_;
};
// Construct a reader from a collection of 32-bit, big-endian words.
// Assumes that any sync word has already been removed.
BitstreamReader(std::vector<uint32_t>&& words)
: words_(std::move(words)) {}
BitstreamReader() {}
size_t size() { return words_.size(); }
// Construct a `BitstreamReader` from a Container of bytes.
// Any bytes preceding an initial sync word are ignored.
template <typename T>
static absl::optional<BitstreamReader<ArchType>> InitWithBytes(
T bitstream);
const std::vector<uint32_t>& words() { return words_; };
// Returns an iterator that yields `ConfigurationPackets`
// as read from the bitstream.
iterator begin();
iterator end();
private:
static std::array<uint8_t, 4> kSyncWord;
std::vector<uint32_t> words_;
};
template <typename ArchType>
template <typename T>
absl::optional<BitstreamReader<ArchType>>
BitstreamReader<ArchType>::InitWithBytes(T bitstream) {
// If this is really a Xilinx bitstream, there will be a sync
// word somewhere toward the beginning.
auto sync_pos = std::search(bitstream.begin(), bitstream.end(),
kSyncWord.begin(), kSyncWord.end());
if (sync_pos == bitstream.end()) {
return absl::optional<BitstreamReader<ArchType>>();
}
sync_pos += kSyncWord.size();
// Wrap the provided container in a span that strips off the preamble.
absl::Span<typename T::value_type> bitstream_span(bitstream);
auto config_packets =
bitstream_span.subspan(sync_pos - bitstream.begin());
// Convert the bytes into 32-bit or 16-bit in case of Spartan6,
// big-endian words.
auto big_endian_reader =
make_big_endian_span<typename ArchType::WordType>(config_packets);
std::vector<uint32_t> words{big_endian_reader.begin(),
big_endian_reader.end()};
return BitstreamReader<ArchType>(std::move(words));
}
// Sync word as specified in UG470 page 81
template <typename ArchType>
std::array<uint8_t, 4> BitstreamReader<ArchType>::kSyncWord{0xAA, 0x99, 0x55,
0x66};
template <typename ArchType>
typename BitstreamReader<ArchType>::iterator
BitstreamReader<ArchType>::begin() {
return iterator(absl::MakeSpan(words_));
}
template <typename ArchType>
typename BitstreamReader<ArchType>::iterator BitstreamReader<ArchType>::end() {
return iterator({});
}
template <typename ArchType>
BitstreamReader<ArchType>::iterator::iterator(absl::Span<uint32_t> words) {
parse_result_.first = words;
parse_result_.second = {};
++(*this);
}
template <typename ArchType>
typename BitstreamReader<ArchType>::iterator&
BitstreamReader<ArchType>::iterator::operator++() {
do {
auto new_result =
ConfigurationPacket<typename ArchType::ConfRegType>::
InitWithWords(parse_result_.first,
parse_result_.second.has_value()
? parse_result_.second.operator->()
: nullptr);
// If the a valid header is being found but there are
// insufficient words to yield a packet, consider it the end.
if (new_result.first == parse_result_.first) {
words_ = absl::Span<uint32_t>();
break;
}
words_ = parse_result_.first;
parse_result_ = new_result;
} while (!parse_result_.first.empty() && !parse_result_.second);
if (!parse_result_.second) {
words_ = absl::Span<uint32_t>();
}
return *this;
}
template <typename ArchType>
bool BitstreamReader<ArchType>::iterator::operator==(
const iterator& other) const {
return words_ == other.words_;
}
template <typename ArchType>
bool BitstreamReader<ArchType>::iterator::operator!=(
const iterator& other) const {
return !(*this == other);
}
template <typename ArchType>
const typename BitstreamReader<ArchType>::value_type&
BitstreamReader<ArchType>::iterator::operator*() const {
return *(parse_result_.second);
}
template <typename ArchType>
const typename BitstreamReader<ArchType>::value_type*
BitstreamReader<ArchType>::iterator::operator->() const {
return parse_result_.second.operator->();
}
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_BITSTREAM_READER_H