Replace API for Series7

Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
This commit is contained in:
Tomasz Michalak 2019-10-02 08:32:24 +02:00
parent 8739b9f9bf
commit 35b7130116
39 changed files with 1955 additions and 1576 deletions

View File

@ -2,24 +2,24 @@ add_library(libprjxray
database.cc
memory_mapped_file.cc
segbits_file_reader.cc
xilinx/xc7series/bitstream_reader.cc
xilinx/xc7series/bitstream_writer.cc
xilinx/xc7series/block_type.cc
xilinx/xc7series/configuration_bus.cc
xilinx/xc7series/configuration_column.cc
xilinx/xc7series/configuration_packet.cc
xilinx/xc7series/configuration_packetizer.cc
xilinx/xc7series/configuration_register.cc
xilinx/bitstream_writer.cc
xilinx/configuration_packet.cc
xilinx/configuration_packetizer.cc
xilinx/configuration_register.cc
xilinx/frames.cc
xilinx/configuration.cc
# Series-7 specific
xilinx/xc7series/frame_address.cc
xilinx/xc7series/global_clock_region.cc
xilinx/xc7series/part.cc
xilinx/xc7series/row.cc
xilinx/xc7series/frames.cc
xilinx/xc7series/utils.cc
xilinx/xc7series/configuration_row.cc
xilinx/xc7series/block_type.cc
xilinx/xc7series/configuration_bus.cc
xilinx/xc7series/configuration_column.cc
xilinx/xc7series/ecc.cc
)
target_include_directories(libprjxray PUBLIC "include")
target_link_libraries(libprjxray absl::optional absl::strings absl::span absl::time yaml-cpp)
target_link_libraries(libprjxray absl::optional absl::variant absl::strings absl::span absl::time yaml-cpp)
if (PRJXRAY_BUILD_TESTING)
add_executable(big_endian_span_test big_endian_span_test.cc)

View File

