diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 8000b610..4a01fbec 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,7 +4,7 @@ add_library(libprjxray segbits_file_reader.cc xilinx/xc7series/bitstream_reader.cc xilinx/xc7series/block_type.cc - xilinx/xc7series/configuration_frame_address.cc + xilinx/xc7series/frame_address.cc xilinx/xc7series/configuration_frame_range.cc xilinx/xc7series/configuration_packet.cc xilinx/xc7series/configuration_register.cc @@ -50,19 +50,20 @@ if (PRJXRAY_BUILD_TESTING) add_test(NAME xilinx_xc7series_block_type_test COMMAND xilinx_xc7series_block_type_test) - add_executable(xilinx_xc7series_configuration_frame_address_test - xilinx/xc7series/configuration_frame_address_test.cc) - target_link_libraries(xilinx_xc7series_configuration_frame_address_test + add_executable(xilinx_xc7series_frame_address_test + xilinx/xc7series/frame_address_test.cc) + target_link_libraries(xilinx_xc7series_frame_address_test libprjxray gtest_main absl::span) - add_test(NAME xilinx_xc7series_configuration_frame_address_test - COMMAND xilinx_xc7series_configuration_frame_address_test) + add_test(NAME xilinx_xc7series_frame_address_test + COMMAND xilinx_xc7series_frame_address_test) add_executable(xilinx_xc7series_configuration_test xilinx/xc7series/configuration_test.cc) target_link_libraries(xilinx_xc7series_configuration_test libprjxray gtest_main absl::span) add_test(NAME xilinx_xc7series_configuration_test - COMMAND xilinx_xc7series_configuration_test) + COMMAND xilinx_xc7series_configuration_test + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data) add_executable(xilinx_xc7series_configuration_packet_test xilinx/xc7series/configuration_packet_test.cc) diff --git a/lib/include/prjxray/memory_mapped_file.h b/lib/include/prjxray/memory_mapped_file.h index 6ed4e4ec..c2fd955d 100644 --- a/lib/include/prjxray/memory_mapped_file.h +++ b/lib/include/prjxray/memory_mapped_file.h @@ -4,6 +4,8 @@ #include #include +#include + namespace prjxray { class MemoryMappedFile { @@ -16,6 +18,10 @@ class MemoryMappedFile { void* const data() const { return data_; } const size_t size() const { return size_; } + absl::Span as_bytes() const { + return {static_cast(data_), size_}; + } + private: MemoryMappedFile(void *data, size_t size) : data_(data), size_(size) {}; diff --git a/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h b/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h index 7b6ad034..fad41bde 100644 --- a/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h +++ b/lib/include/prjxray/xilinx/xc7series/bitstream_reader.h @@ -47,7 +47,7 @@ class BitstreamReader { // Construct a `BitstreamReader` from a Container of bytes. // Any bytes preceding an initial sync word are ignored. template - static absl::optional InitWithBytes(T &bitstream); + static absl::optional InitWithBytes(T bitstream); const std::vector &words() { return words_; }; @@ -62,7 +62,7 @@ class BitstreamReader { }; template -absl::optional BitstreamReader::InitWithBytes(T &bitstream) { +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(), diff --git a/lib/include/prjxray/xilinx/xc7series/configuration.h b/lib/include/prjxray/xilinx/xc7series/configuration.h index 8d9984a5..7fa643ab 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include namespace prjxray { @@ -15,7 +15,7 @@ namespace xc7series { class Configuration { public: - using FrameMap = std::map>; template @@ -46,7 +46,7 @@ absl::optional Configuration::InitWithPackets( // Internal state machine for writes. bool start_new_write = false; - ConfigurationFrameAddress current_frame_address = 0; + FrameAddress current_frame_address = 0; Configuration::FrameMap frames; for (auto packet : packets) { @@ -112,20 +112,24 @@ absl::optional Configuration::InitWithPackets( // 7-series frames are 101-words long. Writes to this // register can be multiples of that to do // auto-incrementing block writes. - int frames_written = packet.data().size() / - kWordsPerFrame; - - for (int ii = 0; ii < frames_written; ++ii) { + for (size_t ii = 0; + ii < packet.data().size(); + ii += kWordsPerFrame) { frames[current_frame_address] = packet.data().subspan( - ii * kWordsPerFrame, - kWordsPerFrame); - auto next_address = - part.GetNextConfigurationFrameAddress( + ii, kWordsPerFrame); + + auto next_address = part.GetNextFrameAddress( current_frame_address); - if (next_address) { - current_frame_address = *next_address; + if (!next_address) break; + + // Bitstreams appear to have 2 frames of + // padding between rows. + if (next_address->row_address() != + current_frame_address.row_address()) { + ii += 2 * kWordsPerFrame; } + current_frame_address = *next_address; } break; } diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_frame_address.h b/lib/include/prjxray/xilinx/xc7series/configuration_frame_address.h deleted file mode 100644 index fe5cb89c..00000000 --- a/lib/include/prjxray/xilinx/xc7series/configuration_frame_address.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_ -#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_ - -#include - -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -class ConfigurationFrameAddress { - public: - ConfigurationFrameAddress() - : address_(0) {} - - ConfigurationFrameAddress(uint32_t address) - : address_(address) {}; - - ConfigurationFrameAddress( - BlockType block_type, bool is_bottom_half_rows, - uint8_t row, uint16_t column, uint8_t minor); - - operator uint32_t() const { return address_; } - - BlockType block_type() const; - bool is_bottom_half_rows() const; - uint8_t row_address() const; - uint16_t column_address() const; - uint8_t minor_address() const; - - private: - uint32_t address_; -}; - -} // namespace xc7series -} // namespace xilinx -} // namespace prjxray - -namespace YAML { -template<> -struct convert { - static Node encode(const prjxray::xilinx::xc7series::ConfigurationFrameAddress &rhs); - static bool decode(const Node& node, - prjxray::xilinx::xc7series::ConfigurationFrameAddress &lhs); -}; -} // namespace YAML -#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_ADDRESS_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h b/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h index 97690d69..4445871b 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h @@ -3,7 +3,7 @@ #include -#include +#include #include namespace prjxray { @@ -14,21 +14,20 @@ class ConfigurationFrameRange { public: ConfigurationFrameRange() : begin_(0), end_(0) {} - ConfigurationFrameRange(ConfigurationFrameAddress begin, - ConfigurationFrameAddress end) + ConfigurationFrameRange(FrameAddress begin, FrameAddress end) : begin_(begin), end_(end) {}; - ConfigurationFrameAddress begin() const { return begin_; } - ConfigurationFrameAddress end() const { return end_; } + FrameAddress begin() const { return begin_; } + FrameAddress end() const { return end_; } size_t size() const { return end_ - begin_; } bool empty() const { return size() == 0; } - bool Contains(ConfigurationFrameAddress address) const; + bool Contains(FrameAddress address) const; private: - ConfigurationFrameAddress begin_; - ConfigurationFrameAddress end_; + FrameAddress begin_; + FrameAddress end_; }; } // namespace xc7series diff --git a/lib/include/prjxray/xilinx/xc7series/frame_address.h b/lib/include/prjxray/xilinx/xc7series/frame_address.h new file mode 100644 index 00000000..88ef7e82 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/frame_address.h @@ -0,0 +1,50 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_FRAME_ADDRESS_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_FRAME_ADDRESS_H_ + +#include +#include + +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +class FrameAddress { + public: + FrameAddress() : address_(0) {} + + FrameAddress(uint32_t address) + : address_(address) {}; + + FrameAddress(BlockType block_type, bool is_bottom_half_rows, + uint8_t row, uint16_t column, uint8_t minor); + + operator uint32_t() const { return address_; } + + BlockType block_type() const; + bool is_bottom_half_rows() const; + uint8_t row_address() const; + uint16_t column_address() const; + uint8_t minor_address() const; + + private: + uint32_t address_; +}; + +std::ostream &operator<<(std::ostream &o, const FrameAddress& addr); + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace YAML { +template<> +struct convert { + static Node encode(const prjxray::xilinx::xc7series::FrameAddress &rhs); + static bool decode(const Node& node, + prjxray::xilinx::xc7series::FrameAddress &lhs); +}; +} // namespace YAML +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_FRAME_ADDRESS_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/part.h b/lib/include/prjxray/xilinx/xc7series/part.h index 7d674f33..5ffe891d 100644 --- a/lib/include/prjxray/xilinx/xc7series/part.h +++ b/lib/include/prjxray/xilinx/xc7series/part.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include namespace prjxray { @@ -28,9 +28,8 @@ class Part { const std::vector& configuration_frame_ranges() const { return frame_ranges_; } - absl::optional - GetNextConfigurationFrameAddress( - ConfigurationFrameAddress address) const; + absl::optional + GetNextFrameAddress(FrameAddress address) const; private: uint32_t idcode_; diff --git a/lib/test_data/configuration_test.bit b/lib/test_data/configuration_test.bit new file mode 100644 index 00000000..6ef4f5ef Binary files /dev/null and b/lib/test_data/configuration_test.bit differ diff --git a/lib/test_data/configuration_test.debug.bit b/lib/test_data/configuration_test.debug.bit new file mode 100644 index 00000000..3dfd7482 Binary files /dev/null and b/lib/test_data/configuration_test.debug.bit differ diff --git a/lib/test_data/configuration_test.perframecrc.bit b/lib/test_data/configuration_test.perframecrc.bit new file mode 100644 index 00000000..7179e2d3 Binary files /dev/null and b/lib/test_data/configuration_test.perframecrc.bit differ diff --git a/lib/test_data/configuration_test.yaml b/lib/test_data/configuration_test.yaml new file mode 100644 index 00000000..2666355e --- /dev/null +++ b/lib/test_data/configuration_test.yaml @@ -0,0 +1,1680 @@ +! +idcode: 0x362c093 +configuration_ranges: + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 0 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 0 + minor: 42 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 1 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 1 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 2 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 2 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 3 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 3 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 4 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 4 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 5 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 5 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 6 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 6 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 7 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 7 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 8 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 8 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 9 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 9 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 10 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 10 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 11 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 11 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 12 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 12 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 13 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 13 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 14 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 14 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 15 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 15 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 16 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 16 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 17 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 17 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 18 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 18 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 19 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 19 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 20 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 20 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 21 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 21 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 22 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 22 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 23 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 23 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 24 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 24 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 25 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 25 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 26 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 26 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 27 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 27 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 28 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 28 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 29 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 29 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 30 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 30 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 31 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 31 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 32 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 32 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 33 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 33 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 34 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 34 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 35 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 35 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 36 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 36 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 37 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 37 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 38 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 38 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 39 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 39 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 40 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 40 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 41 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 41 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 42 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 42 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 43 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 0 + column: 43 + minor: 42 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 0 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 0 + minor: 42 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 1 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 1 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 2 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 2 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 3 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 3 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 4 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 4 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 5 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 5 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 6 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 6 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 7 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 7 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 8 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 8 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 9 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 9 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 10 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 10 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 11 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 11 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 12 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 12 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 13 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 13 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 14 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 14 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 15 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 15 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 16 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 16 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 17 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 17 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 18 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 18 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 19 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 19 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 20 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 20 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 21 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 21 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 22 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 22 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 23 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 23 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 24 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 24 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 25 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 25 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 26 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 26 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 27 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 27 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 28 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 28 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 29 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 29 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 30 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 30 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 31 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 31 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 32 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 32 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 33 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 33 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 34 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 34 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 35 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 35 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 36 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 36 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 37 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: top + row: 1 + column: 37 + minor: 32 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 0 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 0 + minor: 42 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 1 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 1 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 2 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 2 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 3 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 3 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 4 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 4 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 5 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 5 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 6 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 6 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 7 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 7 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 8 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 8 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 9 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 9 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 10 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 10 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 11 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 11 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 12 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 12 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 13 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 13 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 14 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 14 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 15 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 15 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 16 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 16 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 17 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 17 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 18 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 18 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 19 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 19 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 20 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 20 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 21 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 21 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 22 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 22 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 23 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 23 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 24 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 24 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 25 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 25 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 26 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 26 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 27 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 27 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 28 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 28 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 29 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 29 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 30 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 30 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 31 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 31 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 32 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 32 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 33 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 33 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 34 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 34 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 35 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 35 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 36 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 36 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 37 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 37 + minor: 28 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 38 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 38 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 39 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 39 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 40 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 40 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 41 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 41 + minor: 36 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 42 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 42 + minor: 30 + - ! + begin: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 43 + minor: 0 + end: ! + block_type: CLB_IO_CLK + row_half: bottom + row: 0 + column: 43 + minor: 42 + - ! + begin: ! + block_type: BLOCK_RAM + row_half: top + row: 0 + column: 0 + minor: 0 + end: ! + block_type: BLOCK_RAM + row_half: top + row: 0 + column: 3 + minor: 0 + - ! + begin: ! + block_type: BLOCK_RAM + row_half: top + row: 1 + column: 0 + minor: 0 + end: ! + block_type: BLOCK_RAM + row_half: top + row: 1 + column: 2 + minor: 0 + - ! + begin: ! + block_type: BLOCK_RAM + row_half: bottom + row: 0 + column: 0 + minor: 0 + end: ! + block_type: BLOCK_RAM + row_half: bottom + row: 0 + column: 3 + minor: 0 diff --git a/lib/xilinx/xc7series/configuration_frame_range.cc b/lib/xilinx/xc7series/configuration_frame_range.cc index 9113005d..b4f73a5f 100644 --- a/lib/xilinx/xc7series/configuration_frame_range.cc +++ b/lib/xilinx/xc7series/configuration_frame_range.cc @@ -4,8 +4,7 @@ namespace prjxray { namespace xilinx { namespace xc7series { -bool ConfigurationFrameRange::Contains( - ConfigurationFrameAddress address) const { +bool ConfigurationFrameRange::Contains(FrameAddress address) const { return address >= begin_ && address < end_; } @@ -34,8 +33,8 @@ bool convert::decode( !node["end"]) return false; lhs = xc7series::ConfigurationFrameRange( - node["begin"].as(), - node["end"].as()); + node["begin"].as(), + node["end"].as()); return true; } diff --git a/lib/xilinx/xc7series/configuration_test.cc b/lib/xilinx/xc7series/configuration_test.cc index a1f2a623..62d8facc 100644 --- a/lib/xilinx/xc7series/configuration_test.cc +++ b/lib/xilinx/xc7series/configuration_test.cc @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -106,6 +107,106 @@ TEST(ConfigurationTest, ConstructFromPacketsWithAutoincrement) { absl::Span frame_span(frame); EXPECT_EQ(test_config->part().idcode(), static_cast(0x1234)); EXPECT_EQ(test_config->frames().size(), static_cast(2)); - EXPECT_EQ(test_config->frames().at(0x456F), frame_span.subspan(0, 101)); - EXPECT_EQ(test_config->frames().at(0x4580), frame_span.subspan(101)); + EXPECT_EQ(test_config->frames().at(0x456F), std::vector(101, 0xAA)); + EXPECT_EQ(test_config->frames().at(0x4580), std::vector(101, 0xBB)); +} + +TEST(ConfigurationTest, DebugAndPerFrameCrcBitstreamsProduceEqualConfigurations) { + auto part = xc7series::Part::FromFile("configuration_test.yaml"); + ASSERT_TRUE(part); + + auto debug_bitstream = prjxray::MemoryMappedFile::InitWithFile( + "configuration_test.debug.bit"); + ASSERT_TRUE(debug_bitstream); + + auto debug_reader = xc7series::BitstreamReader::InitWithBytes( + debug_bitstream->as_bytes()); + ASSERT_TRUE(debug_reader); + + auto debug_configuration = xc7series::Configuration::InitWithPackets( + *part, *debug_reader); + ASSERT_TRUE(debug_configuration); + + auto perframecrc_bitstream = prjxray::MemoryMappedFile::InitWithFile( + "configuration_test.perframecrc.bit"); + ASSERT_TRUE(perframecrc_bitstream); + + auto perframecrc_reader = xc7series::BitstreamReader::InitWithBytes( + perframecrc_bitstream->as_bytes()); + ASSERT_TRUE(perframecrc_reader); + + auto perframecrc_configuration = xc7series::Configuration::InitWithPackets( + *part, *perframecrc_reader); + ASSERT_TRUE(perframecrc_configuration); + + for (auto debug_frame : debug_configuration->frames()) { + auto perframecrc_frame = perframecrc_configuration->frames().find(debug_frame.first); + if (perframecrc_frame == perframecrc_configuration->frames().end()) { + ADD_FAILURE() << debug_frame.first << ": missing in perframecrc bitstream"; + continue; + } + + for (int ii = 0; ii < 101; ++ii) { + EXPECT_EQ(perframecrc_frame->second[ii], debug_frame.second[ii]) + << debug_frame.first << ": word " << ii; + } + } + + for (auto perframecrc_frame : perframecrc_configuration->frames()) { + auto debug_frame = debug_configuration->frames().find(perframecrc_frame.first); + if (debug_frame == debug_configuration->frames().end()) { + ADD_FAILURE() << perframecrc_frame.first + << ": unexpectedly present in perframecrc bitstream"; + } + } +} + +TEST(ConfigurationTest, DebugAndNormalBitstreamsProduceEqualConfigurations) { + auto part = xc7series::Part::FromFile("configuration_test.yaml"); + ASSERT_TRUE(part); + + auto debug_bitstream = prjxray::MemoryMappedFile::InitWithFile( + "configuration_test.debug.bit"); + ASSERT_TRUE(debug_bitstream); + + auto debug_reader = xc7series::BitstreamReader::InitWithBytes( + debug_bitstream->as_bytes()); + ASSERT_TRUE(debug_reader); + + auto debug_configuration = xc7series::Configuration::InitWithPackets( + *part, *debug_reader); + ASSERT_TRUE(debug_configuration); + + auto normal_bitstream = prjxray::MemoryMappedFile::InitWithFile( + "configuration_test.bit"); + ASSERT_TRUE(normal_bitstream); + + auto normal_reader = xc7series::BitstreamReader::InitWithBytes( + normal_bitstream->as_bytes()); + ASSERT_TRUE(normal_reader); + + auto normal_configuration = xc7series::Configuration::InitWithPackets( + *part, *normal_reader); + ASSERT_TRUE(normal_configuration); + + for (auto debug_frame : debug_configuration->frames()) { + auto normal_frame = normal_configuration->frames().find(debug_frame.first); + if (normal_frame == normal_configuration->frames().end()) { + ADD_FAILURE() << debug_frame.first << ": missing in normal bitstream"; + continue; + } + + for (int ii = 0; ii < 101; ++ii) { + EXPECT_EQ(normal_frame->second[ii], debug_frame.second[ii]) + << debug_frame.first << ": word " << ii; + } + } + + for (auto normal_frame : normal_configuration->frames()) { + auto debug_frame = debug_configuration->frames().find(normal_frame.first); + if (debug_frame == debug_configuration->frames().end()) { + ADD_FAILURE() << normal_frame.first + << ": unexpectedly present in normal bitstream"; + } + } } diff --git a/lib/xilinx/xc7series/configuration_frame_address.cc b/lib/xilinx/xc7series/frame_address.cc similarity index 53% rename from lib/xilinx/xc7series/configuration_frame_address.cc rename to lib/xilinx/xc7series/frame_address.cc index 5bcf48af..4f885816 100644 --- a/lib/xilinx/xc7series/configuration_frame_address.cc +++ b/lib/xilinx/xc7series/frame_address.cc @@ -1,4 +1,6 @@ -#include +#include + +#include #include @@ -6,10 +8,8 @@ namespace prjxray { namespace xilinx { namespace xc7series { - -ConfigurationFrameAddress::ConfigurationFrameAddress( - BlockType block_type, bool is_bottom_half_rows, - uint8_t row, uint16_t column, uint8_t minor) { +FrameAddress::FrameAddress(BlockType block_type, bool is_bottom_half_rows, + uint8_t row, uint16_t column, uint8_t minor) { address_ = bit_field_set(0, 25, 23, block_type); address_ = bit_field_set(address_, 22, 22, is_bottom_half_rows); address_ = bit_field_set(address_, 21, 17, row); @@ -17,26 +17,46 @@ ConfigurationFrameAddress::ConfigurationFrameAddress( address_ = bit_field_set(address_, 6, 0, minor); } -BlockType ConfigurationFrameAddress::block_type() const { +BlockType FrameAddress::block_type() const { return static_cast(bit_field_get(address_, 25, 23)); } -bool ConfigurationFrameAddress::is_bottom_half_rows() const { +bool FrameAddress::is_bottom_half_rows() const { return bit_field_get(address_, 22, 22); } -uint8_t ConfigurationFrameAddress::row_address() const { +uint8_t FrameAddress::row_address() const { return bit_field_get(address_, 21, 17); } -uint16_t ConfigurationFrameAddress::column_address() const { +uint16_t FrameAddress::column_address() const { return bit_field_get(address_, 16, 7); } -uint8_t ConfigurationFrameAddress::minor_address() const { +uint8_t FrameAddress::minor_address() const { return bit_field_get(address_, 6, 0); } +std::ostream &operator<<(std::ostream &o, const FrameAddress& addr) { + o << "[" + << std::hex << std::showbase << std::setw(10) + << static_cast(addr) + << "] " + << (addr.is_bottom_half_rows() ? "BOTTOM" : "TOP") + << " Row=" + << std::setw(2) << std::dec + << static_cast(addr.row_address()) + << " Column=" + << std::setw(2) << std::dec + << addr.column_address() + << " Minor=" + << std::setw(2) << std::dec + << static_cast(addr.minor_address()) + << " Type=" + << addr.block_type(); + return o; +} + } // namespace xc7series } // namespace xilinx } // namespace prjxray @@ -45,10 +65,10 @@ namespace YAML { namespace xc7series = prjxray::xilinx::xc7series; -Node convert::encode( - const xc7series::ConfigurationFrameAddress &rhs) { +Node convert::encode( + const xc7series::FrameAddress &rhs) { Node node; - node.SetTag("xilinx/xc7series/configuration_frame_address"); + node.SetTag("xilinx/xc7series/frame_address"); node["block_type"] = rhs.block_type(); node["row_half"] = (rhs.is_bottom_half_rows() ? "bottom" : "top"); node["row"] = static_cast(rhs.row_address()); @@ -57,9 +77,10 @@ Node convert::encode( return node; } -bool convert::decode( - const Node &node, xc7series::ConfigurationFrameAddress &lhs) { - if (node.Tag() != "xilinx/xc7series/configuration_frame_address" || +bool convert::decode( + const Node &node, xc7series::FrameAddress &lhs) { + if (!(node.Tag() == "xilinx/xc7series/frame_address" || + node.Tag() == "xilinx/xc7series/configuration_frame_address") || !node["block_type"] || !node["row_half"] || !node["row"] || @@ -75,7 +96,7 @@ bool convert::decode( return false; } - lhs = prjxray::xilinx::xc7series::ConfigurationFrameAddress( + lhs = prjxray::xilinx::xc7series::FrameAddress( node["block_type"].as(), row_half, node["row"].as(), diff --git a/lib/xilinx/xc7series/configuration_frame_address_test.cc b/lib/xilinx/xc7series/frame_address_test.cc similarity index 60% rename from lib/xilinx/xc7series/configuration_frame_address_test.cc rename to lib/xilinx/xc7series/frame_address_test.cc index 3574b488..b44f5736 100644 --- a/lib/xilinx/xc7series/configuration_frame_address_test.cc +++ b/lib/xilinx/xc7series/frame_address_test.cc @@ -1,17 +1,16 @@ -#include +#include #include namespace xc7series = prjxray::xilinx::xc7series; -TEST(ConfigurationFrameAddressTest, YamlEncode) { - xc7series::ConfigurationFrameAddress address( - xc7series::BlockType::BLOCK_RAM, - false, 10, 0, 5); +TEST(FrameAddressTest, YamlEncode) { + xc7series::FrameAddress address(xc7series::BlockType::BLOCK_RAM, + false, 10, 0, 5); YAML::Node node(address); - EXPECT_EQ(node.Tag(), "xilinx/xc7series/configuration_frame_address"); + EXPECT_EQ(node.Tag(), "xilinx/xc7series/frame_address"); EXPECT_EQ(node["block_type"].as(), "BLOCK_RAM"); EXPECT_EQ(node["row_half"].as(), "top"); EXPECT_EQ(node["row"].as(), "10"); @@ -19,17 +18,17 @@ TEST(ConfigurationFrameAddressTest, YamlEncode) { EXPECT_EQ(node["minor"].as(), "5"); } -TEST(ConfigurationFrameAddressTest, YamlDecode) { +TEST(FrameAddressTest, YamlDecode) { YAML::Node node; - node.SetTag("xilinx/xc7series/configuration_frame_address"); + node.SetTag("xilinx/xc7series/frame_address"); node["block_type"] = "BLOCK_RAM"; node["row_half"] = "bottom"; node["row"] = "0"; node["column"] = "5"; node["minor"] = "11"; - xc7series::ConfigurationFrameAddress address = - node.as(); + xc7series::FrameAddress address = + node.as(); EXPECT_EQ(address.block_type(), xc7series::BlockType::BLOCK_RAM); EXPECT_TRUE(address.is_bottom_half_rows()); EXPECT_EQ(address.row_address(), 0); diff --git a/lib/xilinx/xc7series/part.cc b/lib/xilinx/xc7series/part.cc index 456565af..448b6cc6 100644 --- a/lib/xilinx/xc7series/part.cc +++ b/lib/xilinx/xc7series/part.cc @@ -16,16 +16,16 @@ absl::optional Part::FromFile(const std::string &path) { } } -absl::optional -Part::GetNextConfigurationFrameAddress(ConfigurationFrameAddress address) const { +absl::optional +Part::GetNextFrameAddress(FrameAddress address) const { // Start with the next linear address. - ConfigurationFrameAddress target_address(address + 1); + FrameAddress target_address(address + 1); // The address space is non-continguous. If the next linear address // happens to fall in a valid range, that's the next address. // Otherwise, find the closest valid range and use it's beginning // address. - absl::optional closest_address; + absl::optional closest_address; int32_t closest_distance; for (auto iter = frame_ranges_.begin(); iter != frame_ranges_.end(); diff --git a/lib/xilinx/xc7series/part_test.cc b/lib/xilinx/xc7series/part_test.cc index 0c65d7de..45c8c701 100644 --- a/lib/xilinx/xc7series/part_test.cc +++ b/lib/xilinx/xc7series/part_test.cc @@ -11,7 +11,7 @@ TEST(PartTest, GetNextAddressWhereNextIsInValidRange) { xc7series::Part part(0x1234, ranges); - auto next_address = part.GetNextConfigurationFrameAddress(0x4); + auto next_address = part.GetNextFrameAddress(0x4); EXPECT_TRUE(next_address); EXPECT_EQ(static_cast(0x5), *next_address); } @@ -23,7 +23,7 @@ TEST(PartTest, GetNextAddressWhereNextIsBetweenRanges) { xc7series::Part part(0x1234, ranges); - auto next_address = part.GetNextConfigurationFrameAddress(0xF); + auto next_address = part.GetNextFrameAddress(0xF); EXPECT_TRUE(next_address); EXPECT_EQ(static_cast(0x20), *next_address); } @@ -35,6 +35,6 @@ TEST(PartTest, GetNextAddressWhereNextWouldBePastLastRange) { xc7series::Part part(0x1234, ranges); - auto next_address = part.GetNextConfigurationFrameAddress(0x2F); + auto next_address = part.GetNextFrameAddress(0x2F); EXPECT_FALSE(next_address); } diff --git a/minitests/roi_harness/.gitignore b/minitests/roi_harness/.gitignore new file mode 100644 index 00000000..82a01aa0 --- /dev/null +++ b/minitests/roi_harness/.gitignore @@ -0,0 +1,8 @@ +/.Xil +/design/ +/design.bit +/design.bits +/design.dcp +/usage_statistics_webtalk.* +/vivado* +/design.txt diff --git a/minitests/roi_harness/Makefile b/minitests/roi_harness/Makefile new file mode 100644 index 00000000..e9e022b0 --- /dev/null +++ b/minitests/roi_harness/Makefile @@ -0,0 +1,8 @@ +all: + bash runme.sh + +clean: + rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit design.txt .Xil + +.PHONY: all clean + diff --git a/minitests/roi_harness/README.txt b/minitests/roi_harness/README.txt new file mode 100644 index 00000000..c8fe8978 --- /dev/null +++ b/minitests/roi_harness/README.txt @@ -0,0 +1,12 @@ +Creates an ROI with clk, inputs, and outputs to use as a partial reconfiguration test harness + +Basic idea: +-LOC LUTs in the ROI to terminate input and output routing +-Let Vivado LOC the rest of the logic +-Manually route signals in and out of the ROI enough to avoid routing loops into the ROI +-Let Vivado finish the rest of the routes + +There is no logic outside of the ROI in order to keep IOB to ROI delays short +Its expected the end user will rip out everything inside the ROI + +To target Arty A7 you should source the artix DB environment script then source arty.sh diff --git a/minitests/roi_harness/arty.sh b/minitests/roi_harness/arty.sh new file mode 100644 index 00000000..2b9b208c --- /dev/null +++ b/minitests/roi_harness/arty.sh @@ -0,0 +1 @@ +export XRAY_PART=xc7a35tcsg324-1 diff --git a/minitests/roi_harness/runme.sh b/minitests/roi_harness/runme.sh new file mode 100644 index 00000000..149ec619 --- /dev/null +++ b/minitests/roi_harness/runme.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +set -ex +vivado -mode batch -source runme.tcl +test -z "$(fgrep CRITICAL vivado.log)" + diff --git a/minitests/roi_harness/runme.tcl b/minitests/roi_harness/runme.tcl new file mode 100644 index 00000000..5b95f719 --- /dev/null +++ b/minitests/roi_harness/runme.tcl @@ -0,0 +1,273 @@ +# WARNING: this is somewhat paramaterized, but is only tested on A50T/A35T with the traditional ROI +# Your ROI should at least have a SLICEL on the left + +set DIN_N 8 +set DOUT_N 8 +# X12 in the ROI, X10 just to the left +# Start at bottom left of ROI and work up +# (IOs are to left) +# SLICE_X12Y100:SLICE_X27Y149 +# set X_BASE 12 +set X_BASE [lindex [split [lindex [split "$::env(XRAY_ROI)" Y] 0] X] 1] +set Y_BASE [lindex [split [lindex [split "$::env(XRAY_ROI)" Y] 1] :] 0] +# set Y_DIN_BASE 100 +set Y_CLK_BASE $Y_BASE +# Clock lut in middle +set Y_DIN_BASE [expr "$Y_CLK_BASE + 1"] +set Y_DOUT_BASE [expr "$Y_DIN_BASE + $DIN_N"] + +puts "Environment" +puts " XRAY_ROI: $::env(XRAY_ROI)" +puts " X_BASE: $X_BASE" +puts " Y_DIN_BASE: $Y_DIN_BASE" +puts " Y_CLK_BASE: $Y_CLK_BASE" +puts " Y_DOUT_BASE: $Y_DOUT_BASE" + +source ../../utils/utils.tcl + +create_project -force -part $::env(XRAY_PART) design design +read_verilog top.v +# added flatten_hierarchy +# dout_shr was getting folded into the pblock +# synth_design -top top -flatten_hierarchy none -no_lc -keep_equivalent_registers -resource_sharing off +synth_design -top top -flatten_hierarchy none -verilog_define DIN_N=$DIN_N -verilog_define DOUT_N=$DOUT_N + +# TODO: find a way to more automatically assign these? +# Sequential I/O Bank 16 layout +set part "$::env(XRAY_PART)" +if {$part eq "xc7a50tfgg484-1"} { + # Partial list, expand as needed + set bank_16 "F21 G22 G21 D21 E21 D22 E22 A21 B21 B22 C22 C20 D20 F20 F19 A19 A18" + set banki 0 + + # CLK + set pin [lindex $bank_16 $banki] + incr banki + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports "clk"] + + # DIN + for {set j 0} {$j < $DIN_N} {incr j} { + set pin [lindex $bank_16 $banki] + incr banki + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports "din[$j]"] + } + + # DOUT + for {set j 0} {$j < $DOUT_N} {incr j} { + set pin [lindex $bank_16 $banki] + incr banki + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports "dout[$j]"] + } +# Arty A7 optimized I/O layout +} elseif {$part eq "xc7a35tcsg324-1"} { + # https://reference.digilentinc.com/reference/programmable-logic/arty/reference-manual?redirect=1 + set pmod_ja "G13 B11 A11 D12 D13 B18 A18 K16" + set pmod_jb "E15 E16 D15 C15 J17 J18 K15 J15" + set pmod_jc "U12 V12 V10 V11 U14 V14 T13 U13" + + # CLK on Pmod JA + set pin [lindex $pmod_ja 0] + set_property -dict "PACKAGE_PIN G13 IOSTANDARD LVCMOS33" [get_ports "clk"] + + # DIN on Pmod JB + for {set i 0} {$i < $DIN_N} {incr i} { + set pin [lindex $pmod_jb $i] + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports "din[$i]"] + } + + # DOUT on Pmod JC + for {set i 0} {$i < $DOUT_N} {incr i} { + set pin [lindex $pmod_jc $i] + set_property -dict "PACKAGE_PIN $pin IOSTANDARD LVCMOS33" [get_ports "dout[$i]"] + } +} else { + error "Unsupported part $part" +} + +create_pblock roi +set_property EXCLUDE_PLACEMENT 1 [get_pblocks roi] +add_cells_to_pblock [get_pblocks roi] [get_cells roi] +resize_pblock [get_pblocks roi] -add "$::env(XRAY_ROI)" + +set_property CFGBVS VCCO [current_design] +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design] + +set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk_IBUF] + +#write_checkpoint -force synth.dcp + + + +proc loc_roi_clk_left {ff_x ff_y} { + # Place an ROI clk on the left edge of the ROI + # It doesn't actually matter where we place this, just do it to keep things neat looking + # ff_x: ROI SLICE X position + # ff_yy: row primitives will be placed at + + set slice_ff "SLICE_X${ff_x}Y${ff_y}" + + # Fix FFs to guide route in + set cell [get_cells "roi/clk_reg_reg"] + set_property LOC $slice_ff $cell + set_property BEL AFF $cell +} + +proc loc_roi_in_left {index lut_x y} { + # Place an ROI input on the left edge of the ROI + # index: input bus index + # lut_x: ROI SLICE X position. FF position is implicit to left + # y: row primitives will be placed at + + set slice_lut "SLICE_X${lut_x}Y${y}" + + # Fix LUTs near the edge + set cell [get_cells "roi/ins[$index].lut"] + set_property LOC $slice_lut $cell + set_property BEL A6LUT $cell +} + +proc loc_roi_out_left {index lut_x y} { + # Place an ROI output on the left edge of the ROI + # index: input bus index + # lut_x: ROI SLICE X position. FF position is implicit to left + # y: row primitives will be placed at + + set slice_lut "SLICE_X${lut_x}Y${y}" + + # Fix LUTs near the edge + set cell [get_cells "roi/outs[$index].lut"] + set_property LOC $slice_lut $cell + set_property BEL A6LUT $cell +} + + +if {1} { + set x $X_BASE + + # Place ROI clock right after inputs + puts "Placing ROI clock" + loc_roi_clk_left $x $Y_CLK_BASE + + # Place ROI inputs + puts "Placing ROI inputs" + set y $Y_DIN_BASE + for {set i 0} {$i < $DIN_N} {incr i} { + loc_roi_in_left $i $x $y + set y [expr {$y + 1}] + } + + # Place ROI outputs + set y $Y_DOUT_BASE + puts "Placing ROI outputs" + for {set i 0} {$i < $DOUT_N} {incr i} { + loc_roi_out_left $i $x $y + set y [expr {$y + 1}] + } +} + +place_design +#write_checkpoint -force placed.dcp + +# Version with more error checking for missing end node +# Will do best effort in this case +proc route_via2 {net nodes} { + # net: net as string + # nodes: string list of one or more intermediate routing nodes to visit + + set net [get_nets $net] + # Start at the net source + set fixed_route [get_nodes -of_objects [get_site_pins -filter {DIRECTION == OUT} -of_objects $net]] + # End at the net destination + # For sone reason this doesn't always show up + set site_pins [get_site_pins -filter {DIRECTION == IN} -of_objects $net] + if {$site_pins eq ""} { + puts "WARNING: could not find end node" + #error "Could not find end node" + } else { + set end_node [get_nodes -of_objects] + lappend nodes [$end_node] + } + + puts "" + puts "Routing net $net:" + + foreach to_node $nodes { + if {$to_node eq ""} { + error "Empty node" + } + + # Node string to object + set to_node [get_nodes -of_objects [get_wires $to_node]] + # Start at last routed position + set from_node [lindex $fixed_route end] + # Let vivado do heavy liftin in between + set route [find_routing_path -quiet -from $from_node -to $to_node] + if {$route == ""} { + # Some errors print a huge route + puts [concat [string range " $from_node -> $to_node" 0 1000] ": no route found - assuming direct PIP"] + lappend fixed_route $to_node + } { + puts [concat [string range " $from_node -> $to_node: $route" 0 1000] "routed"] + set fixed_route [concat $fixed_route [lrange $route 1 end]] + } + set_property -quiet FIXED_ROUTE $fixed_route $net + } + + set_property -quiet FIXED_ROUTE $fixed_route $net + puts "" +} + +# XXX: maybe add IOB? +set fp [open "design.txt" w] +puts $fp "name node" +if {1} { + set x $X_BASE + + # Nothing needed for clk + # It will go to high level interconnect that goes everywhere + + puts "Routing ROI inputs" + # Arbitrary offset as observed + set y [expr {$Y_DIN_BASE - 1}] + for {set i 0} {$i < $DIN_N} {incr i} { + #route_via2 "din_IBUF[$i]" "INT_R_X9Y${y}/NE2BEG3" + # needed to force routes away to avoid looping into ROI + #set x_EE2BEG3 [expr {$x - 2}] + set x_EE2BEG3 7 + set x_NE2BEG3 9 + set node "INT_R_X${x_NE2BEG3}Y${y}/NE2BEG3" + route_via2 "din_IBUF[$i]" "INT_R_X${x_EE2BEG3}Y${y}/EE2BEG3 $node" + puts $fp "din[$i] $node" + + set y [expr {$y + 1}] + } + + puts "Routing ROI outputs" + # Arbitrary offset as observed + set y [expr {$Y_DOUT_BASE + 0}] + for {set i 0} {$i < $DOUT_N} {incr i} { + # XXX: find a better solution if we need harness long term + # works on 50t but not 35t + if {$part eq "xc7a50tfgg484-1"} { + set node "INT_L_X10Y${y}/WW2BEG0" + route_via2 "roi/dout[$i]" "$node" + # works on 35t but not 50t + } elseif {$part eq "xc7a35tcsg324-1"} { + set node "INT_L_X10Y${y}/SW6BEG0" + route_via2 "roi/dout[$i]" "$node" + } else { + error "Unsupported part $part" + } + puts $fp "dout[$i] $node" + set y [expr {$y + 1}] + } +} +close $fp + +puts "routing design" +route_design + +write_checkpoint -force design.dcp +write_bitstream -force design.bit + diff --git a/minitests/roi_harness/top.v b/minitests/roi_harness/top.v new file mode 100644 index 00000000..efe551fe --- /dev/null +++ b/minitests/roi_harness/top.v @@ -0,0 +1,65 @@ +//See README and tcl for more info + +`ifndef DIN_N +`define DIN_N 4 +`endif + +`ifndef DOUT_N +`define DOUT_N 4 +`endif + +module top(input wire clk, + input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); + parameter DIN_N = `DIN_N; + parameter DOUT_N = `DOUT_N; + + roi #(.DIN_N(DIN_N), .DOUT_N(DOUT_N)) roi ( + .clk(clk), + .din(din), .dout(dout)); +endmodule + +module roi(input clk, + input [DIN_N-1:0] din, output [DOUT_N-1:0] dout); + parameter DIN_N = 4; + parameter DOUT_N = 4; + + genvar i; + generate + //CLK + (* KEEP, DONT_TOUCH *) + reg clk_reg; + always @(posedge clk) begin + clk_reg <= clk_reg; + end + + //DIN + for (i = 0; i < DIN_N; i = i+1) begin:ins + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(din[i]), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O()); + end + + //DOUT + for (i = 0; i < DOUT_N; i = i+1) begin:outs + (* KEEP, DONT_TOUCH *) + LUT6 #( + .INIT(64'b01) + ) lut ( + .I0(1'b0), + .I1(1'b0), + .I2(1'b0), + .I3(1'b0), + .I4(1'b0), + .I5(1'b0), + .O(dout[i])); + end + endgenerate +endmodule diff --git a/tools/bitread.cc b/tools/bitread.cc index 3b81b57c..e00b4b24 100644 --- a/tools/bitread.cc +++ b/tools/bitread.cc @@ -78,10 +78,8 @@ int main(int argc, char **argv) { std::cout << "Bitstream size: " << in_file->size() << " bytes" << std::endl; - auto in_bytes = absl::Span( - static_cast(in_file->data()), - in_file->size()); - reader = xc7series::BitstreamReader::InitWithBytes(in_bytes); + reader = xc7series::BitstreamReader::InitWithBytes( + in_file->as_bytes()); } else { std::vector bitdata; while (1) { diff --git a/tools/bittool.cc b/tools/bittool.cc index 9bcd039c..38fb8800 100644 --- a/tools/bittool.cc +++ b/tools/bittool.cc @@ -31,10 +31,8 @@ int ListConfigPackets(int argc, char *argv[]) { return 1; } - auto in_bytes = absl::Span( - static_cast(in_file->data()), - in_file->size()); - auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes); + auto reader = xc7series::BitstreamReader::InitWithBytes( + in_file->as_bytes()); if (!reader) { std::cerr << "Input doesn't look like a bitstream" << std::endl; diff --git a/tools/frame_address_decoder.cc b/tools/frame_address_decoder.cc index 858c7232..c4a64618 100644 --- a/tools/frame_address_decoder.cc +++ b/tools/frame_address_decoder.cc @@ -2,7 +2,7 @@ #include #include -#include +#include namespace xc7series = prjxray::xilinx::xc7series; @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) { for (uint32_t frame_address_raw; (*input_stream) >> std::setbase(0) >> frame_address_raw; ) { - xc7series::ConfigurationFrameAddress frame_address(frame_address_raw); + xc7series::FrameAddress frame_address(frame_address_raw); std::cout << "[" << std::hex << std::showbase << std::setw(10) << frame_address_raw diff --git a/tools/gen_part_base_yaml.cc b/tools/gen_part_base_yaml.cc index 41cfef07..79fe183b 100644 --- a/tools/gen_part_base_yaml.cc +++ b/tools/gen_part_base_yaml.cc @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -31,10 +30,8 @@ int main(int argc, char *argv[]) { return 1; } - auto in_bytes = absl::Span( - static_cast(in_file->data()), - in_file->size()); - auto reader = xc7series::BitstreamReader::InitWithBytes(in_bytes); + auto reader = xc7series::BitstreamReader::InitWithBytes( + in_file->as_bytes()); if (!reader) { std::cerr << "Input doesn't look like a bitstream" << std::endl;