diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c934db88..d7344330 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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) diff --git a/lib/include/prjxray/xilinx/architectures.h b/lib/include/prjxray/xilinx/architectures.h new file mode 100644 index 00000000..11958531 --- /dev/null +++ b/lib/include/prjxray/xilinx/architectures.h @@ -0,0 +1,55 @@ +#ifndef PRJXRAY_LIB_XILINX_ARCHITECTURES_H_ +#define PRJXRAY_LIB_XILINX_ARCHITECTURES_H_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +class Series7; + +class Architecture { + public: + using Container = absl::variant; + virtual const std::string& name() const = 0; +}; + +class Series7 : public Architecture { + public: + using ConfRegType = Series7ConfigurationRegister; + using Part = xc7series::Part; + using ConfigurationPackage = + std::vector>>; + 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_ diff --git a/lib/include/prjxray/xilinx/bitstream_reader.h b/lib/include/prjxray/xilinx/bitstream_reader.h new file mode 100644 index 00000000..d514fadd --- /dev/null +++ b/lib/include/prjxray/xilinx/bitstream_reader.h @@ -0,0 +1,179 @@ +#ifndef PRJXRAY_LIB_XILINX_BITSTREAM_READER_H +#define PRJXRAY_LIB_XILINX_BITSTREAM_READER_H + +#include +#include +#include +#include + +#include + +#include +#include +#include + +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 +class BitstreamReader { + public: + using value_type = ConfigurationPacket; + + // Implements an iterator over the words grouped in configuration + // packets. + class iterator + : public std::iterator { + 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 words); + + private: + friend BitstreamReader; + + typename value_type::ParseResult parse_result_; + absl::Span 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&& 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 + static absl::optional> InitWithBytes( + T bitstream); + + const std::vector& words() { return words_; }; + + // Returns an iterator that yields `ConfigurationPackets` + // as read from the bitstream. + iterator begin(); + iterator end(); + + private: + static std::array kSyncWord; + + std::vector words_; +}; + +template <> +template +absl::optional> +BitstreamReader::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>(); + } + sync_pos += kSyncWord.size(); + + // Wrap the provided container in a span that strips off the preamble. + absl::Span 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(config_packets); + std::vector words{big_endian_reader.begin(), + big_endian_reader.end()}; + + return BitstreamReader(std::move(words)); +} + +// Sync word as specified in UG470 page 81 +template +std::array BitstreamReader::kSyncWord{0xAA, 0x99, 0x55, + 0x66}; + +template +typename BitstreamReader::iterator +BitstreamReader::begin() { + return iterator(absl::MakeSpan(words_)); +} + +template +typename BitstreamReader::iterator BitstreamReader::end() { + return iterator({}); +} + +template +BitstreamReader::iterator::iterator(absl::Span words) { + parse_result_.first = words; + parse_result_.second = {}; + ++(*this); +} + +template +typename 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(); + break; + } + + words_ = parse_result_.first; + parse_result_ = new_result; + } while (!parse_result_.first.empty() && !parse_result_.second); + + if (!parse_result_.second) { + words_ = absl::Span(); + } + + return *this; +} + +template +bool BitstreamReader::iterator::operator==( + const iterator& other) const { + return words_ == other.words_; +} + +template +bool BitstreamReader::iterator::operator!=( + const iterator& other) const { + return !(*this == other); +} + +template +const typename BitstreamReader::value_type& + BitstreamReader::iterator::operator*() const { + return *(parse_result_.second); +} + +template +const typename BitstreamReader::value_type* + BitstreamReader::iterator::operator->() const { + return parse_result_.second.operator->(); +} +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_BITSTREAM_READER_H diff --git a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h b/lib/include/prjxray/xilinx/bitstream_writer.h similarity index 58% rename from lib/include/prjxray/xilinx/xc7series/bitstream_writer.h rename to lib/include/prjxray/xilinx/bitstream_writer.h index 806cc9a2..f904e7cb 100644 --- a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h +++ b/lib/include/prjxray/xilinx/bitstream_writer.h @@ -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 #include @@ -14,16 +14,21 @@ #include #include -#include +#include namespace prjxray { namespace xilinx { -namespace xc7series { +// Writes out the complete Xilinx bitstream including +// header, sync word and configuration sequence. +template class BitstreamWriter { public: - typedef std::array header_t; - typedef std::vector> packets_t; + typedef std::vector header_t; + typedef std::vector>> + packets_t; + typedef std::vector BitstreamHeader; // Only defined if a packet exists typedef absl::optional> op_data_t; typedef absl::Span::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* + 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* + packet_; }; - using value_type = uint32_t; class iterator : public std::iterator { 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 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 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 diff --git a/lib/include/prjxray/xilinx/xc7series/configuration.h b/lib/include/prjxray/xilinx/configuration.h similarity index 59% rename from lib/include/prjxray/xilinx/xc7series/configuration.h rename to lib/include/prjxray/xilinx/configuration.h index c86bc493..5b568818 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration.h +++ b/lib/include/prjxray/xilinx/configuration.h @@ -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 +#include #include + #include -#include -#include -#include -#include +#include +#include namespace prjxray { namespace xilinx { -namespace xc7series { +template class Configuration { public: - using FrameMap = std::map>; + using FrameMap = std::map>; + using PacketData = std::vector; + // Returns a configuration, i.e. collection of frame addresses + // and corresponding data from a collection of configuration packets. template - static absl::optional InitWithPackets( - const Part& part, + static absl::optional> InitWithPackets( + const typename ArchType::Part& part, Collection& packets); - Configuration(const Part& part, - std::map>* 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& part); + + // Returns the payload for a type 2 packet + // which allows for bigger payload compared to type 1. + static PacketData createType2ConfigurationPacketData( + const typename Frames::Frames2Data& frames, + absl::optional& part); + + Configuration(const typename ArchType::Part& part, + std::map>* 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 -absl::optional Configuration::InitWithPackets( - const Part& part, +absl::optional> Configuration::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::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::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::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::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::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::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::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::InitWithPackets( return Configuration(part, frames); } -} // namespace xc7series } // namespace xilinx } // namespace prjxray -#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_H_ +#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_H_ diff --git a/lib/include/prjxray/xilinx/configuration_packet.h b/lib/include/prjxray/xilinx/configuration_packet.h new file mode 100644 index 00000000..4df21052 --- /dev/null +++ b/lib/include/prjxray/xilinx/configuration_packet.h @@ -0,0 +1,68 @@ +#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H +#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H + +#include +#include + +#include +#include +#include + +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 +class ConfigurationPacket { + public: + typedef std::pair, + absl::optional>> + 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& 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& data() const { return data_; } + static ParseResult InitWithWords( + absl::Span words, + const ConfigurationPacket* previous_packet = + nullptr); + + private: + unsigned int header_type_; + Opcode opcode_; + ConfigRegType address_; + absl::Span data_; +}; + +template +std::ostream& operator<<(std::ostream& o, + const ConfigurationPacket& packet); + +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_H diff --git a/lib/include/prjxray/xilinx/configuration_packet_with_payload.h b/lib/include/prjxray/xilinx/configuration_packet_with_payload.h new file mode 100644 index 00000000..05619386 --- /dev/null +++ b/lib/include/prjxray/xilinx/configuration_packet_with_payload.h @@ -0,0 +1,36 @@ +#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H +#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H + +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +template +class ConfigurationPacketWithPayload + : public ConfigurationPacket { + public: + ConfigurationPacketWithPayload( + typename ConfigurationPacket::Opcode op, + ConfigRegType reg, + const std::array& payload) + : ConfigurationPacket( + ConfigurationPacketType::TYPE1, + op, + reg, + absl::Span(payload_)), + payload_(std::move(payload)) {} + + private: + std::array payload_; +}; + +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKET_WITH_PAYLOAD_H diff --git a/lib/include/prjxray/xilinx/configuration_packetizer.h b/lib/include/prjxray/xilinx/configuration_packetizer.h new file mode 100644 index 00000000..5ca7ed9e --- /dev/null +++ b/lib/include/prjxray/xilinx/configuration_packetizer.h @@ -0,0 +1,72 @@ +#ifndef PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_ +#define PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_ + +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +template +class ConfigurationPacketizer { + public: + class iterator + : std::iterator< + std::input_iterator_tag, + ConfigurationPacket> { + public: + iterator( + const typename ArchType::Part* part, + typename Configuration::FrameMap::const_iterator + begin, + typename 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 typename ArchType::Part* part_; + State state_; + typename Configuration::FrameMap::const_iterator + frame_cur_; + typename Configuration::FrameMap::const_iterator + frame_end_; + absl::optional 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 xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_CONFIGURATION_PACKETIZER_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_register.h b/lib/include/prjxray/xilinx/configuration_register.h similarity index 50% rename from lib/include/prjxray/xilinx/xc7series/configuration_register.h rename to lib/include/prjxray/xilinx/configuration_register.h index 4fbc5d4c..9825aacb 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration_register.h +++ b/lib/include/prjxray/xilinx/configuration_register.h @@ -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 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_ diff --git a/lib/include/prjxray/xilinx/xc7series/frames.h b/lib/include/prjxray/xilinx/frames.h similarity index 60% rename from lib/include/prjxray/xilinx/xc7series/frames.h rename to lib/include/prjxray/xilinx/frames.h index 77f0e976..43747875 100644 --- a/lib/include/prjxray/xilinx/xc7series/frames.h +++ b/lib/include/prjxray/xilinx/frames.h @@ -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 #include #include -#include -#include -#include -#include +#include 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 class Frames { public: typedef std::vector FrameData; - typedef std::map Frames2Data; + typedef std::map + 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); + void addMissingFrames( + const absl::optional& 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 diff --git a/lib/include/prjxray/xilinx/nop_packet.h b/lib/include/prjxray/xilinx/nop_packet.h new file mode 100644 index 00000000..6f89e84d --- /dev/null +++ b/lib/include/prjxray/xilinx/nop_packet.h @@ -0,0 +1,24 @@ +#ifndef PRJXRAY_LIB_XILINX_NOP_PACKET_H +#define PRJXRAY_LIB_XILINX_NOP_PACKET_H + +#include +#include + +namespace prjxray { +namespace xilinx { + +template +class NopPacket : public ConfigurationPacket { + public: + NopPacket() + : ConfigurationPacket( + ConfigurationPacketType::TYPE1, + ConfigurationPacket::Opcode::NOP, + ConfigRegType::CRC, + {}) {} +}; + +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_NOP_PACKET_H diff --git a/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h b/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h deleted file mode 100644 index 5cfca36d..00000000 --- a/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H -#define PRJXRAY_LIB_XILINX_XC7SERIES_BITSTREAM_READER_H - -#include -#include -#include - -#include -#include - -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -class BitstreamReader { - public: - using value_type = ConfigurationPacket; - - class iterator - : public std::iterator { - 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 words); - - private: - friend BitstreamReader; - - ConfigurationPacket::ParseResult parse_result_; - absl::Span 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&& words); - - // Construct a `BitstreamReader` from a Container of bytes. - // Any bytes preceding an initial sync word are ignored. - template - static absl::optional InitWithBytes(T bitstream); - - const std::vector& words() { return words_; }; - - // Returns an iterator that yields `ConfigurationPackets` - // as read from the bitstream. - iterator begin(); - iterator end(); - - private: - static std::array kSyncWord; - - std::vector words_; -}; - -template -absl::optional 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(); - } - sync_pos += kSyncWord.size(); - - // Wrap the provided container in a span that strips off the preamble. - absl::Span 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(config_packets); - std::vector 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 diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h index 1b7c1c13..06307378 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h @@ -2,8 +2,8 @@ #define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H #include -#include -#include +#include +#include namespace prjxray { namespace xilinx { diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_packet.h b/lib/include/prjxray/xilinx/xc7series/configuration_packet.h deleted file mode 100644 index f60d370b..00000000 --- a/lib/include/prjxray/xilinx/xc7series/configuration_packet.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H -#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H - -#include - -#include -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -class ConfigurationPacket { - public: - typedef std::pair, - absl::optional> - ParseResult; - - enum Opcode { - NOP = 0, - Read = 1, - Write = 2, - /* reserved = 3 */ - }; - - ConfigurationPacket(unsigned int header_type, - Opcode opcode, - ConfigurationRegister address, - const absl::Span& 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 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& data() const { return data_; } - - private: - unsigned int header_type_; - Opcode opcode_; - ConfigurationRegister address_; - absl::Span data_; -}; - -std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet); - -} // namespace xc7series -} // namespace xilinx -} // namespace prjxray - -#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKET_H diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h b/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h deleted file mode 100644 index bdcdc3c3..00000000 --- a/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h +++ /dev/null @@ -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 - -#include -#include -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -template -class ConfigurationPacketWithPayload : public ConfigurationPacket { - public: - ConfigurationPacketWithPayload( - Opcode op, - ConfigurationRegister reg, - const std::array& payload) - : ConfigurationPacket(1, op, reg, absl::Span(payload_)), - payload_(std::move(payload)) {} - - private: - std::array payload_; -}; // namespace xc7series - -} // namespace xc7series -} // namespace xilinx -} // namespace prjxray - -#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_packetizer.h b/lib/include/prjxray/xilinx/xc7series/configuration_packetizer.h deleted file mode 100644 index 5eac8f17..00000000 --- a/lib/include/prjxray/xilinx/xc7series/configuration_packetizer.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKETIZER_H_ -#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_PACKETIZER_H_ - -#include -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -class ConfigurationPacketizer { - public: - class iterator - : std::iterator { - 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 frame_address_; - absl::optional 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_ diff --git a/lib/include/prjxray/xilinx/xc7series/row.h b/lib/include/prjxray/xilinx/xc7series/configuration_row.h similarity index 100% rename from lib/include/prjxray/xilinx/xc7series/row.h rename to lib/include/prjxray/xilinx/xc7series/configuration_row.h diff --git a/lib/include/prjxray/xilinx/xc7series/global_clock_region.h b/lib/include/prjxray/xilinx/xc7series/global_clock_region.h index 75b6de2d..8d791a25 100644 --- a/lib/include/prjxray/xilinx/xc7series/global_clock_region.h +++ b/lib/include/prjxray/xilinx/xc7series/global_clock_region.h @@ -7,8 +7,8 @@ #include #include +#include #include -#include #include namespace prjxray { diff --git a/lib/include/prjxray/xilinx/xc7series/nop_packet.h b/lib/include/prjxray/xilinx/xc7series/nop_packet.h deleted file mode 100644 index 65339883..00000000 --- a/lib/include/prjxray/xilinx/xc7series/nop_packet.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H -#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H - -#include -#include - -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 diff --git a/lib/include/prjxray/xilinx/xc7series/utils.h b/lib/include/prjxray/xilinx/xc7series/utils.h deleted file mode 100644 index 36767544..00000000 --- a/lib/include/prjxray/xilinx/xc7series/utils.h +++ /dev/null @@ -1,51 +0,0 @@ - -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_ -#define PRJXRAY_LIB_XILINX_XC7SERIES_UTILS_H_ - -#include -#include -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { -using PacketData = std::vector; -using BitstreamHeader = std::vector; -using ConfigurationPackage = std::vector>; - -// 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); - -// 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); - -// 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_ diff --git a/lib/xilinx/bitstream_writer.cc b/lib/xilinx/bitstream_writer.cc new file mode 100644 index 00000000..72cd5d77 --- /dev/null +++ b/lib/xilinx/bitstream_writer.cc @@ -0,0 +1,350 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +// Per UG470 pg 80: Bus Width Auto Detection +template <> +typename BitstreamWriter::header_t BitstreamWriter::header_{ + 0xFFFFFFFF, 0x000000BB, 0x11220044, 0xFFFFFFFF, 0xFFFFFFFF, 0xAA995566}; + +template +int BitstreamWriter::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(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(4); + + BitstreamWriter 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 BitstreamWriter::BitstreamHeader +BitstreamWriter::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((build_source.size() + 1) >> 8)); + bit_header.push_back(static_cast(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((part_name.size() + 1) >> 8)); + bit_header.push_back(static_cast(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((build_date_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(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((build_time_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(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 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()); +} + +template +typename 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()); +} + +template +BitstreamWriter::packet_iterator::packet_iterator( + const ConfigurationPacket* packet, + state_t state, + data_iterator_t itr_data) + : state_(state), itr_data_(itr_data), packet_(packet) {} + +template +typename 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; +} + +template +bool BitstreamWriter::packet_iterator::operator==( + const packet_iterator& other) const { + return state_ == other.state_ && itr_data_ == other.itr_data_; +} + +template +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 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 +const typename 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? +} + +template +const typename BitstreamWriter::itr_value_type + BitstreamWriter::packet_iterator::operator->() const { + return *(*this); +} + +/************************************************** + * BitstreamWriter::iterator + *************************************************/ + +template +typename BitstreamWriter::iterator +BitstreamWriter::begin() { + typename packets_t::const_iterator itr_packets = packets_.begin(); + absl::optional 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); +} + +template +typename BitstreamWriter::iterator BitstreamWriter::end() { + return iterator(header_.end(), packets_, packets_.end(), + absl::optional()); +} + +template +BitstreamWriter::iterator::iterator( + header_t::iterator itr_header, + const typename BitstreamWriter::packets_t& packets, + typename BitstreamWriter::packets_t::const_iterator itr_packets, + absl::optional itr_packet) + : itr_header_(itr_header), + packets_(packets), + itr_packets_(itr_packets), + op_itr_packet_(itr_packet) {} + +template +typename 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; +} + +template +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_; +} + +template +bool BitstreamWriter::iterator::operator!=( + const iterator& other) const { + return !(*this == other); +} + +template +const typename 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_); + } +} + +template +const typename BitstreamWriter::itr_value_type + BitstreamWriter::iterator::operator->() const { + return *(*this); +} + +template int BitstreamWriter::writeBitstream( + const Series7::ConfigurationPackage&, + const std::string&, + const std::string&, + const std::string&, + const std::string&); +template BitstreamWriter::iterator BitstreamWriter::begin(); +template BitstreamWriter::iterator BitstreamWriter::end(); +template const BitstreamWriter::itr_value_type + BitstreamWriter::iterator::operator*() const; +template BitstreamWriter::iterator& + BitstreamWriter::iterator::operator++(); +template bool BitstreamWriter::iterator::operator!=( + const BitstreamWriter::iterator&) const; + +} // namespace xilinx +} // namespace prjxray diff --git a/lib/xilinx/configuration.cc b/lib/xilinx/configuration.cc new file mode 100644 index 00000000..2c105020 --- /dev/null +++ b/lib/xilinx/configuration.cc @@ -0,0 +1,217 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +template <> +Configuration::PacketData +Configuration::createType2ConfigurationPacketData( + const Frames::Frames2Data& frames, + absl::optional& 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::createConfigurationPackage( + Series7::ConfigurationPackage& out_packets, + const PacketData& packet_data, + absl::optional& part) { + using ArchType = Series7; + using ConfigurationRegister = ArchType::ConfRegType; + // Initialization sequence + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::TIMER, {0x0})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::WBSTAR, {0x0})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::NOP)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::UNKNOWN, {0x0})); + + // Configuration Options 0 + out_packets.emplace_back(new ConfigurationPacketWithPayload< + 1, ConfigurationRegister>( + ConfigurationPacket::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::Opcode::Write, + ConfigurationRegister::COR1, {0x0})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::IDCODE, {part->idcode()})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::SWITCH)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::MASK, {0x401})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CTL0, {0x501})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::MASK, {0x0})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + 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, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FAR, {0x0})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::WCFG)})); + out_packets.emplace_back(new NopPacket()); + + // Frame data write + out_packets.emplace_back(new ConfigurationPacket( + TYPE1, ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FDRI, {})); + out_packets.emplace_back(new ConfigurationPacket( + TYPE2, ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FDRI, packet_data)); + + // Finalization sequence + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::GRESTORE)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::LFRM)})); + for (int ii = 0; ii < 100; ++ii) { + out_packets.emplace_back( + new NopPacket()); + } + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::START)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::FAR, {0x3be0000})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::MASK, {0x501})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CTL0, {0x501})); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::RCRC)})); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back(new NopPacket()); + out_packets.emplace_back( + new ConfigurationPacketWithPayload<1, ConfigurationRegister>( + ConfigurationPacket::Opcode::Write, + ConfigurationRegister::CMD, + {static_cast(xc7series::Command::DESYNC)})); + for (int ii = 0; ii < 400; ++ii) { + out_packets.emplace_back( + new NopPacket()); + } +} + +} // namespace xilinx +} // namespace prjxray diff --git a/lib/xilinx/xc7series/configuration_packet.cc b/lib/xilinx/configuration_packet.cc similarity index 77% rename from lib/xilinx/xc7series/configuration_packet.cc rename to lib/xilinx/configuration_packet.cc index bb241715..21be8c5a 100644 --- a/lib/xilinx/xc7series/configuration_packet.cc +++ b/lib/xilinx/configuration_packet.cc @@ -1,24 +1,28 @@ -#include +#include #include +#include #include #include namespace prjxray { namespace xilinx { -namespace xc7series { -std::pair, absl::optional> -ConfigurationPacket::InitWithWords(absl::Span words, - const ConfigurationPacket* previous_packet) { +template <> +std::pair, + absl::optional>> +ConfigurationPacket::InitWithWords( + absl::Span words, + const ConfigurationPacket* 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 words, Opcode::NOP, ConfigurationRegister::CRC, {}}}}; - case 0x1: { + case TYPE1: { Opcode opcode = static_cast( bit_field_get(words[0], 28, 27)); ConfigurationRegister address = @@ -49,7 +53,7 @@ ConfigurationPacket::InitWithWords(absl::Span words, {{header_type, opcode, address, words.subspan(1, data_word_count)}}}; } - case 0x2: { + case TYPE2: { absl::optional packet; Opcode opcode = static_cast( bit_field_get(words[0], 28, 27)); @@ -76,16 +80,18 @@ ConfigurationPacket::InitWithWords(absl::Span words, } } -std::ostream& operator<<(std::ostream& o, const ConfigurationPacket& packet) { +template +std::ostream& operator<<(std::ostream& o, + const ConfigurationPacket& packet) { if (packet.header_type() == 0x0) { return o << "[Zero-pad]" << std::endl; } switch (packet.opcode()) { - case ConfigurationPacket::Opcode::NOP: + case ConfigurationPacket::Opcode::NOP: o << "[NOP]" << std::endl; break; - case ConfigurationPacket::Opcode::Read: + case ConfigurationPacket::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::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&); } // namespace xilinx } // namespace prjxray diff --git a/lib/xilinx/configuration_packetizer.cc b/lib/xilinx/configuration_packetizer.cc new file mode 100644 index 00000000..e25b3d3b --- /dev/null +++ b/lib/xilinx/configuration_packetizer.cc @@ -0,0 +1,162 @@ +#include +#include +#include + +namespace prjxray { +namespace xilinx { + +template +ConfigurationPacketizer::ConfigurationPacketizer( + const Configuration& config) + : config_(config) {} + +template +typename ConfigurationPacketizer::iterator +ConfigurationPacketizer::begin() const { + return iterator(&config_.part(), config_.frames().begin(), + config_.frames().end()); +} + +template +typename ConfigurationPacketizer::iterator +ConfigurationPacketizer::end() const { + return iterator(&config_.part(), config_.frames().end(), + config_.frames().end()); +} + +template +ConfigurationPacketizer::iterator::iterator( + const typename ArchType::Part* part, + typename Configuration::FrameMap::const_iterator begin, + typename Configuration::FrameMap::const_iterator end) + : part_(part), + state_(begin != end ? State::Start : State::Finished), + frame_cur_(begin), + frame_end_(end) { + this->operator++(); +} + +template +const ConfigurationPacket& + ConfigurationPacketizer::iterator::operator*() const { + return *packet_; +} + +template +const ConfigurationPacket* + ConfigurationPacketizer::iterator::operator->() const { + return &(*packet_); +} + +template +bool ConfigurationPacketizer::iterator::operator==( + const ConfigurationPacketizer::iterator& other) const { + return state_ == other.state_ && frame_cur_ == other.frame_cur_; +} + +template +bool ConfigurationPacketizer::iterator::operator!=( + const ConfigurationPacketizer::iterator& other) const { + return !(*this == other); +} + +template <> +typename ConfigurationPacketizer::iterator& + ConfigurationPacketizer::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(&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::ConfigurationPacketizer( + const Configuration& config); +template ConfigurationPacketizer::iterator +ConfigurationPacketizer::begin() const; +template ConfigurationPacketizer::iterator +ConfigurationPacketizer::end() const; +template const ConfigurationPacket& + ConfigurationPacketizer::iterator::operator*() const; +template const ConfigurationPacket* + ConfigurationPacketizer::iterator::operator->() const; +template bool ConfigurationPacketizer::iterator::operator==( + const ConfigurationPacketizer::iterator& other) const; +template bool ConfigurationPacketizer::iterator::operator!=( + const ConfigurationPacketizer::iterator& other) const; +} // namespace xilinx +} // namespace prjxray diff --git a/lib/xilinx/configuration_register.cc b/lib/xilinx/configuration_register.cc new file mode 100644 index 00000000..0935fa8a --- /dev/null +++ b/lib/xilinx/configuration_register.cc @@ -0,0 +1,55 @@ +#include + +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 diff --git a/lib/xilinx/xc7series/frames.cc b/lib/xilinx/frames.cc similarity index 52% rename from lib/xilinx/xc7series/frames.cc rename to lib/xilinx/frames.cc index e53f1d82..9ffd50cd 100644 --- a/lib/xilinx/xc7series/frames.cc +++ b/lib/xilinx/frames.cc @@ -1,18 +1,21 @@ #include #include +#include + +#include #include -#include namespace prjxray { namespace xilinx { -namespace xc7series { -Frames::Frames2Data& Frames::getFrames() { +template +typename Frames::Frames2Data& Frames::getFrames() { return frames_data_; } -int Frames::readFrames(const std::string& frm_file_str) { +template +int Frames::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 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(frm_addr, frame_data)); + std::pair( + frm_addr, frame_data)); } return 0; } -void Frames::addMissingFrames(const absl::optional& part) { +template +void Frames::addMissingFrames( + const absl::optional& part) { auto current_frame_address = - absl::optional(FrameAddress(0)); + absl::optional( + 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( - *current_frame_address, frame_data)); + FrameData frame_data(ArchType::words_per_frame, 0); + frames_data_.insert( + std::pair(*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::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::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::Frames2Data& Frames::getFrames(); +template void Frames::addMissingFrames( + const absl::optional& part); +template int Frames::readFrames(const std::string&); +template void Frames::updateECC(Frames::FrameData&); -} // namespace xc7series } // namespace xilinx } // namespace prjxray diff --git a/lib/xilinx/xc7series/bitstream_reader.cc b/lib/xilinx/xc7series/bitstream_reader.cc deleted file mode 100644 index b390f272..00000000 --- a/lib/xilinx/xc7series/bitstream_reader.cc +++ /dev/null @@ -1,71 +0,0 @@ -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -std::array BitstreamReader::kSyncWord{0xAA, 0x99, 0x55, 0x66}; - -BitstreamReader::BitstreamReader(std::vector&& 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 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(); - break; - } - - words_ = parse_result_.first; - parse_result_ = new_result; - } while (!parse_result_.first.empty() && !parse_result_.second); - - if (!parse_result_.second) { - words_ = absl::Span(); - } - - 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 diff --git a/lib/xilinx/xc7series/bitstream_writer.cc b/lib/xilinx/xc7series/bitstream_writer.cc deleted file mode 100644 index eb388ca5..00000000 --- a/lib/xilinx/xc7series/bitstream_writer.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* - * TODO - * -Finish type 1/2 support - * -Review sample bitstream padding. What are they for? - */ -#include - -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -// Per UG470 pg 80: Bus Width Auto Detection -std::array 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 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()); -} - -BitstreamWriter::iterator::iterator(header_t::iterator itr_header, - const packets_t& packets, - packets_t::const_iterator itr_packets, - absl::optional 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 diff --git a/lib/xilinx/xc7series/configuration_packetizer.cc b/lib/xilinx/xc7series/configuration_packetizer.cc deleted file mode 100644 index e7282bfd..00000000 --- a/lib/xilinx/xc7series/configuration_packetizer.cc +++ /dev/null @@ -1,128 +0,0 @@ -#include - -#include -#include - -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(&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 diff --git a/lib/xilinx/xc7series/configuration_register.cc b/lib/xilinx/xc7series/configuration_register.cc deleted file mode 100644 index 6337e4da..00000000 --- a/lib/xilinx/xc7series/configuration_register.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include - -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 diff --git a/lib/xilinx/xc7series/row.cc b/lib/xilinx/xc7series/configuration_row.cc similarity index 96% rename from lib/xilinx/xc7series/row.cc rename to lib/xilinx/xc7series/configuration_row.cc index 5f737164..39ef9f4f 100644 --- a/lib/xilinx/xc7series/row.cc +++ b/lib/xilinx/xc7series/configuration_row.cc @@ -1,4 +1,4 @@ -#include +#include namespace prjxray { namespace xilinx { diff --git a/lib/xilinx/xc7series/row_test.cc b/lib/xilinx/xc7series/row_test.cc index 2475f90b..e0c42f93 100644 --- a/lib/xilinx/xc7series/row_test.cc +++ b/lib/xilinx/xc7series/row_test.cc @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/lib/xilinx/xc7series/utils.cc b/lib/xilinx/xc7series/utils.cc deleted file mode 100644 index c8fae481..00000000 --- a/lib/xilinx/xc7series/utils.cc +++ /dev/null @@ -1,263 +0,0 @@ -#include -#include - -#include -#include -#include -#include -//#include - -#include -#include -#include -#include -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -PacketData createType2ConfigurationPacketData(const Frames::Frames2Data& frames, - absl::optional& 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) { - // 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(Command::NOP)})); - out_packets.emplace_back(new NopPacket()); - out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( - ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, - {static_cast(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(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(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(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(Command::GRESTORE)})); - out_packets.emplace_back(new NopPacket()); - out_packets.emplace_back(new ConfigurationPacketWithPayload<1>( - ConfigurationPacket::Opcode::Write, ConfigurationRegister::CMD, - {static_cast(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(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(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(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((build_source.size() + 1) >> 8)); - bit_header.push_back(static_cast(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((part_name.size() + 1) >> 8)); - bit_header.push_back(static_cast(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((build_date_string.size() + 1) >> 8)); - bit_header.push_back( - static_cast(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((build_time_string.size() + 1) >> 8)); - bit_header.push_back( - static_cast(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(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(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 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2fc35558..2ebadf19 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(xc7patch gflags libprjxray ) + add_executable(xc7frames2bit xc7frames2bit.cc) target_link_libraries(xc7frames2bit absl::strings diff --git a/tools/bitread.cc b/tools/bitread.cc index 8e4c7335..dfc7cc32 100644 --- a/tools/bitread.cc +++ b/tools/bitread.cc @@ -10,12 +10,11 @@ #include #include #include -#include #include #include -#include -#include -#include +#include +#include +#include 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 frames; uint32_t frame_range_begin = 0, frame_range_end = 0; std::vector zero_frame(101); +struct BitReader { + BitReader(const std::vector& bytes) : bytes_(bytes) {} + + const std::vector& bytes_; + + template + int operator()(T& arg) { + using ArchType = std::decay_t; + auto reader = + xilinx::BitstreamReader::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::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> pgmdata; + std::vector 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(it.first), + static_cast( + 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()); + + 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(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 reader; + std::vector 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( + static_cast(in_file->data()), + static_cast(in_file->data()) + in_file->size()); } else { - std::vector 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> pgmdata; - std::vector 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(it.first), - static_cast(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()); - - 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(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); } diff --git a/tools/bittool.cc b/tools/bittool.cc index a43e807c..7e513bb9 100644 --- a/tools/bittool.cc +++ b/tools/bittool.cc @@ -1,26 +1,56 @@ #include #include +#include #include #include #include #include -#include +#include +#include -namespace xc7series = prjxray::xilinx::xc7series; +namespace xilinx = prjxray::xilinx; struct Action { std::string name; std::function handler; }; +struct ConfigPacketsLister { + ConfigPacketsLister(const absl::Span& bytes) : bytes_(bytes) {} + + const absl::Span& bytes_; + + template + int operator()(T& arg) { + using ArchType = std::decay_t; + auto reader = + xilinx::BitstreamReader::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 " << 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( + static_cast(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& bytes) + : bytes_(bytes) {} + + const absl::Span& bytes_; + + template + int operator()(T& arg) { + using ArchType = std::decay_t; + auto reader = + xilinx::BitstreamReader::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( static_cast(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 " - << std::endl; - return 1; - } +struct DeviceIdGetter { + DeviceIdGetter(const absl::Span& 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& bytes_; - auto in_bytes = absl::Span( - static_cast(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 + int operator()(T& arg) { + using ArchType = std::decay_t; + auto reader = + xilinx::BitstreamReader::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 []" << 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( + static_cast(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}, diff --git a/tools/gen_part_base_yaml.cc b/tools/gen_part_base_yaml.cc index a215e639..e5f965f2 100644 --- a/tools/gen_part_base_yaml.cc +++ b/tools/gen_part_base_yaml.cc @@ -11,15 +11,13 @@ #include #include #include -#include -#include -#include -#include +#include +#include #include 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::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 frame_addresses; + std::vector frame_addresses; absl::optional 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; diff --git a/tools/xc7frames2bit.cc b/tools/xc7frames2bit.cc index 554ca197..6b5c758f 100644 --- a/tools/xc7frames2bit.cc +++ b/tools/xc7frames2bit.cc @@ -1,7 +1,9 @@ #include #include -#include +#include +#include +#include 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: " " ,...,."); -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 + int operator()(T& arg) { + using ArchType = std::decay_t; + 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 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::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::PacketData + configuration_packet_data( + xilinx::Configuration:: + createType2ConfigurationPacketData( + frames.getFrames(), part)); + + // Put together a configuration package + typename ArchType::ConfigurationPackage configuration_package; + xilinx::Configuration::createConfigurationPackage( + configuration_package, configuration_packet_data, part); + + // Write bitstream + auto bitstream_writer = + xilinx::BitstreamWriter(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); } diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc index 9d030cb5..369ddac9 100644 --- a/tools/xc7patch.cc +++ b/tools/xc7patch.cc @@ -2,7 +2,10 @@ #include #include -#include +#include +#include +#include +#include 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: " " ,...,."); 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 int patch_frames( const std::string& frm_file_str, - std::map>* frames) { - xc7series::Frames frames_from_file; + std::map>* frames) { + xilinx::Frames 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 + int operator()(T& arg) { + using ArchType = std::decay_t; + 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::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::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> + 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 + typename xilinx::Configuration::PacketData + configuration_packet_data( + xilinx::Configuration:: + createType2ConfigurationPacketData(frames, part)); + + // Put together a configuration package + typename ArchType::ConfigurationPackage configuration_package; + xilinx::Configuration::createConfigurationPackage( + configuration_package, configuration_packet_data, part); + + // Write bitstream. + auto bitstream_writer = + xilinx::BitstreamWriter(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> 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); }