@ -0,0 +1,55 @@
#ifndef PRJXRAY_LIB_XILINX_ARCHITECTURES_H_
#define PRJXRAY_LIB_XILINX_ARCHITECTURES_H_
#include <absl/types/variant.h>
#include <memory>
#include <vector>
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_register.h>
#include <prjxray/xilinx/xc7series/frame_address.h>
#include <prjxray/xilinx/xc7series/part.h>
namespace prjxray {
namespace xilinx {
class Series7;
class Architecture {
public:
using Container = absl::variant<Series7>;
virtual const std::string& name() const = 0;
};
class Series7 : public Architecture {
public:
using ConfRegType = Series7ConfigurationRegister;
using Part = xc7series::Part;
using ConfigurationPackage =
std::vector<std::unique_ptr<ConfigurationPacket<ConfRegType>>>;
using FrameAddress = xc7series::FrameAddress;
using WordType = uint32_t;
Series7() : name_("Series7") {}
const std::string& name() const override { return name_; }
static constexpr int words_per_frame = 101;
private:
std::string name_;
};
class ArchitectureFactory {
public:
static Architecture::Container create_architecture(
const std::string& arch) {
if (arch == "Series7") {
return Series7();
} else {
return Architecture::Container();
}
}
};
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_ARCHITECTURES_H_

View File

@ -0,0 +1,179 @@
#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 <>
template <typename T>
absl::optional<BitstreamReader<Series7>>
BitstreamReader<Series7>::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<Series7>>();
}
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, big-endian words.
auto big_endian_reader = make_big_endian_span<uint32_t>(config_packets);
std::vector<uint32_t> words{big_endian_reader.begin(),
big_endian_reader.end()};
return BitstreamReader<Series7>(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

View File

@ -3,8 +3,8 @@
* file This includes the following: -Bus auto detection -Sync Word -FPGA
* configuration
*/
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_WRITER_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_WRITER_H
#ifndef PRJXRAY_LIB_XILINX_BITSTREAM_WRITER_H
#define PRJXRAY_LIB_XILINX_BITSTREAM_WRITER_H
#include <algorithm>
#include <memory>
@ -14,16 +14,21 @@
#include <absl/types/span.h>
#include <prjxray/big_endian_span.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/configuration_packet.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
// Writes out the complete Xilinx bitstream including
// header, sync word and configuration sequence.
template <typename ArchType>
class BitstreamWriter {
public:
typedef std::array<uint32_t, 6> header_t;
typedef std::vector<std::unique_ptr<ConfigurationPacket>> packets_t;
typedef std::vector<uint32_t> header_t;
typedef std::vector<std::unique_ptr<
ConfigurationPacket<typename ArchType::ConfRegType>>>
packets_t;
typedef std::vector<uint8_t> BitstreamHeader;
// Only defined if a packet exists
typedef absl::optional<absl::Span<const uint32_t>> op_data_t;
typedef absl::Span<const uint32_t>::iterator data_iterator_t;
@ -47,9 +52,11 @@ class BitstreamWriter {
} state_t;
protected:
explicit packet_iterator(const ConfigurationPacket* packet,
state_t state,
data_iterator_t itr_data);
explicit packet_iterator(
const ConfigurationPacket<typename ArchType::ConfRegType>*
packet,
state_t state,
data_iterator_t itr_data);
private:
friend iterator;
@ -61,10 +68,10 @@ class BitstreamWriter {
// Over packet.data()
data_iterator_t itr_data_;
const ConfigurationPacket* packet_;
const ConfigurationPacket<typename ArchType::ConfRegType>*
packet_;
};
using value_type = uint32_t;
class iterator
: public std::iterator<std::input_iterator_tag, itr_value_type> {
public:
@ -83,7 +90,7 @@ class BitstreamWriter {
explicit iterator(
header_t::iterator itr_header,
const packets_t& packets,
packets_t::const_iterator itr_packets,
typename packets_t::const_iterator itr_packets,
absl::optional<packet_iterator> op_itr_packet);
private:
@ -92,21 +99,36 @@ class BitstreamWriter {
// First over the fixed header, then the configuration data
header_t::iterator itr_header_;
const packets_t& packets_;
packets_t::const_iterator itr_packets_;
typename packets_t::const_iterator itr_packets_;
absl::optional<packet_iterator> op_itr_packet_;
};
BitstreamWriter(const packets_t& packets);
BitstreamWriter(const packets_t& packets) : packets_(packets) {}
// Writes out the complete bitstream for Xilinx FPGA based on
// the Configuration Package which holds the complete programming
// sequence.
int 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);
iterator begin();
iterator end();
private:
static header_t header_;
const packets_t& packets_;
// Creates a Xilinx bit header which is mostly a
// Tag-Length-Value(TLV) format documented here:
// http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm
BitstreamHeader create_header(const std::string& part_name,
const std::string& frames_file_name,
const std::string& generator_name);
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,30 +1,51 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_H_
#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_H_
#define PRJXRAY_LIB_XILINX_CONFIGURATION_H_
#include <map>
#include <type_traits>
#include <absl/types/span.h>
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/frame_address.h>
#include <prjxray/xilinx/xc7series/part.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/frames.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
template <typename ArchType>
class Configuration {
public:
using FrameMap = std::map<FrameAddress, absl::Span<const uint32_t>>;
using FrameMap = std::map<typename ArchType::FrameAddress,
absl::Span<const uint32_t>>;
using PacketData = std::vector<uint32_t>;
// Returns a configuration, i.e. collection of frame addresses
// and corresponding data from a collection of configuration packets.
template <typename Collection>
static absl::optional<Configuration> InitWithPackets(
const Part& part,
static absl::optional<Configuration<ArchType>> InitWithPackets(
const typename ArchType::Part& part,
Collection& packets);
Configuration(const Part& part,
std::map<FrameAddress, std::vector<uint32_t>>* frames)
// Creates the complete configuration package which is later on
// used by the bitstream writer to generate the bitstream file.
// The pacakge forms a sequence suitable for Xilinx devices.
// The programming sequence for Series-7 is taken from
// https://www.kc8apf.net/2018/05/unpacking-xilinx-7-series-bitstreams-part-2/
static void createConfigurationPackage(
typename ArchType::ConfigurationPackage& out_packets,
const PacketData& packet_data,
absl::optional<typename ArchType::Part>& part);
// Returns the payload for a type 2 packet
// which allows for bigger payload compared to type 1.
static PacketData createType2ConfigurationPacketData(
const typename Frames<ArchType>::Frames2Data& frames,
absl::optional<typename ArchType::Part>& part);
Configuration(const typename ArchType::Part& part,
std::map<typename ArchType::FrameAddress,
std::vector<uint32_t>>* frames)
: part_(part) {
for (auto& frame : *frames) {
frames_[frame.first] =
@ -32,23 +53,24 @@ class Configuration {
}
}
Configuration(const Part& part, const FrameMap& frames)
Configuration(const typename ArchType::Part& part,
const FrameMap& frames)
: part_(part), frames_(std::move(frames)) {}
const Part& part() const { return part_; }
const typename ArchType::Part& part() const { return part_; }
const FrameMap& frames() const { return frames_; }
private:
static constexpr int kWordsPerFrame = 101;
Part part_;
typename ArchType::Part part_;
FrameMap frames_;
};
template <>
template <typename Collection>
absl::optional<Configuration> Configuration::InitWithPackets(
const Part& part,
absl::optional<Configuration<Series7>> Configuration<Series7>::InitWithPackets(
const typename Series7::Part& part,
Collection& packets) {
using ArchType = Series7;
// Registers that can be directly written to.
uint32_t command_register = 0;
uint32_t frame_address_register = 0;
@ -57,27 +79,29 @@ absl::optional<Configuration> Configuration::InitWithPackets(
// Internal state machine for writes.
bool start_new_write = false;
FrameAddress current_frame_address = 0;
typename ArchType::FrameAddress current_frame_address = 0;
Configuration::FrameMap frames;
Configuration<ArchType>::FrameMap frames;
for (auto packet : packets) {
if (packet.opcode() != ConfigurationPacket::Opcode::Write) {
if (packet.opcode() !=
ConfigurationPacket<
typename ArchType::ConfRegType>::Opcode::Write) {
continue;
}
switch (packet.address()) {
case ConfigurationRegister::MASK:
case ArchType::ConfRegType::MASK:
if (packet.data().size() < 1)
continue;
mask_register = packet.data()[0];
break;
case ConfigurationRegister::CTL1:
case ArchType::ConfRegType::CTL1:
if (packet.data().size() < 1)
continue;
ctl1_register =
packet.data()[0] & mask_register;
break;
case ConfigurationRegister::CMD:
case ArchType::ConfRegType::CMD:
if (packet.data().size() < 1)
continue;
command_register = packet.data()[0];
@ -88,7 +112,7 @@ absl::optional<Configuration> Configuration::InitWithPackets(
start_new_write = true;
}
break;
case ConfigurationRegister::IDCODE:
case ArchType::ConfRegType::IDCODE:
// This really should be a one-word write.
if (packet.data().size() < 1)
continue;
@ -99,7 +123,7 @@ absl::optional<Configuration> Configuration::InitWithPackets(
return {};
}
break;
case ConfigurationRegister::FAR:
case ArchType::ConfRegType::FAR:
// This really should be a one-word write.
if (packet.data().size() < 1)
continue;
@ -123,7 +147,7 @@ absl::optional<Configuration> Configuration::InitWithPackets(
start_new_write = true;
}
break;
case ConfigurationRegister::FDRI: {
case ArchType::ConfRegType::FDRI: {
if (start_new_write) {
current_frame_address =
frame_address_register;
@ -134,10 +158,10 @@ absl::optional<Configuration> Configuration::InitWithPackets(
// to this register can be multiples of that to
// do auto-incrementing block writes.
for (size_t ii = 0; ii < packet.data().size();
ii += kWordsPerFrame) {
ii += ArchType::words_per_frame) {
frames[current_frame_address] =
packet.data().subspan(
ii, kWordsPerFrame);
ii, ArchType::words_per_frame);
auto next_address =
part.GetNextFrameAddress(
@ -157,7 +181,8 @@ absl::optional<Configuration> Configuration::InitWithPackets(
.is_bottom_half_rows() ||
next_address->row() !=
current_frame_address.row())) {
ii += 2 * kWordsPerFrame;
ii += 2 *
ArchType::words_per_frame;
}
current_frame_address = *next_address;
}
@ -171,8 +196,7 @@ absl::optional<Configuration> Configuration::InitWithPackets(
return Configuration(part, frames);
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_H_
#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_H_

View File

@ -0,0 +1,68 @@
#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H
#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H
#include <cstdint>
#include <ostream>
#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/xilinx/configuration_register.h>
namespace prjxray {
namespace xilinx {
// As described in the configuration user guide for Series-7
// (UG470, pg. 108) there are two types of configuration packets
enum ConfigurationPacketType { NONE, TYPE1, TYPE2 };
// Creates a Type1 or Type2 configuration packet.
// Specification of the packets for Series-7 can be found in UG470, pg. 108
// For Spartan6 UG380, pg. 98
template <typename ConfigRegType>
class ConfigurationPacket {
public:
typedef std::pair<absl::Span<uint32_t>,
absl::optional<ConfigurationPacket<ConfigRegType>>>
ParseResult;
// Opcodes as specified in UG470 page 108
enum Opcode {
NOP = 0,
Read = 1,
Write = 2,
/* reserved = 3 */
};
ConfigurationPacket(unsigned int header_type,
Opcode opcode,
ConfigRegType address,
const absl::Span<const uint32_t>& data)
: header_type_(header_type),
opcode_(opcode),
address_(address),
data_(std::move(data)) {}
unsigned int header_type() const { return header_type_; }
const Opcode opcode() const { return opcode_; }
const ConfigRegType address() const { return address_; }
const absl::Span<const uint32_t>& data() const { return data_; }
static ParseResult InitWithWords(
absl::Span<uint32_t> words,
const ConfigurationPacket<ConfigRegType>* previous_packet =
nullptr);
private:
unsigned int header_type_;
Opcode opcode_;
ConfigRegType address_;
absl::Span<const uint32_t> data_;
};
template <class ConfigRegType>
std::ostream& operator<<(std::ostream& o,
const ConfigurationPacket<ConfigRegType>& packet);
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H

View File

@ -0,0 +1,36 @@
#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#include <memory>
#include <absl/types/span.h>
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_register.h>
namespace prjxray {
namespace xilinx {
template <int Words, typename ConfigRegType>
class ConfigurationPacketWithPayload
: public ConfigurationPacket<ConfigRegType> {
public:
ConfigurationPacketWithPayload(
typename ConfigurationPacket<ConfigRegType>::Opcode op,
ConfigRegType reg,
const std::array<uint32_t, Words>& payload)
: ConfigurationPacket<ConfigRegType>(
ConfigurationPacketType::TYPE1,
op,
reg,
absl::Span<uint32_t>(payload_)),
payload_(std::move(payload)) {}
private:
std::array<uint32_t, Words> payload_;
};
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H

View File

@ -0,0 +1,72 @@
#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_
#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_
#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/xilinx/configuration.h>
namespace prjxray {
namespace xilinx {
template <typename ArchType>
class ConfigurationPacketizer {
public:
class iterator
: std::iterator<
std::input_iterator_tag,
ConfigurationPacket<typename ArchType::ConfRegType>> {
public:
iterator(
const typename ArchType::Part* part,
typename Configuration<ArchType>::FrameMap::const_iterator
begin,
typename Configuration<ArchType>::FrameMap::const_iterator
end);
iterator& operator++();
bool operator==(const iterator& other) const;
bool operator!=(const iterator& other) const;
const ConfigurationPacket<typename ArchType::ConfRegType>&
operator*() const;
const ConfigurationPacket<typename ArchType::ConfRegType>*
operator->() const;
private:
friend class ConfigurationPacketizer;
enum class State {
Start,
FrameAddressWritten,
FrameDataWritten,
ZeroPadWritten,
Finished,
};
const typename ArchType::Part* part_;
State state_;
typename Configuration<ArchType>::FrameMap::const_iterator
frame_cur_;
typename Configuration<ArchType>::FrameMap::const_iterator
frame_end_;
absl::optional<uint32_t> frame_address_;
absl::optional<
ConfigurationPacket<typename ArchType::ConfRegType>>
packet_;
int zero_pad_packets_to_write_;
};
ConfigurationPacketizer(const Configuration<ArchType>& config);
iterator begin() const;
iterator end() const;
private:
const Configuration<ArchType>& config_;
};
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_

View File

@ -1,13 +1,14 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_
#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_REGISTER_H_
#define PRJXRAY_LIB_XILINX_CONFIGURATION_REGISTER_H_
#include <ostream>
namespace prjxray {
namespace xilinx {
namespace xc7series {
enum class ConfigurationRegister : unsigned int {
// Series-7 configuration register addresses
// according to UG470, pg. 109
enum class Series7ConfigurationRegister : unsigned int {
CRC = 0x00,
FAR = 0x01,
FDRI = 0x02,
@ -31,10 +32,10 @@ enum class ConfigurationRegister : unsigned int {
BSPI = 0x1F,
};
std::ostream& operator<<(std::ostream& o, const ConfigurationRegister& value);
std::ostream& operator<<(std::ostream& o,
const Series7ConfigurationRegister& value);
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_REGISTER_H_
#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_REGISTER_H_

View File

@ -1,24 +1,23 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H
#ifndef PRJXRAY_LIB_XILINX_FRAMES_H
#define PRJXRAY_LIB_XILINX_FRAMES_H
#include <map>
#include <string>
#include <vector>
#include <absl/strings/str_split.h>
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/frame_address.h>
#include <prjxray/xilinx/xc7series/part.h>
#include <prjxray/xilinx/architectures.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
// Contains frame information which is used for the generation
// of the configuration package that is used in bitstream generation.
template <typename ArchType>
class Frames {
public:
typedef std::vector<uint32_t> FrameData;
typedef std::map<FrameAddress, FrameData> Frames2Data;
typedef std::map<typename ArchType::FrameAddress, FrameData>
Frames2Data;
// Reads the contents of the frames file and populates
// the Frames container.
@ -26,7 +25,8 @@ class Frames {
// Adds empty frames that are present in the tilegrid of a specific part
// but are missing in the current frames container.
void addMissingFrames(const absl::optional<Part>& part);
void addMissingFrames(
const absl::optional<typename ArchType::Part>& part);
// Returns the map with frame addresses and corresponding data
Frames2Data& getFrames();
@ -36,11 +36,9 @@ class Frames {
// Updates the ECC information in the frame.
void updateECC(FrameData& data);
uint32_t calculateECC(const FrameData& data);
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_FRAMES_H
#endif // PRJXRAY_LIB_XILINX_FRAMES_H

View File

@ -0,0 +1,24 @@
#ifndef PRJXRAY_LIB_XILINX_NOP_PACKET_H
#define PRJXRAY_LIB_XILINX_NOP_PACKET_H
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_register.h>
namespace prjxray {
namespace xilinx {
template <typename ConfigRegType>
class NopPacket : public ConfigurationPacket<ConfigRegType> {
public:
NopPacket()
: ConfigurationPacket<ConfigRegType>(
ConfigurationPacketType::TYPE1,
ConfigurationPacket<ConfigRegType>::Opcode::NOP,
ConfigRegType::CRC,
{}) {}
};
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_NOP_PACKET_H

View File

@ -1,93 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H
#include <algorithm>
#include <memory>
#include <vector>
#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/big_endian_span.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class BitstreamReader {
public:
using value_type = ConfigurationPacket;
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;
ConfigurationPacket::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);
// Construct a `BitstreamReader` from a Container of bytes.
// Any bytes preceding an initial sync word are ignored.
template <typename T>
static absl::optional<BitstreamReader> 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 T>
absl::optional<BitstreamReader> BitstreamReader::InitWithBytes(T bitstream) {
// If this is really a Xilinx 7-Series 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>();
}
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, big-endian words.
auto big_endian_reader = make_big_endian_span<uint32_t>(config_packets);
std::vector<uint32_t> words{big_endian_reader.begin(),
big_endian_reader.end()};
return BitstreamReader(std::move(words));
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H

View File

@ -2,8 +2,8 @@
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_register.h>
namespace prjxray {
namespace xilinx {

View File

@ -1,65 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H
#include <cstdint>
#include <absl/types/optional.h>
#include <absl/types/span.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class ConfigurationPacket {
public:
typedef std::pair<absl::Span<uint32_t>,
absl::optional<ConfigurationPacket>>
ParseResult;
enum Opcode {
NOP = 0,
Read = 1,
Write = 2,
/* reserved = 3 */
};
ConfigurationPacket(unsigned int header_type,
Opcode opcode,
ConfigurationRegister address,
const absl::Span<const uint32_t>& data)
: header_type_(header_type),
opcode_(opcode),
address_(address),
data_(std::move(data)) {}
// Attempt to read a configuration packet from a sequence of
// 32-bit, big-endian words. If successful, returns the packet read and
// a span containing any words remaining after the packet. If a valid
// header is found but there are insufficient words provided for the
// complete packet, the original span<> is returned unchanged and no
// packet is produced. If no valid header is found, an empty span is
// returned.
static ParseResult InitWithWords(
absl::Span<uint32_t> words,
const ConfigurationPacket* previous_packet = nullptr);
unsigned int header_type() const { return header_type_; }
const Opcode opcode() const { return opcode_; }
const ConfigurationRegister address() const { return address_; }
const absl::Span<const uint32_t>& data() const { return data_; }
private:
unsigned int header_type_;
Opcode opcode_;
ConfigurationRegister address_;
absl::Span<const uint32_t> data_;
};
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet);
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H

View File

@ -1,33 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#include <memory>
#include <absl/types/span.h>
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
template <int Words>
class ConfigurationPacketWithPayload : public ConfigurationPacket {
public:
ConfigurationPacketWithPayload(
Opcode op,
ConfigurationRegister reg,
const std::array<uint32_t, Words>& payload)
: ConfigurationPacket(1, op, reg, absl::Span<uint32_t>(payload_)),
payload_(std::move(payload)) {}
private:
std::array<uint32_t, Words> payload_;
}; // namespace xc7series
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H

View File

@ -1,62 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKETIZER_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKETIZER_H_
#include <absl/types/optional.h>
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class ConfigurationPacketizer {
public:
class iterator
: std::iterator<std::input_iterator_tag, ConfigurationPacket> {
public:
iterator(const Part* part,
Configuration::FrameMap::const_iterator begin,
Configuration::FrameMap::const_iterator end);
iterator& operator++();
bool operator==(const iterator& other) const;
bool operator!=(const iterator& other) const;
const ConfigurationPacket& operator*() const;
const ConfigurationPacket* operator->() const;
private:
friend class ConfigurationPacketizer;
enum class State {
Start,
FrameAddressWritten,
FrameDataWritten,
ZeroPadWritten,
Finished,
};
const Part* part_;
State state_;
Configuration::FrameMap::const_iterator frame_cur_;
Configuration::FrameMap::const_iterator frame_end_;
absl::optional<uint32_t> frame_address_;
absl::optional<ConfigurationPacket> packet_;
int zero_pad_packets_to_write_;
};
ConfigurationPacketizer(const Configuration& config);
iterator begin() const;
iterator end() const;
private:
const Configuration& config_;
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKETIZER_H_

View File

@ -7,8 +7,8 @@
#include <memory>
#include <absl/types/optional.h>
#include <prjxray/xilinx/xc7series/configuration_row.h>
#include <prjxray/xilinx/xc7series/frame_address.h>
#include <prjxray/xilinx/xc7series/row.h>
#include <yaml-cpp/yaml.h>
namespace prjxray {

View File

@ -1,24 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class NopPacket : public ConfigurationPacket {
public:
NopPacket()
: ConfigurationPacket(1,
Opcode::NOP,
ConfigurationRegister::CRC,
{}) {}
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H

View File

@ -1,51 +0,0 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/frames.h>
#include <prjxray/xilinx/xc7series/part.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
using PacketData = std::vector<uint32_t>;
using BitstreamHeader = std::vector<uint8_t>;
using ConfigurationPackage = std::vector<std::unique_ptr<ConfigurationPacket>>;
// Returns the payload for a type 2 packet.
// Type 2 packets can have the payload length of more than the 11 bits available
// for type 1 packets.
PacketData createType2ConfigurationPacketData(const Frames::Frames2Data& frames,
absl::optional<Part>& part);
// Creates the complete configuration package that is
// then used by the bitstream writer to generate the bitstream file. The package
// forms a sequence suitable for xilinx 7-series devices. The programming
// sequence is taken from
// https://www.kc8apf.net/2018/05/unpacking-xilinx-7-series-bitstreams-part-2/
void createConfigurationPackage(ConfigurationPackage& out_packets,
const PacketData& packet_data,
absl::optional<Part>& part);
// Creates a Xilinx bit header which is mostly a
// Tag-Length-Value(TLV) format documented here:
// http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm
BitstreamHeader createBitistreamHeader(const std::string& part_name,
const std::string& frames_file_name,
const std::string& generator_name);
// Writies out the complete bitstream for a 7-series
// Xilinx FPGA based on the Configuration Package which holds the complete
// programming sequence.
int writeBitstream(const ConfigurationPackage& packets,
const std::string& part_name,
const std::string& frames_file,
const std::string& generator_name,
const std::string& output_file);
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_

View File

@ -0,0 +1,350 @@
#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>
namespace prjxray {
namespace xilinx {
// Per UG470 pg 80: Bus Width Auto Detection
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;
ret = bit_field_set(ret, 31, 29, packet.header_type());
switch (packet.header_type()) {
case NONE:
// Bitstreams are 0 padded sometimes, essentially making
// a type 0 frame Ignore the other fields for now
break;
case TYPE1: {
// Table 5-20: Type 1 Packet Header Format
ret = bit_field_set(ret, 28, 27, packet.opcode());
ret = bit_field_set(ret, 26, 13, packet.address());
ret = bit_field_set(ret, 10, 0, packet.data().length());
break;
}
case TYPE2: {
// Table 5-22: Type 2 Packet Header
// Note address is from previous type 1 header
ret = bit_field_set(ret, 28, 27, packet.opcode());
ret = bit_field_set(ret, 26, 0, packet.data().length());
break;
}
default:
break;
}
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

217
lib/xilinx/configuration.cc Normal file
View File

@ -0,0 +1,217 @@
#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/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_writer.h>
#include <prjxray/xilinx/configuration.h>
#include <prjxray/xilinx/configuration_packet.h>
#include <prjxray/xilinx/configuration_packet_with_payload.h>
#include <prjxray/xilinx/nop_packet.h>
#include <prjxray/xilinx/xc7series/command.h>
#include <prjxray/xilinx/xc7series/configuration_options_0_value.h>
namespace prjxray {
namespace xilinx {
template <>
Configuration<Series7>::PacketData
Configuration<Series7>::createType2ConfigurationPacketData(
const Frames<Series7>::Frames2Data& frames,
absl::optional<Series7::Part>& part) {
PacketData packet_data;
for (auto& frame : frames) {
std::copy(frame.second.begin(), frame.second.end(),
std::back_inserter(packet_data));
auto next_address = part->GetNextFrameAddress(frame.first);
if (next_address &&
(next_address->block_type() != frame.first.block_type() ||
next_address->is_bottom_half_rows() !=
frame.first.is_bottom_half_rows() ||
next_address->row() != frame.first.row())) {
packet_data.insert(packet_data.end(), 202, 0);
}
}
packet_data.insert(packet_data.end(), 202, 0);
return packet_data;
}
template <>
void Configuration<Series7>::createConfigurationPackage(
Series7::ConfigurationPackage& out_packets,
const PacketData& packet_data,
absl::optional<Series7::Part>& part) {
using ArchType = Series7;
using ConfigurationRegister = ArchType::ConfRegType;
// Initialization sequence
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::TIMER, {0x0}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::WBSTAR, {0x0}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::NOP)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::UNKNOWN, {0x0}));
// Configuration Options 0
out_packets.emplace_back(new ConfigurationPacketWithPayload<
1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::COR0,
{xc7series::ConfigurationOptions0Value()
.SetAddPipelineStageForDoneIn(true)
.SetReleaseDonePinAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase4)
.SetStallAtStartupCycleUntilDciMatch(
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
.SetStallAtStartupCycleUntilMmcmLock(
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
.SetReleaseGtsSignalAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase5)
.SetReleaseGweSignalAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase6)}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::COR1, {0x0}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::IDCODE, {part->idcode()}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::SWITCH)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::MASK, {0x401}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CTL0, {0x501}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::MASK, {0x0}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CTL1, {0x0}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::FAR, {0x0}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::WCFG)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
// Frame data write
out_packets.emplace_back(new ConfigurationPacket<ConfigurationRegister>(
TYPE1, ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::FDRI, {}));
out_packets.emplace_back(new ConfigurationPacket<ConfigurationRegister>(
TYPE2, ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::FDRI, packet_data));
// Finalization sequence
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::GRESTORE)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::LFRM)}));
for (int ii = 0; ii < 100; ++ii) {
out_packets.emplace_back(
new NopPacket<ConfigurationRegister>());
}
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::START)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::FAR, {0x3be0000}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::MASK, {0x501}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CTL0, {0x501}));
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(new NopPacket<ConfigurationRegister>());
out_packets.emplace_back(
new ConfigurationPacketWithPayload<1, ConfigurationRegister>(
ConfigurationPacket<ConfigurationRegister>::Opcode::Write,
ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::DESYNC)}));
for (int ii = 0; ii < 400; ++ii) {
out_packets.emplace_back(
new NopPacket<ConfigurationRegister>());
}
}
} // namespace xilinx
} // namespace prjxray

View File

@ -1,24 +1,28 @@
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/configuration_packet.h>
#include <iomanip>
#include <iostream>
#include <ostream>
#include <prjxray/bit_ops.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
std::pair<absl::Span<uint32_t>, absl::optional<ConfigurationPacket>>
ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
const ConfigurationPacket* previous_packet) {
template <>
std::pair<absl::Span<uint32_t>,
absl::optional<ConfigurationPacket<Series7ConfigurationRegister>>>
ConfigurationPacket<Series7ConfigurationRegister>::InitWithWords(
absl::Span<uint32_t> words,
const ConfigurationPacket<Series7ConfigurationRegister>* previous_packet) {
using ConfigurationRegister = Series7ConfigurationRegister;
// Need at least one 32-bit word to have a valid packet header.
if (words.size() < 1)
return {words, {}};
uint32_t header_type = bit_field_get(words[0], 31, 29);
switch (header_type) {
case 0x0:
case NONE:
// Type 0 is emitted at the end of a configuration row
// when BITSTREAM.GENERAL.DEBUGBITSTREAM is set to YES.
// These seem to be padding that are interepreted as
@ -30,7 +34,7 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
Opcode::NOP,
ConfigurationRegister::CRC,
{}}}};
case 0x1: {
case TYPE1: {
Opcode opcode = static_cast<Opcode>(
bit_field_get(words[0], 28, 27));
ConfigurationRegister address =
@ -49,7 +53,7 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
{{header_type, opcode, address,
words.subspan(1, data_word_count)}}};
}
case 0x2: {
case TYPE2: {
absl::optional<ConfigurationPacket> packet;
Opcode opcode = static_cast<Opcode>(
bit_field_get(words[0], 28, 27));
@ -76,16 +80,18 @@ ConfigurationPacket::InitWithWords(absl::Span<uint32_t> words,
}
}
std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet) {
template <class ConfigRegType>
std::ostream& operator<<(std::ostream& o,
const ConfigurationPacket<ConfigRegType>& packet) {
if (packet.header_type() == 0x0) {
return o << "[Zero-pad]" << std::endl;
}
switch (packet.opcode()) {
case ConfigurationPacket::Opcode::NOP:
case ConfigurationPacket<ConfigRegType>::Opcode::NOP:
o << "[NOP]" << std::endl;
break;
case ConfigurationPacket::Opcode::Read:
case ConfigurationPacket<ConfigRegType>::Opcode::Read:
o << "[Read Type=";
o << packet.header_type();
o << " Address=";
@ -96,7 +102,7 @@ std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet) {
o << " Reg=\"" << packet.address() << "\"";
o << "]" << std::endl;
break;
case ConfigurationPacket::Opcode::Write:
case ConfigurationPacket<ConfigRegType>::Opcode::Write:
o << "[Write Type=";
o << packet.header_type();
o << " Address=";
@ -127,6 +133,8 @@ std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet) {
return o;
}
} // namespace xc7series
template std::ostream& operator<<(
std::ostream&,
const ConfigurationPacket<Series7ConfigurationRegister>&);
} // namespace xilinx
} // namespace prjxray

View File

@ -0,0 +1,162 @@
#include <absl/types/span.h>
#include <prjxray/xilinx/configuration.h>
#include <prjxray/xilinx/configuration_packetizer.h>
namespace prjxray {
namespace xilinx {
template <typename ArchType>
ConfigurationPacketizer<ArchType>::ConfigurationPacketizer(
const Configuration<ArchType>& config)
: config_(config) {}
template <typename ArchType>
typename ConfigurationPacketizer<ArchType>::iterator
ConfigurationPacketizer<ArchType>::begin() const {
return iterator(&config_.part(), config_.frames().begin(),
config_.frames().end());
}
template <typename ArchType>
typename ConfigurationPacketizer<ArchType>::iterator
ConfigurationPacketizer<ArchType>::end() const {
return iterator(&config_.part(), config_.frames().end(),
config_.frames().end());
}
template <typename ArchType>
ConfigurationPacketizer<ArchType>::iterator::iterator(
const typename ArchType::Part* part,
typename Configuration<ArchType>::FrameMap::const_iterator begin,
typename Configuration<ArchType>::FrameMap::const_iterator end)
: part_(part),
state_(begin != end ? State::Start : State::Finished),
frame_cur_(begin),
frame_end_(end) {
this->operator++();
}
template <typename ArchType>
const ConfigurationPacket<typename ArchType::ConfRegType>&
ConfigurationPacketizer<ArchType>::iterator::operator*() const {
return *packet_;
}
template <typename ArchType>
const ConfigurationPacket<typename ArchType::ConfRegType>*
ConfigurationPacketizer<ArchType>::iterator::operator->() const {
return &(*packet_);
}
template <typename ArchType>
bool ConfigurationPacketizer<ArchType>::iterator::operator==(
const ConfigurationPacketizer<ArchType>::iterator& other) const {
return state_ == other.state_ && frame_cur_ == other.frame_cur_;
}
template <typename ArchType>
bool ConfigurationPacketizer<ArchType>::iterator::operator!=(
const ConfigurationPacketizer<ArchType>::iterator& other) const {
return !(*this == other);
}
template <>
typename ConfigurationPacketizer<Series7>::iterator&
ConfigurationPacketizer<Series7>::iterator::operator++() {
using ArchType = Series7;
// Frames are accessed via an indirect addressing scheme using the FAR
// and FDRI registers. Writes begin with writing the target frame
// address to FAR and then the frame data is written to FDRI. The
// following state machine primarily follows that flow:
// Start -> FrameAddressWritten -> FrameDataWritten -> Start....
// When the last frame within a row is written, 2 full frames (202
// words) of zero padding need to be written after the frame data.
switch (state_) {
case State::FrameDataWritten: {
// If this is the last address in this row (i.e. the
// next valid address known by the part is in a
// different row, half, or bus type), start a zero fill.
// Otherwise, increment the frame iterator and fall
// through to Start.
auto& this_address = frame_cur_->first;
auto next_address =
part_->GetNextFrameAddress(frame_cur_->first);
if (next_address &&
(next_address->block_type() !=
this_address.block_type() ||
next_address->is_bottom_half_rows() !=
this_address.is_bottom_half_rows() ||
next_address->row() != this_address.row())) {
zero_pad_packets_to_write_ = 202;
// Type 0 frames aren't documented in UG470. In
// practice, they are used to zero pad in the
// bitstream.
packet_ = ConfigurationPacket<
typename ArchType::ConfRegType>(
0,
ConfigurationPacket<
typename ArchType::ConfRegType>::
Opcode::NOP,
ArchType::ConfRegType::CRC, {});
state_ = State::ZeroPadWritten;
break;
}
++frame_cur_;
}
case State::Start:
if (frame_cur_ == frame_end_) {
state_ = State::Finished;
frame_address_.reset();
packet_.reset();
return *this;
}
frame_address_ = frame_cur_->first;
packet_ = ConfigurationPacket<
typename ArchType::ConfRegType>(
1,
ConfigurationPacket<
typename ArchType::ConfRegType>::Opcode::Write,
ArchType::ConfRegType::FAR,
absl::Span<uint32_t>(&frame_address_.value(), 1));
state_ = State::FrameAddressWritten;
break;
case State::FrameAddressWritten:
packet_ = ConfigurationPacket<
typename ArchType::ConfRegType>(
1,
ConfigurationPacket<
typename ArchType::ConfRegType>::Opcode::Write,
ArchType::ConfRegType::FDRI, frame_cur_->second);
state_ = State::FrameDataWritten;
break;
case State::ZeroPadWritten:
if (--zero_pad_packets_to_write_ == 1) {
++frame_cur_;
state_ = State::Start;
}
break;
case State::Finished:
break;
}
return *this;
}
template ConfigurationPacketizer<Series7>::ConfigurationPacketizer(
const Configuration<Series7>& config);
template ConfigurationPacketizer<Series7>::iterator
ConfigurationPacketizer<Series7>::begin() const;
template ConfigurationPacketizer<Series7>::iterator
ConfigurationPacketizer<Series7>::end() const;
template const ConfigurationPacket<typename Series7::ConfRegType>&
ConfigurationPacketizer<Series7>::iterator::operator*() const;
template const ConfigurationPacket<typename Series7::ConfRegType>*
ConfigurationPacketizer<Series7>::iterator::operator->() const;
template bool ConfigurationPacketizer<Series7>::iterator::operator==(
const ConfigurationPacketizer<Series7>::iterator& other) const;
template bool ConfigurationPacketizer<Series7>::iterator::operator!=(
const ConfigurationPacketizer<Series7>::iterator& other) const;
} // namespace xilinx
} // namespace prjxray

View File

@ -0,0 +1,55 @@
#include <prjxray/xilinx/configuration_register.h>
namespace prjxray {
namespace xilinx {
std::ostream& operator<<(std::ostream& o,
const Series7ConfigurationRegister& value) {
switch (value) {
case Series7ConfigurationRegister::CRC:
return o << "CRC";
case Series7ConfigurationRegister::FAR:
return o << "Frame Address";
case Series7ConfigurationRegister::FDRI:
return o << "Frame Data Input";
case Series7ConfigurationRegister::FDRO:
return o << "Frame Data Output";
case Series7ConfigurationRegister::CMD:
return o << "Command";
case Series7ConfigurationRegister::CTL0:
return o << "Control 0";
case Series7ConfigurationRegister::MASK:
return o << "Mask for CTL0 and CTL1";
case Series7ConfigurationRegister::STAT:
return o << "Status";
case Series7ConfigurationRegister::LOUT:
return o << "Legacy Output";
case Series7ConfigurationRegister::COR0:
return o << "Configuration Option 0";
case Series7ConfigurationRegister::MFWR:
return o << "Multiple Frame Write";
case Series7ConfigurationRegister::CBC:
return o << "Initial CBC Value";
case Series7ConfigurationRegister::IDCODE:
return o << "Device ID";
case Series7ConfigurationRegister::AXSS:
return o << "User Access";
case Series7ConfigurationRegister::COR1:
return o << "Configuration Option 1";
case Series7ConfigurationRegister::WBSTAR:
return o << "Warm Boot Start Address";
case Series7ConfigurationRegister::TIMER:
return o << "Watchdog Timer";
case Series7ConfigurationRegister::BOOTSTS:
return o << "Boot History Status";
case Series7ConfigurationRegister::CTL1:
return o << "Control 1";
case Series7ConfigurationRegister::BSPI:
return o << "BPI/SPI Configuration Options";
default:
return o << "Unknown";
}
}
} // namespace xilinx
} // namespace prjxray

View File

@ -1,18 +1,21 @@
#include <fstream>
#include <iostream>
#include <absl/strings/str_split.h>
#include <prjxray/xilinx/frames.h>
#include <prjxray/xilinx/xc7series/ecc.h>
#include <prjxray/xilinx/xc7series/frames.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
Frames::Frames2Data& Frames::getFrames() {
template <typename ArchType>
typename Frames<ArchType>::Frames2Data& Frames<ArchType>::getFrames() {
return frames_data_;
}
int Frames::readFrames(const std::string& frm_file_str) {
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);
@ -35,65 +38,76 @@ int Frames::readFrames(const std::string& frm_file_str) {
std::vector<std::string> frame_data_strings =
absl::StrSplit(frame_delta.second, ',');
if (frame_data_strings.size() != 101) {
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 101";
<< " words instead of "
<< ArchType::words_per_frame << std::endl;
continue;
}
FrameData frame_data(101, 0);
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);
});
// TODO make sure if this is needed
updateECC(frame_data);
// Insert the frame address and corresponding frame data to the
// map
FrameAddress frm_addr(frame_address);
typename ArchType::FrameAddress frm_addr(frame_address);
frames_data_.insert(
std::pair<FrameAddress, FrameData>(frm_addr, frame_data));
std::pair<typename ArchType::FrameAddress, FrameData>(
frm_addr, frame_data));
}
return 0;
}
void Frames::addMissingFrames(const absl::optional<Part>& part) {
template <typename ArchType>
void Frames<ArchType>::addMissingFrames(
const absl::optional<typename ArchType::Part>& part) {
auto current_frame_address =
absl::optional<FrameAddress>(FrameAddress(0));
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(101, 0);
// TODO make sure if this is needed
updateECC(frame_data);
frames_data_.insert(std::pair<FrameAddress, FrameData>(
*current_frame_address, frame_data));
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);
}
void Frames::updateECC(FrameData& data) {
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);
}
uint32_t Frames::calculateECC(const FrameData& data) {
uint32_t ecc = 0;
for (size_t ii = 0; ii < data.size(); ++ii) {
ecc = icap_ecc(ii, data[ii], ecc);
}
return ecc;
}
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 xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,71 +0,0 @@
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
std::array<uint8_t, 4> BitstreamReader::kSyncWord{0xAA, 0x99, 0x55, 0x66};
BitstreamReader::BitstreamReader(std::vector<uint32_t>&& words)
: words_(std::move(words)) {}
BitstreamReader::iterator BitstreamReader::begin() {
return iterator(absl::MakeSpan(words_));
}
BitstreamReader::iterator BitstreamReader::end() {
return iterator({});
}
BitstreamReader::iterator::iterator(absl::Span<uint32_t> words) {
parse_result_.first = words;
parse_result_.second = {};
++(*this);
}
BitstreamReader::iterator& BitstreamReader::iterator::operator++() {
do {
auto new_result = ConfigurationPacket::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;
}
bool BitstreamReader::iterator::operator==(const iterator& other) const {
return words_ == other.words_;
}
bool BitstreamReader::iterator::operator!=(const iterator& other) const {
return !(*this == other);
}
const BitstreamReader::value_type& BitstreamReader::iterator::operator*()
const {
return *(parse_result_.second);
}
const BitstreamReader::value_type* BitstreamReader::iterator::operator->()
const {
return parse_result_.second.operator->();
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,225 +0,0 @@
/*
* TODO
* -Finish type 1/2 support
* -Review sample bitstream padding. What are they for?
*/
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
#include <prjxray/bit_ops.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
// Per UG470 pg 80: Bus Width Auto Detection
std::array<uint32_t, 6> BitstreamWriter::header_{
0xFFFFFFFF, 0x000000BB, 0x11220044, 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566};
/**************************************************
* BitstreamWriter::BitstreamWriter
*************************************************/
BitstreamWriter::BitstreamWriter(const packets_t& packets)
: packets_(packets) {}
/**************************************************
*
*************************************************/
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
// itr_packets = packets.begin();
const ConfigurationPacket& packet = **itr_packets_;
return BitstreamWriter::packet_iterator(
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
packet.data().begin());
}
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_end() {
const ConfigurationPacket& packet = **itr_packets_;
return BitstreamWriter::packet_iterator(
&packet, BitstreamWriter::packet_iterator::STATE_END,
// Essentially ignored
packet.data().end());
}
BitstreamWriter::packet_iterator::packet_iterator(
const ConfigurationPacket* packet,
state_t state,
data_iterator_t itr_data)
: state_(state), itr_data_(itr_data), packet_(packet) {}
BitstreamWriter::packet_iterator& BitstreamWriter::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;
}
bool BitstreamWriter::packet_iterator::operator==(
const packet_iterator& other) const {
return state_ == other.state_ && itr_data_ == other.itr_data_;
}
bool BitstreamWriter::packet_iterator::operator!=(
const packet_iterator& other) const {
return !(*this == other);
}
uint32_t packet2header(const ConfigurationPacket& packet) {
uint32_t ret = 0;
ret = bit_field_set(ret, 31, 29, packet.header_type());
switch (packet.header_type()) {
case 0x0:
// Bitstreams are 0 padded sometimes, essentially making
// a type 0 frame Ignore the other fields for now
break;
case 0x1: {
// Table 5-20: Type 1 Packet Header Format
ret = bit_field_set(ret, 28, 27, packet.opcode());
ret = bit_field_set(ret, 26, 13, packet.address());
ret = bit_field_set(ret, 10, 0, packet.data().length());
break;
}
case 0x2: {
// Table 5-22: Type 2 Packet Header
// Note address is from previous type 1 header
ret = bit_field_set(ret, 28, 27, packet.opcode());
ret = bit_field_set(ret, 26, 0, packet.data().length());
break;
}
default:
break;
}
return ret;
}
const BitstreamWriter::itr_value_type BitstreamWriter::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?
}
const BitstreamWriter::itr_value_type BitstreamWriter::packet_iterator::
operator->() const {
return *(*this);
}
/**************************************************
* BitstreamWriter::iterator
*************************************************/
BitstreamWriter::iterator BitstreamWriter::begin() {
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& 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);
}
BitstreamWriter::iterator BitstreamWriter::end() {
return iterator(header_.end(), packets_, packets_.end(),
absl::optional<packet_iterator>());
}
BitstreamWriter::iterator::iterator(header_t::iterator itr_header,
const packets_t& packets,
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) {}
BitstreamWriter::iterator& BitstreamWriter::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;
}
bool BitstreamWriter::iterator::operator==(const iterator& other) const {
return itr_header_ == other.itr_header_ &&
itr_packets_ == other.itr_packets_ &&
op_itr_packet_ == other.op_itr_packet_;
}
bool BitstreamWriter::iterator::operator!=(const iterator& other) const {
return !(*this == other);
}
const BitstreamWriter::itr_value_type BitstreamWriter::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_);
}
}
const BitstreamWriter::itr_value_type BitstreamWriter::iterator::operator->()
const {
return *(*this);
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,128 +0,0 @@
#include <prjxray/xilinx/xc7series/configuration_packetizer.h>
#include <absl/types/span.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
ConfigurationPacketizer::ConfigurationPacketizer(const Configuration& config)
: config_(config) {}
ConfigurationPacketizer::iterator ConfigurationPacketizer::begin() const {
return iterator(&config_.part(), config_.frames().begin(),
config_.frames().end());
}
ConfigurationPacketizer::iterator ConfigurationPacketizer::end() const {
return iterator(&config_.part(), config_.frames().end(),
config_.frames().end());
}
ConfigurationPacketizer::iterator::iterator(
const Part* part,
Configuration::FrameMap::const_iterator begin,
Configuration::FrameMap::const_iterator end)
: part_(part),
state_(begin != end ? State::Start : State::Finished),
frame_cur_(begin),
frame_end_(end) {
this->operator++();
}
const ConfigurationPacket& ConfigurationPacketizer::iterator::operator*()
const {
return *packet_;
}
const ConfigurationPacket* ConfigurationPacketizer::iterator::operator->()
const {
return &(*packet_);
}
bool ConfigurationPacketizer::iterator::operator==(
const ConfigurationPacketizer::iterator& other) const {
return state_ == other.state_ && frame_cur_ == other.frame_cur_;
}
bool ConfigurationPacketizer::iterator::operator!=(
const ConfigurationPacketizer::iterator& other) const {
return !(*this == other);
}
ConfigurationPacketizer::iterator& ConfigurationPacketizer::iterator::
operator++() {
// Frames are accessed via an indirect addressing scheme using the FAR
// and FDRI registers. Writes begin with writing the target frame
// address to FAR and then the frame data is written to FDRI. The
// following state machine primarily follows that flow:
// Start -> FrameAddressWritten -> FrameDataWritten -> Start....
// When the last frame within a row is written, 2 full frames (202
// words) of zero padding need to be written after the frame data.
switch (state_) {
case State::FrameDataWritten: {
// If this is the last address in this row (i.e. the
// next valid address known by the part is in a
// different row, half, or bus type), start a zero fill.
// Otherwise, increment the frame iterator and fall
// through to Start.
auto& this_address = frame_cur_->first;
auto next_address =
part_->GetNextFrameAddress(frame_cur_->first);
if (next_address &&
(next_address->block_type() !=
this_address.block_type() ||
next_address->is_bottom_half_rows() !=
this_address.is_bottom_half_rows() ||
next_address->row() != this_address.row())) {
zero_pad_packets_to_write_ = 202;
// Type 0 frames aren't documented in UG470. In
// practice, they are used to zero pad in the
// bitstream.
packet_ = ConfigurationPacket(
0, ConfigurationPacket::Opcode::NOP,
ConfigurationRegister::CRC, {});
state_ = State::ZeroPadWritten;
break;
}
++frame_cur_;
}
case State::Start:
if (frame_cur_ == frame_end_) {
state_ = State::Finished;
frame_address_.reset();
packet_.reset();
return *this;
}
frame_address_ = frame_cur_->first;
packet_ = ConfigurationPacket(
1, ConfigurationPacket::Opcode::Write,
ConfigurationRegister::FAR,
absl::Span<uint32_t>(&frame_address_.value(), 1));
state_ = State::FrameAddressWritten;
break;
case State::FrameAddressWritten:
packet_ = ConfigurationPacket(
1, ConfigurationPacket::Opcode::Write,
ConfigurationRegister::FDRI, frame_cur_->second);
state_ = State::FrameDataWritten;
break;
case State::ZeroPadWritten:
if (--zero_pad_packets_to_write_ == 1) {
++frame_cur_;
state_ = State::Start;
}
break;
case State::Finished:
break;
}
return *this;
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,56 +0,0 @@
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
std::ostream& operator<<(std::ostream& o, const ConfigurationRegister& value) {
switch (value) {
case ConfigurationRegister::CRC:
return o << "CRC";
case ConfigurationRegister::FAR:
return o << "Frame Address";
case ConfigurationRegister::FDRI:
return o << "Frame Data Input";
case ConfigurationRegister::FDRO:
return o << "Frame Data Output";
case ConfigurationRegister::CMD:
return o << "Command";
case ConfigurationRegister::CTL0:
return o << "Control 0";
case ConfigurationRegister::MASK:
return o << "Mask for CTL0 and CTL1";
case ConfigurationRegister::STAT:
return o << "Status";
case ConfigurationRegister::LOUT:
return o << "Legacy Output";
case ConfigurationRegister::COR0:
return o << "Configuration Option 0";
case ConfigurationRegister::MFWR:
return o << "Multiple Frame Write";
case ConfigurationRegister::CBC:
return o << "Initial CBC Value";
case ConfigurationRegister::IDCODE:
return o << "Device ID";
case ConfigurationRegister::AXSS:
return o << "User Access";
case ConfigurationRegister::COR1:
return o << "Configuration Option 1";
case ConfigurationRegister::WBSTAR:
return o << "Warm Boot Start Address";
case ConfigurationRegister::TIMER:
return o << "Watchdog Timer";
case ConfigurationRegister::BOOTSTS:
return o << "Boot History Status";
case ConfigurationRegister::CTL1:
return o << "Control 1";
case ConfigurationRegister::BSPI:
return o << "BPI/SPI Configuration Options";
default:
return o << "Unknown";
}
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -1,4 +1,4 @@
#include <prjxray/xilinx/xc7series/row.h>
#include <prjxray/xilinx/xc7series/configuration_row.h>
namespace prjxray {
namespace xilinx {

View File

@ -1,4 +1,4 @@
#include <prjxray/xilinx/xc7series/row.h>
#include <prjxray/xilinx/xc7series/configuration_row.h>
#include <gtest/gtest.h>

View File

@ -1,263 +0,0 @@
#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 <gflags/gflags.h>
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
#include <prjxray/xilinx/xc7series/command.h>
#include <prjxray/xilinx/xc7series/configuration_options_0_value.h>
#include <prjxray/xilinx/xc7series/configuration_packet_with_payload.h>
#include <prjxray/xilinx/xc7series/nop_packet.h>
#include <prjxray/xilinx/xc7series/utils.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
PacketData createType2ConfigurationPacketData(const Frames::Frames2Data& frames,
absl::optional<Part>& part) {
// Generate a single type 2 packet that writes everything at once.
PacketData packet_data;
for (auto& frame : frames) {
std::copy(frame.second.begin(), frame.second.end(),
std::back_inserter(packet_data));
auto next_address = part->GetNextFrameAddress(frame.first);
if (next_address &&
(next_address->block_type() != frame.first.block_type() ||
next_address->is_bottom_half_rows() !=
frame.first.is_bottom_half_rows() ||
next_address->row() != frame.first.row())) {
packet_data.insert(packet_data.end(), 202, 0);
}
}
packet_data.insert(packet_data.end(), 202, 0);
return packet_data;
}
void createConfigurationPackage(ConfigurationPackage& out_packets,
const PacketData& packet_data,
absl::optional<Part>& part) {
// Initialization sequence
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::TIMER,
{0x0}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::WBSTAR,
{0x0}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::NOP)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::RCRC)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::UNKNOWN,
{0x0}));
// Configuration Options 0
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::COR0,
{ConfigurationOptions0Value()
.SetAddPipelineStageForDoneIn(true)
.SetReleaseDonePinAtStartupCycle(
ConfigurationOptions0Value::SignalReleaseCycle::Phase4)
.SetStallAtStartupCycleUntilDciMatch(
ConfigurationOptions0Value::StallCycle::NoWait)
.SetStallAtStartupCycleUntilMmcmLock(
ConfigurationOptions0Value::StallCycle::NoWait)
.SetReleaseGtsSignalAtStartupCycle(
ConfigurationOptions0Value::SignalReleaseCycle::Phase5)
.SetReleaseGweSignalAtStartupCycle(
ConfigurationOptions0Value::SignalReleaseCycle::Phase6)}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::COR1,
{0x0}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::IDCODE,
{part->idcode()}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::SWITCH)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK,
{0x401}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL0,
{0x501}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK,
{0x0}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL1,
{0x0}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::FAR,
{0x0}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::WCFG)}));
out_packets.emplace_back(new NopPacket());
// Frame data write
out_packets.emplace_back(
new ConfigurationPacket(1, ConfigurationPacket::Opcode::Write,
ConfigurationRegister::FDRI, {}));
out_packets.emplace_back(
new ConfigurationPacket(2, ConfigurationPacket::Opcode::Write,
ConfigurationRegister::FDRI, packet_data));
// Finalization sequence
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::RCRC)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::GRESTORE)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::LFRM)}));
for (int ii = 0; ii < 100; ++ii) {
out_packets.emplace_back(new NopPacket());
}
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::START)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::FAR,
{0x3be0000}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::MASK,
{0x501}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CTL0,
{0x501}));
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::RCRC)}));
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new NopPacket());
out_packets.emplace_back(new ConfigurationPacketWithPayload<1>(
ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD,
{static_cast<uint32_t>(Command::DESYNC)}));
for (int ii = 0; ii < 400; ++ii) {
out_packets.emplace_back(new NopPacket());
}
}
BitstreamHeader createBitstreamHeader(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;
}
int writeBitstream(const 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(
createBitstreamHeader(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 out_bitstream_writer(packets);
for (uint32_t word : out_bitstream_writer) {
out_file.put((word >> 24) & 0xFF);
out_file.put((word >> 16) & 0xFF);
out_file.put((word >> 8) & 0xFF);
out_file.put((word)&0xFF);
}
uint32_t length_of_data = out_file.tellp() - end_of_header_pos;
out_file.seekp(header_data_length_pos);
out_file.put((length_of_data >> 24) & 0xFF);
out_file.put((length_of_data >> 16) & 0xFF);
out_file.put((length_of_data >> 8) & 0xFF);
out_file.put((length_of_data)&0xFF);
return 0;
}
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray

View File

@ -25,6 +25,7 @@ target_link_libraries(xc7patch
gflags
libprjxray
)
add_executable(xc7frames2bit xc7frames2bit.cc)
target_link_libraries(xc7frames2bit
absl::strings

View File

@ -10,12 +10,11 @@
#include <absl/strings/numbers.h>
#include <absl/strings/str_cat.h>
#include <absl/strings/str_split.h>
#include <absl/types/optional.h>
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/part.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
#include <prjxray/xilinx/configuration.h>
DEFINE_bool(c, false, "output '*' for repeating patterns");
DEFINE_bool(C, false, "do not ignore the checksum in each frame");
@ -42,26 +41,225 @@ DEFINE_bool(x,
" - decoded minor address from frame id\n");
DEFINE_bool(y, false, "use format 'bit_%%08x_%%03d_%%02d'");
DEFINE_bool(z, false, "skip zero frames (frames with all bits cleared) in o");
DEFINE_string(part_file, "", "YAML file describing a Xilinx 7-Series part");
DEFINE_string(part_file, "", "YAML file describing a Xilinx part");
DEFINE_string(architecture,
"Series7",
"Architecture of the provided bitstream");
namespace xc7series = prjxray::xilinx::xc7series;
namespace xilinx = prjxray::xilinx;
std::set<uint32_t> frames;
uint32_t frame_range_begin = 0, frame_range_end = 0;
std::vector<uint32_t> zero_frame(101);
struct BitReader {
BitReader(const std::vector<uint8_t>& bytes) : bytes_(bytes) {}
const std::vector<uint8_t>& bytes_;
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto reader =
xilinx::BitstreamReader<ArchType>::InitWithBytes(bytes_);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream"
<< std::endl;
return 1;
}
std::cout << "Config size: " << reader->words().size()
<< " words" << std::endl;
auto part = ArchType::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file not found or invalid"
<< std::endl;
return 1;
}
auto config = xilinx::Configuration<ArchType>::InitWithPackets(
*part, *reader);
if (!config) {
std::cerr
<< "Bitstream does not appear to be for this part"
<< std::endl;
return 1;
}
std::cout << "Number of configuration frames: "
<< config->frames().size() << std::endl;
FILE* f = stdout;
if (!FLAGS_o.empty()) {
f = fopen(FLAGS_o.c_str(), "w");
if (f == nullptr) {
printf(
"Can't open output file '%s' for "
"writing!\n",
FLAGS_o.c_str());
return 1;
}
} else {
fprintf(f, "\n");
}
std::vector<std::vector<bool>> pgmdata;
std::vector<int> pgmsep;
int word_length = sizeof(typename ArchType::WordType) * 8;
for (auto& it : config->frames()) {
if (FLAGS_z && it.second == zero_frame)
continue;
if (!frames.empty() && !frames.count(it.first))
continue;
if (frame_range_begin != frame_range_end &&
(it.first < frame_range_begin ||
frame_range_end <= it.first))
continue;
if (FLAGS_o.empty())
printf(
"Frame 0x%08x (Type=%d Top=%d Row=%d "
"Column=%d "
"Minor=%d):\n",
static_cast<uint32_t>(it.first),
static_cast<unsigned int>(
it.first.block_type()),
it.first.is_bottom_half_rows() ? 1 : 0,
it.first.row(), it.first.column(),
it.first.minor());
if (FLAGS_p) {
if (it.first.minor() == 0 && !pgmdata.empty())
pgmsep.push_back(pgmdata.size());
pgmdata.push_back(std::vector<bool>());
for (size_t i = 0; i < it.second.size(); i++)
for (int k = 0; k < word_length; k++)
pgmdata.back().push_back(
(it.second.at(i) &
(1 << k)) != 0);
} else if (FLAGS_x || FLAGS_y) {
for (int i = 0; i < (int)it.second.size();
i++) {
for (int k = 0; k < word_length; k++) {
if (((i != 50 || k > 12 ||
FLAGS_C)) &&
((it.second.at(i) &
(1 << k)) != 0)) {
if (FLAGS_x)
fprintf(
f,
"bit_%08x_%"
"03d_%"
"02d_t%d_h%"
"d_r%d_c%"
"d_m%d\n",
static_cast<
uint32_t>(
it.first),
i, k,
static_cast<
unsigned int>(
it.first
.block_type()),
it.first.is_bottom_half_rows()
? 1
: 0,
it.first
.row(),
it.first
.column(),
it.first
.minor());
else
fprintf(
f,
"bit_%08x_%"
"03d_"
"%02d\n",
static_cast<
uint32_t>(
it.first),
i, k);
}
}
}
if (FLAGS_o.empty())
fprintf(f, "\n");
} else {
if (!FLAGS_o.empty())
fprintf(
f, ".frame 0x%08x\n",
static_cast<uint32_t>(it.first));
for (size_t i = 0; i < it.second.size(); i++)
fprintf(f, "%08x%s",
it.second.at(i) &
((i != 50 || FLAGS_C)
? 0xffffffff
: 0xffffe000),
(i % 6) == 5 ? "\n" : " ");
fprintf(f, "\n\n");
}
}
if (FLAGS_p) {
int width = pgmdata.size() + pgmsep.size();
int height = ArchType::words_per_frame * word_length;
fprintf(f, "P5 %d %d 15\n", width, height);
for (int y = 0,
bit = ArchType::words_per_frame * word_length -
1;
y < height; y++, bit--) {
for (int x = 0, frame = 0, sep = 0; x < width;
x++, frame++) {
if (sep < int(pgmsep.size()) &&
frame == pgmsep.at(sep)) {
fputc(8, f);
x++, sep++;
}
if (bit >=
(int)pgmdata.at(frame).size()) {
fputc(0, f);
continue;
}
fputc(
pgmdata.at(frame).at(bit) ? 15 : 0,
f);
}
if (bit % word_length == 0 && y) {
for (int x = 0; x < width; x++)
fputc(8, f);
y++;
}
}
}
if (!FLAGS_o.empty())
fclose(f);
printf("DONE\n");
return 0;
}
};
int main(int argc, char** argv) {
gflags::SetUsageMessage(
absl::StrCat("Usage: ", argv[0], " [options] [bitfile]"));
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto part = xc7series::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file not found or invalid" << std::endl;
return 1;
}
if (FLAGS_f >= 0) {
frames.insert(FLAGS_f);
}
@ -73,7 +271,7 @@ int main(int argc, char** argv) {
frame_range_end = strtol(p.second.c_str(), nullptr, 0) + 1;
}
absl::optional<xc7series::BitstreamReader> reader;
std::vector<uint8_t> in_bytes;
if (argc == 2) {
auto in_file_name = argv[1];
auto in_file =
@ -87,171 +285,23 @@ int main(int argc, char** argv) {
std::cout << "Bitstream size: " << in_file->size() << " bytes"
<< std::endl;
reader = xc7series::BitstreamReader::InitWithBytes(
in_file->as_bytes());
in_bytes = std::vector<uint8_t>(
static_cast<uint8_t*>(in_file->data()),
static_cast<uint8_t*>(in_file->data()) + in_file->size());
} else {
std::vector<uint8_t> bitdata;
while (1) {
int c = getchar();
if (c == EOF)
break;
bitdata.push_back(c);
in_bytes.push_back(c);
}
std::cout << "Bitstream size: " << bitdata.size() << " bytes"
std::cout << "Bitstream size: " << in_bytes.size() << " bytes"
<< std::endl;
reader = xc7series::BitstreamReader::InitWithBytes(bitdata);
}
if (!reader) {
std::cerr << "Bitstream does not appear to be a Xilinx "
<< "7-series bitstream!" << std::endl;
return 1;
}
std::cout << "Config size: " << reader->words().size() << " words"
<< std::endl;
auto config = xc7series::Configuration::InitWithPackets(*part, *reader);
if (!config) {
std::cerr << "Bitstream does not appear to be for this part"
<< std::endl;
return 1;
}
std::cout << "Number of configuration frames: "
<< config->frames().size() << std::endl;
FILE* f = stdout;
if (!FLAGS_o.empty()) {
f = fopen(FLAGS_o.c_str(), "w");
if (f == nullptr) {
printf("Can't open output file '%s' for writing!\n",
FLAGS_o.c_str());
return 1;
}
} else {
fprintf(f, "\n");
}
std::vector<std::vector<bool>> pgmdata;
std::vector<int> pgmsep;
for (auto& it : config->frames()) {
if (FLAGS_z && it.second == zero_frame)
continue;
if (!frames.empty() && !frames.count(it.first))
continue;
if (frame_range_begin != frame_range_end &&
(it.first < frame_range_begin ||
frame_range_end <= it.first))
continue;
if (FLAGS_o.empty())
printf(
"Frame 0x%08x (Type=%d Top=%d Row=%d Column=%d "
"Minor=%d):\n",
static_cast<uint32_t>(it.first),
static_cast<unsigned int>(it.first.block_type()),
it.first.is_bottom_half_rows() ? 1 : 0,
it.first.row(), it.first.column(),
it.first.minor());
if (FLAGS_p) {
if (it.first.minor() == 0 && !pgmdata.empty())
pgmsep.push_back(pgmdata.size());
pgmdata.push_back(std::vector<bool>());
for (int i = 0; i < 101; i++)
for (int k = 0; k < 32; k++)
pgmdata.back().push_back(
(it.second.at(i) & (1 << k)) != 0);
} else if (FLAGS_x || FLAGS_y) {
for (int i = 0; i < 101; i++)
for (int k = 0; k < 32; k++)
if ((i != 50 || k > 12 || FLAGS_C) &&
((it.second.at(i) & (1 << k)) !=
0)) {
if (FLAGS_x)
fprintf(
f,
"bit_%08x_%03d_%"
"02d_t%d_h%d_r%d_c%"
"d_m%d\n",
static_cast<
uint32_t>(
it.first),
i, k,
static_cast<
unsigned int>(
it.first
.block_type()),
it.first.is_bottom_half_rows()
? 1
: 0,
it.first.row(),
it.first.column(),
it.first.minor());
else
fprintf(f,
"bit_%08x_%03d_"
"%02d\n",
static_cast<
uint32_t>(
it.first),
i, k);
}
if (FLAGS_o.empty())
fprintf(f, "\n");
} else {
if (!FLAGS_o.empty())
fprintf(f, ".frame 0x%08x\n",
static_cast<uint32_t>(it.first));
for (int i = 0; i < 101; i++)
fprintf(f, "%08x%s",
it.second.at(i) &
((i != 50 || FLAGS_C) ? 0xffffffff
: 0xffffe000),
(i % 6) == 5 ? "\n" : " ");
fprintf(f, "\n\n");
}
}
if (FLAGS_p) {
int width = pgmdata.size() + pgmsep.size();
int height = 101 * 32 + 100;
fprintf(f, "P5 %d %d 15\n", width, height);
for (int y = 0, bit = 101 * 32 - 1; y < height; y++, bit--) {
for (int x = 0, frame = 0, sep = 0; x < width;
x++, frame++) {
if (sep < int(pgmsep.size()) &&
frame == pgmsep.at(sep)) {
fputc(8, f);
x++, sep++;
}
fputc(pgmdata.at(frame).at(bit) ? 15 : 0, f);
}
if (bit % 32 == 0 && y) {
for (int x = 0; x < width; x++)
fputc(8, f);
y++;
}
}
}
if (!FLAGS_o.empty())
fclose(f);
printf("DONE\n");
return 0;
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(
FLAGS_architecture);
return absl::visit(BitReader(in_bytes), arch_container);
}

View File

@ -1,26 +1,56 @@
#include <algorithm>
#include <iostream>
#include <typeinfo>
#include <absl/strings/str_cat.h>
#include <absl/types/span.h>
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
namespace xc7series = prjxray::xilinx::xc7series;
namespace xilinx = prjxray::xilinx;
struct Action {
std::string name;
std::function<int(int, char* [])> handler;
};
struct ConfigPacketsLister {
ConfigPacketsLister(const absl::Span<uint8_t>& bytes) : bytes_(bytes) {}
const absl::Span<uint8_t>& bytes_;
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto reader =
xilinx::BitstreamReader<ArchType>::InitWithBytes(bytes_);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream"
<< std::endl;
return 1;
}
for (auto packet : *reader) {
std::cout << packet;
}
return 0;
}
};
int ListConfigPackets(int argc, char* argv[]) {
std::string architecture("Series7");
if (argc < 1) {
std::cerr << "ERROR: no input specified" << std::endl;
std::cerr << "Usage: " << argv[0]
<< "list_config_packets <bit_file>" << std::endl;
return 1;
}
if (argc == 2) {
architecture = argv[1];
}
auto in_file_name = argv[0];
auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
@ -29,22 +59,64 @@ int ListConfigPackets(int argc, char* argv[]) {
<< std::endl;
return 1;
}
auto reader =
xc7series::BitstreamReader::InitWithBytes(in_file->as_bytes());
if (!reader) {
std::cerr << "Input doesn't look like a bitstream" << std::endl;
return 1;
}
for (auto packet : *reader) {
std::cout << packet;
}
return 0;
auto in_bytes = absl::Span<uint8_t>(
static_cast<uint8_t*>(in_file->data()), in_file->size());
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(architecture);
return absl::visit(ConfigPacketsLister(in_bytes), arch_container);
}
struct DebugFrameAddressesDumper {
DebugFrameAddressesDumper(const absl::Span<uint8_t>& bytes)
: bytes_(bytes) {}
const absl::Span<uint8_t>& bytes_;
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto reader =
xilinx::BitstreamReader<ArchType>::InitWithBytes(bytes_);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream"
<< std::endl;
return 1;
}
bool found_one_lout = false;
for (auto packet : *reader) {
if ((packet.opcode() !=
xilinx::ConfigurationPacket<
typename ArchType::ConfRegType>::Opcode::
Write) ||
(packet.address() != ArchType::ConfRegType::LOUT)) {
continue;
}
if (packet.data().size() != 1) {
std::cerr << "Write to FAR with word_count != 1"
<< std::endl;
continue;
}
found_one_lout = true;
std::cout << std::dec << packet.data()[0] << std::endl;
}
if (!found_one_lout) {
std::cerr
<< "No LOUT writes found. Was "
<< "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?"
<< std::endl;
return 1;
}
return 0;
}
};
int DumpDebugbitstreamFrameAddresses(int argc, char* argv[]) {
std::string architecture("Series7");
if (argc < 1) {
std::cerr << "ERROR: no input specified" << std::endl;
std::cerr << "Usage: " << argv[0]
@ -52,6 +124,9 @@ int DumpDebugbitstreamFrameAddresses(int argc, char* argv[]) {
<< std::endl;
return 1;
}
if (argc == 2) {
architecture = argv[1];
}
auto in_file_name = argv[0];
auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
@ -63,86 +138,79 @@ int DumpDebugbitstreamFrameAddresses(int argc, char* argv[]) {
auto in_bytes = absl::Span<uint8_t>(
static_cast<uint8_t*>(in_file->data()), in_file->size());
auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream" << std::endl;
return 1;
}
bool found_one_lout = false;
for (auto packet : *reader) {
if ((packet.opcode() !=
xc7series::ConfigurationPacket::Opcode::Write) ||
(packet.address() !=
xc7series::ConfigurationRegister::LOUT)) {
continue;
}
if (packet.data().size() != 1) {
std::cerr << "Write to FAR with word_count != 1"
<< std::endl;
continue;
}
found_one_lout = true;
std::cout << std::dec << packet.data()[0] << std::endl;
}
if (!found_one_lout) {
std::cerr << "No LOUT writes found. Was "
<< "BITSTREAM.GENERAL.DEBUGBITSTREAM set to YES?"
<< std::endl;
return 1;
}
return 0;
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(architecture);
return absl::visit(DebugFrameAddressesDumper(in_bytes), arch_container);
}
int GetDeviceId(int argc, char* argv[]) {
if (argc < 1) {
std::cerr << "ERROR: no input specified" << std::endl;
std::cerr << "Usage: " << argv[0] << "get_device_id <bit_file>"
<< std::endl;
return 1;
}
struct DeviceIdGetter {
DeviceIdGetter(const absl::Span<uint8_t>& bytes) : bytes_(bytes) {}
auto in_file_name = argv[0];
auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
if (!in_file) {
std::cerr << "Unable to open bit file: " << in_file_name
<< std::endl;
return 1;
}
const absl::Span<uint8_t>& bytes_;
auto in_bytes = absl::Span<uint8_t>(
static_cast<uint8_t*>(in_file->data()), in_file->size());
auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream" << std::endl;
return 1;
}
auto idcode_packet = std::find_if(
reader->begin(), reader->end(),
[](const xc7series::ConfigurationPacket& packet) {
return (packet.opcode() ==
xc7series::ConfigurationPacket::Opcode::Write) &&
(packet.address() ==
xc7series::ConfigurationRegister::IDCODE);
});
if (idcode_packet != reader->end()) {
if (idcode_packet->data().size() != 1) {
std::cerr << "Write to IDCODE with word_count != 1"
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto reader =
xilinx::BitstreamReader<ArchType>::InitWithBytes(bytes_);
if (!reader) {
std::cerr << "Input doesn't look like a bitstream"
<< std::endl;
return 1;
}
auto idcode_packet = std::find_if(
reader->begin(), reader->end(),
[](const xilinx::ConfigurationPacket<
typename ArchType::ConfRegType>& packet) {
return (packet.opcode() ==
xilinx::ConfigurationPacket<
typename ArchType::ConfRegType>::
Opcode::Write) &&
(packet.address() ==
ArchType::ConfRegType::IDCODE);
});
if (idcode_packet != reader->end()) {
if (idcode_packet->data().size() != 1) {
std::cerr
<< "Write to IDCODE with word_count != 1"
<< std::endl;
return 1;
}
std::cout << "0x" << std::hex
<< idcode_packet->data()[0] << std::endl;
}
return 0;
}
};
std::cout << "0x" << std::hex << idcode_packet->data()[0]
int GetDeviceId(int argc, char* argv[]) {
std::string architecture("Series7");
if (argc < 1) {
std::cerr << "ERROR: no input specified" << std::endl;
std::cerr << "Usage: " << argv[0]
<< "get_device_id <bit_file> [<architecture>]"
<< std::endl;
return 1;
}
if (argc == 2) {
architecture = argv[1];
}
return 0;
auto in_file_name = argv[0];
auto in_file = prjxray::MemoryMappedFile::InitWithFile(in_file_name);
if (!in_file) {
std::cerr << "Unable to open bit file: " << in_file_name
<< std::endl;
return 1;
}
auto in_bytes = absl::Span<uint8_t>(
static_cast<uint8_t*>(in_file->data()), in_file->size());
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(architecture);
return absl::visit(DeviceIdGetter(in_bytes), arch_container);
}
int main(int argc, char* argv[]) {
Action actions[] = {
{"list_config_packets", ListConfigPackets},

View File

@ -11,15 +11,13 @@
#include <absl/types/span.h>
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/frame_address.h>
#include <prjxray/xilinx/xc7series/global_clock_region.h>
#include <prjxray/xilinx/xc7series/part.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
#include <yaml-cpp/yaml.h>
DEFINE_bool(f, false, "Use FAR registers instead of LOUT ones");
namespace xc7series = prjxray::xilinx::xc7series;
namespace xilinx = prjxray::xilinx;
int main(int argc, char* argv[]) {
gflags::SetUsageMessage(
@ -41,38 +39,38 @@ int main(int argc, char* argv[]) {
return 1;
}
auto reader =
xc7series::BitstreamReader::InitWithBytes(in_file->as_bytes());
auto reader = xilinx::BitstreamReader<xilinx::Series7>::InitWithBytes(
in_file->as_bytes());
if (!reader) {
std::cerr << "Input doesn't look like a bitstream" << std::endl;
return 1;
}
bool found_fdri_write = false;
std::vector<xc7series::FrameAddress> frame_addresses;
std::vector<xilinx::Series7::FrameAddress> frame_addresses;
absl::optional<uint32_t> idcode;
for (auto packet : *reader) {
if (packet.opcode() !=
xc7series::ConfigurationPacket::Opcode::Write) {
xilinx::ConfigurationPacket<
xilinx::Series7::ConfRegType>::Opcode::Write) {
continue;
}
if (packet.address() ==
xc7series::ConfigurationRegister::FDRI) {
if (packet.address() == xilinx::Series7::ConfRegType::FDRI) {
found_fdri_write = true;
} else if ((packet.address() ==
xc7series::ConfigurationRegister::IDCODE) &&
xilinx::Series7::ConfRegType::IDCODE) &&
packet.data().size() == 1) {
idcode = packet.data()[0];
} else if (found_fdri_write &&
(packet.address() ==
xc7series::ConfigurationRegister::LOUT) &&
xilinx::Series7::ConfRegType::LOUT) &&
(packet.data().size() == 1) && FLAGS_f == false) {
frame_addresses.push_back(packet.data()[0]);
found_fdri_write = false;
} else if (found_fdri_write &&
(packet.address() ==
xc7series::ConfigurationRegister::FAR) &&
xilinx::Series7::ConfRegType::FAR) &&
(packet.data().size() == 1) && FLAGS_f == true) {
frame_addresses.push_back(packet.data()[0]);
found_fdri_write = false;
@ -92,8 +90,8 @@ int main(int argc, char* argv[]) {
return 1;
}
auto part = xc7series::Part(*idcode, frame_addresses.begin(),
frame_addresses.end());
auto part = xilinx::Series7::Part(*idcode, frame_addresses.begin(),
frame_addresses.end());
std::cout << YAML::Node(part) << std::endl;
return 0;

View File

@ -1,7 +1,9 @@
#include <iostream>
#include <gflags/gflags.h>
#include <prjxray/xilinx/xc7series/utils.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_writer.h>
#include <prjxray/xilinx/configuration.h>
DEFINE_string(part_name, "", "Name of the 7-series part");
DEFINE_string(part_file, "", "Definition file for target 7-series part");
@ -11,51 +13,69 @@ DEFINE_string(
"File containing a list of frame deltas to be applied to the base "
"bitstream. Each line in the file is of the form: "
"<frame_address> <word1>,...,<word101>.");
DEFINE_string(output_file, "", "Write bitsteam to file");
DEFINE_string(output_file, "", "Write bitstream to file");
DEFINE_string(architecture,
"Series7",
"Architecture of the provided bitstream");
namespace xc7series = prjxray::xilinx::xc7series;
namespace xilinx = prjxray::xilinx;
struct Frames2BitWriter {
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto part = ArchType::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file " << FLAGS_part_file
<< " not found or invalid" << std::endl;
return 1;
}
// Read the frames from the input file
xilinx::Frames<ArchType> frames;
if (frames.readFrames(FLAGS_frm_file)) {
std::cerr << "Frames file " << FLAGS_frm_file
<< " not found or invalid" << std::endl;
return 1;
}
if (std::is_same<ArchType, xilinx::Series7>::value) {
// In case the frames input file is missing some frames
// that are in the tilegrid
frames.addMissingFrames(part);
}
// Create data for the type 2 configuration packet with
// information about all frames
typename xilinx::Configuration<ArchType>::PacketData
configuration_packet_data(
xilinx::Configuration<ArchType>::
createType2ConfigurationPacketData(
frames.getFrames(), part));
// Put together a configuration package
typename ArchType::ConfigurationPackage configuration_package;
xilinx::Configuration<ArchType>::createConfigurationPackage(
configuration_package, configuration_packet_data, part);
// Write bitstream
auto bitstream_writer =
xilinx::BitstreamWriter<ArchType>(configuration_package);
if (bitstream_writer.writeBitstream(
configuration_package, FLAGS_part_name, FLAGS_frm_file,
"xc7frames2bit", FLAGS_output_file)) {
std::cerr << "Failed to write bitstream" << std::endl
<< "Exitting" << std::endl;
}
return 0;
}
};
int main(int argc, char* argv[]) {
gflags::SetUsageMessage(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto part = xc7series::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file " << FLAGS_part_file
<< " not found or invalid" << std::endl;
return 1;
}
// Read the frames from the input file
xc7series::Frames frames;
if (frames.readFrames(FLAGS_frm_file)) {
std::cerr << "Frames file " << FLAGS_frm_file
<< " not found or invalid" << std::endl;
return 1;
}
// In case the frames input file is missing some frames that are in the
// tilegrid
frames.addMissingFrames(part);
// Create data for the type 2 configuration packet with information
// about all frames
xc7series::PacketData configuration_packet_data(
xc7series::createType2ConfigurationPacketData(frames.getFrames(),
part));
// Put together a configuration package
xc7series::ConfigurationPackage configuration_package;
xc7series::createConfigurationPackage(configuration_package,
configuration_packet_data, part);
// Write bitstream
if (xc7series::writeBitstream(configuration_package, FLAGS_part_name,
FLAGS_frm_file, "xc7frames2bit",
FLAGS_output_file)) {
std::cerr << "Failed to write bitstream" << std::endl
<< "Exitting" << std::endl;
}
return 0;
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(
FLAGS_architecture);
return absl::visit(Frames2BitWriter(), arch_container);
}

View File

@ -2,7 +2,10 @@
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/utils.h>
#include <prjxray/xilinx/architectures.h>
#include <prjxray/xilinx/bitstream_reader.h>
#include <prjxray/xilinx/bitstream_writer.h>
#include <prjxray/xilinx/configuration.h>
DEFINE_string(part_name, "", "");
DEFINE_string(part_file, "", "Definition file for target 7-series part");
@ -16,13 +19,17 @@ DEFINE_string(
"bitstream. Each line in the file is of the form: "
"<frame_address> <word1>,...,<word101>.");
DEFINE_string(output_file, "", "Write patched bitsteam to file");
DEFINE_string(architecture,
"Series7",
"Architecture of the provided bitstream");
namespace xc7series = prjxray::xilinx::xc7series;
namespace xilinx = prjxray::xilinx;
template <typename ArchType>
int patch_frames(
const std::string& frm_file_str,
std::map<xc7series::FrameAddress, std::vector<uint32_t>>* frames) {
xc7series::Frames frames_from_file;
std::map<typename ArchType::FrameAddress, std::vector<uint32_t>>* frames) {
xilinx::Frames<ArchType> frames_from_file;
if (frames_from_file.readFrames(frm_file_str)) {
std::cerr << "Failed to read frames" << std::endl;
return 1;
@ -46,73 +53,94 @@ int patch_frames(
return 0;
}
struct BitstreamPatcher {
template <typename T>
int operator()(T& arg) {
using ArchType = std::decay_t<decltype(arg)>;
auto part = ArchType::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file not found or invalid"
<< std::endl;
return 1;
}
auto bitstream_file = prjxray::MemoryMappedFile::InitWithFile(
FLAGS_bitstream_file);
if (!bitstream_file) {
std::cerr << "Can't open base bitstream file: "
<< FLAGS_bitstream_file << std::endl;
return 1;
}
auto bitstream_reader =
xilinx::BitstreamReader<ArchType>::InitWithBytes(
bitstream_file->as_bytes());
if (!bitstream_reader) {
std::cout << "Bitstream does not appear to be a "
"7-series bitstream!"
<< std::endl;
return 1;
}
auto bitstream_config =
xilinx::Configuration<ArchType>::InitWithPackets(
*part, *bitstream_reader);
if (!bitstream_config) {
std::cerr
<< "Bitstream does not appear to be for this part"
<< std::endl;
return 1;
}
// Copy the base frames to a mutable collection
std::map<typename ArchType::FrameAddress, std::vector<uint32_t>>
frames;
for (auto& frame_val : bitstream_config->frames()) {
auto& cur_frame = frames[frame_val.first];
std::copy(frame_val.second.begin(),
frame_val.second.end(),
std::back_inserter(cur_frame));
}
if (!FLAGS_frm_file.empty()) {
int ret =
patch_frames<ArchType>(FLAGS_frm_file, &frames);
if (ret != 0) {
return ret;
}
}
// Create data for the type 2 configuration packet with
// information about all frames
typename xilinx::Configuration<ArchType>::PacketData
configuration_packet_data(
xilinx::Configuration<ArchType>::
createType2ConfigurationPacketData(frames, part));
// Put together a configuration package
typename ArchType::ConfigurationPackage configuration_package;
xilinx::Configuration<ArchType>::createConfigurationPackage(
configuration_package, configuration_packet_data, part);
// Write bitstream.
auto bitstream_writer =
xilinx::BitstreamWriter<ArchType>(configuration_package);
if (bitstream_writer.writeBitstream(
configuration_package, FLAGS_part_name, FLAGS_frm_file,
"xc7patch", FLAGS_output_file)) {
std::cerr << "Failed to write bitstream" << std::endl
<< "Exitting" << std::endl;
}
return 0;
}
};
int main(int argc, char* argv[]) {
gflags::SetUsageMessage(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
auto part = xc7series::Part::FromFile(FLAGS_part_file);
if (!part) {
std::cerr << "Part file not found or invalid" << std::endl;
return 1;
}
auto bitstream_file =
prjxray::MemoryMappedFile::InitWithFile(FLAGS_bitstream_file);
if (!bitstream_file) {
std::cerr << "Can't open base bitstream file: "
<< FLAGS_bitstream_file << std::endl;
return 1;
}
auto bitstream_reader = xc7series::BitstreamReader::InitWithBytes(
bitstream_file->as_bytes());
if (!bitstream_reader) {
std::cout
<< "Bitstream does not appear to be a 7-series bitstream!"
<< std::endl;
return 1;
}
auto bitstream_config =
xc7series::Configuration::InitWithPackets(*part, *bitstream_reader);
if (!bitstream_config) {
std::cerr << "Bitstream does not appear to be for this part"
<< std::endl;
return 1;
}
// Copy the base frames to a mutable collection
std::map<xc7series::FrameAddress, std::vector<uint32_t>> frames;
for (auto& frame_val : bitstream_config->frames()) {
auto& cur_frame = frames[frame_val.first];
std::copy(frame_val.second.begin(), frame_val.second.end(),
std::back_inserter(cur_frame));
}
if (!FLAGS_frm_file.empty()) {
int ret = patch_frames(FLAGS_frm_file, &frames);
if (ret != 0) {
return ret;
}
}
// Create data for the type 2 configuration packet with information
// about all frames
xc7series::PacketData configuration_packet_data(
xc7series::createType2ConfigurationPacketData(frames, part));
// Put together a configuration package
xc7series::ConfigurationPackage configuration_package;
xc7series::createConfigurationPackage(configuration_package,
configuration_packet_data, part);
// Write bitstream.
if (xc7series::writeBitstream(configuration_package, FLAGS_part_name,
FLAGS_frm_file, "xc7patch",
FLAGS_output_file)) {
std::cerr << "Failed to write bitstream" << std::endl
<< "Exitting" << std::endl;
}
return 0;
xilinx::Architecture::Container arch_container =
xilinx::ArchitectureFactory::create_architecture(
FLAGS_architecture);
return absl::visit(BitstreamPatcher(), arch_container);
}