From 53d7f1f80b997d71ee3c5ecf7fba58819f20950f Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Wed, 10 Jan 2018 12:56:44 -0800 Subject: [PATCH 1/3] lib: xc7series: shorten accessor names _address suffix on accessors is unnecessary and somewhat inaccurate. The returned values are indices rather than frame addresses. Signed-off-by: Rick Altherr --- .../prjxray/xilinx/xc7series/configuration.h | 5 ++-- .../prjxray/xilinx/xc7series/frame_address.h | 6 ++--- lib/xilinx/xc7series/frame_address.cc | 19 ++++++++------- lib/xilinx/xc7series/frame_address_test.cc | 6 ++--- tools/bitread.cc | 15 +++++------- tools/frame_address_decoder.cc | 23 ++++++++++--------- 6 files changed, 35 insertions(+), 39 deletions(-) diff --git a/lib/include/prjxray/xilinx/xc7series/configuration.h b/lib/include/prjxray/xilinx/xc7series/configuration.h index 6e1dfbc9..0258db12 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration.h @@ -137,9 +137,8 @@ absl::optional Configuration::InitWithPackets( // Bitstreams appear to have 2 frames of // padding between rows. - if (next_address->row_address() != - current_frame_address - .row_address()) { + if (next_address->row() != + current_frame_address.row()) { ii += 2 * kWordsPerFrame; } current_frame_address = *next_address; diff --git a/lib/include/prjxray/xilinx/xc7series/frame_address.h b/lib/include/prjxray/xilinx/xc7series/frame_address.h index 72ce6b34..e668034e 100644 --- a/lib/include/prjxray/xilinx/xc7series/frame_address.h +++ b/lib/include/prjxray/xilinx/xc7series/frame_address.h @@ -27,9 +27,9 @@ class FrameAddress { 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; + uint8_t row() const; + uint16_t column() const; + uint8_t minor() const; private: uint32_t address_; diff --git a/lib/xilinx/xc7series/frame_address.cc b/lib/xilinx/xc7series/frame_address.cc index 04bf71e2..a4ae2585 100644 --- a/lib/xilinx/xc7series/frame_address.cc +++ b/lib/xilinx/xc7series/frame_address.cc @@ -28,15 +28,15 @@ bool FrameAddress::is_bottom_half_rows() const { return bit_field_get(address_, 22, 22); } -uint8_t FrameAddress::row_address() const { +uint8_t FrameAddress::row() const { return bit_field_get(address_, 21, 17); } -uint16_t FrameAddress::column_address() const { +uint16_t FrameAddress::column() const { return bit_field_get(address_, 16, 7); } -uint8_t FrameAddress::minor_address() const { +uint8_t FrameAddress::minor() const { return bit_field_get(address_, 6, 0); } @@ -45,10 +45,9 @@ std::ostream& operator<<(std::ostream& o, const FrameAddress& addr) { << 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()) + << static_cast(addr.row()) << " Column=" << std::setw(2) + << std::dec << addr.column() << " Minor=" << std::setw(2) << std::dec + << static_cast(addr.minor()) << " Type=" << addr.block_type(); return o; } @@ -67,9 +66,9 @@ Node convert::encode( 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()); - node["column"] = static_cast(rhs.column_address()); - node["minor"] = static_cast(rhs.minor_address()); + node["row"] = static_cast(rhs.row()); + node["column"] = static_cast(rhs.column()); + node["minor"] = static_cast(rhs.minor()); return node; } diff --git a/lib/xilinx/xc7series/frame_address_test.cc b/lib/xilinx/xc7series/frame_address_test.cc index 85aae466..8e2bcc94 100644 --- a/lib/xilinx/xc7series/frame_address_test.cc +++ b/lib/xilinx/xc7series/frame_address_test.cc @@ -30,7 +30,7 @@ TEST(FrameAddressTest, YamlDecode) { 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); - EXPECT_EQ(address.column_address(), 5); - EXPECT_EQ(address.minor_address(), 11); + EXPECT_EQ(address.row(), 0); + EXPECT_EQ(address.column(), 5); + EXPECT_EQ(address.minor(), 11); } diff --git a/tools/bitread.cc b/tools/bitread.cc index c8c69b35..8e4c7335 100644 --- a/tools/bitread.cc +++ b/tools/bitread.cc @@ -159,11 +159,11 @@ int main(int argc, char** argv) { static_cast(it.first), static_cast(it.first.block_type()), it.first.is_bottom_half_rows() ? 1 : 0, - it.first.row_address(), it.first.column_address(), - it.first.minor_address()); + it.first.row(), it.first.column(), + it.first.minor()); if (FLAGS_p) { - if (it.first.minor_address() == 0 && !pgmdata.empty()) + if (it.first.minor() == 0 && !pgmdata.empty()) pgmsep.push_back(pgmdata.size()); pgmdata.push_back(std::vector()); @@ -195,12 +195,9 @@ int main(int argc, char** argv) { it.first.is_bottom_half_rows() ? 1 : 0, - it.first - .row_address(), - it.first - .column_address(), - it.first - .minor_address()); + it.first.row(), + it.first.column(), + it.first.minor()); else fprintf(f, "bit_%08x_%03d_" diff --git a/tools/frame_address_decoder.cc b/tools/frame_address_decoder.cc index 48b611fa..f9943ba1 100644 --- a/tools/frame_address_decoder.cc +++ b/tools/frame_address_decoder.cc @@ -18,17 +18,18 @@ int main(int argc, char* argv[]) { for (uint32_t frame_address_raw; (*input_stream) >> std::setbase(0) >> frame_address_raw;) { xc7series::FrameAddress frame_address(frame_address_raw); - std::cout - << "[" << std::hex << std::showbase << std::setw(10) - << frame_address_raw << "] " - << (frame_address.is_bottom_half_rows() ? "BOTTOM" : "TOP") - << " Row=" << std::setw(2) << std::dec - << static_cast(frame_address.row_address()) - << " Column=" << std::setw(2) << std::dec - << frame_address.column_address() - << " Minor=" << std::setw(2) << std::dec - << static_cast(frame_address.minor_address()) - << " Type=" << frame_address.block_type() << std::endl; + std::cout << "[" << std::hex << std::showbase << std::setw(10) + << frame_address_raw << "] " + << (frame_address.is_bottom_half_rows() ? "BOTTOM" + : "TOP") + << " Row=" << std::setw(2) << std::dec + << static_cast(frame_address.row()) + << " Column=" << std::setw(2) << std::dec + << frame_address.column() << " Minor=" << std::setw(2) + << std::dec + << static_cast(frame_address.minor()) + << " Type=" << frame_address.block_type() + << std::endl; } return 0; From 2b34fbb35de7168bc0c8ba69da7d64dde16b78c5 Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Tue, 2 Jan 2018 20:33:50 -0800 Subject: [PATCH 2/3] xc7series: refactor Part() ConfigurationFrameAddress row-half and row fields translate directly to the clock region structure used in 7-series parts. Break these concepts out into separate classes and encode them as such in Part YAML. Columns within a row are more complicated. Column indices are relative to a BlockType. Think of each BlockType as a data bus that terminates at some particular tile type (e.g. CLB_IO_CLK maps to INT_{L,R} tiles). Column indices act as addresses of endpoints on the associated BlockType bus. As the bus is 1 frame (101 words, 404 bytes) wide, each endpoint feeds frames into multiple tiles simultaneously. Minor addresses are frame addresses within a BlockType bus endpoint. These can refer to frames either stored within the endpoint tiles or in tiles chained behind them. Note that a given tile can be connected on multiple BlockType buses. For example, block RAMs appear to be attached both by being chained behind an INT_{L,R} on the CLB_IO_CLK bus as well as being a direct endpoint on the BLOCK_RAM bus. Due to this, tiles conceptually belong to the row rather than a single column. Signed-off-by: Rick Altherr --- lib/CMakeLists.txt | 12 +- .../xilinx/xc7series/configuration_bus.h | 93 +++++++++++ .../xilinx/xc7series/configuration_column.h | 78 +++++++++ .../xilinx/xc7series/global_clock_region.h | 93 +++++++++++ lib/include/prjxray/xilinx/xc7series/part.h | 44 +++-- lib/include/prjxray/xilinx/xc7series/row.h | 90 ++++++++++ lib/xilinx/xc7series/configuration_bus.cc | 77 +++++++++ .../xc7series/configuration_bus_test.cc | 72 ++++++++ lib/xilinx/xc7series/configuration_column.cc | 52 ++++++ .../xc7series/configuration_column_test.cc | 65 ++++++++ lib/xilinx/xc7series/configuration_test.cc | 25 +-- lib/xilinx/xc7series/global_clock_region.cc | 71 ++++++++ .../xc7series/global_clock_region_test.cc | 147 +++++++++++++++++ lib/xilinx/xc7series/part.cc | 98 +++++++---- lib/xilinx/xc7series/part_test.cc | 155 +++++++++++++++--- lib/xilinx/xc7series/row.cc | 62 +++++++ lib/xilinx/xc7series/row_test.cc | 115 +++++++++++++ tools/gen_part_base_yaml.cc | 31 +--- 18 files changed, 1279 insertions(+), 101 deletions(-) create mode 100644 lib/include/prjxray/xilinx/xc7series/configuration_bus.h create mode 100644 lib/include/prjxray/xilinx/xc7series/configuration_column.h create mode 100644 lib/include/prjxray/xilinx/xc7series/global_clock_region.h create mode 100644 lib/include/prjxray/xilinx/xc7series/row.h create mode 100644 lib/xilinx/xc7series/configuration_bus.cc create mode 100644 lib/xilinx/xc7series/configuration_bus_test.cc create mode 100644 lib/xilinx/xc7series/configuration_column.cc create mode 100644 lib/xilinx/xc7series/configuration_column_test.cc create mode 100644 lib/xilinx/xc7series/global_clock_region.cc create mode 100644 lib/xilinx/xc7series/global_clock_region_test.cc create mode 100644 lib/xilinx/xc7series/row.cc create mode 100644 lib/xilinx/xc7series/row_test.cc diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 552d5728..759f5eb4 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -4,11 +4,15 @@ add_library(libprjxray segbits_file_reader.cc xilinx/xc7series/bitstream_reader.cc xilinx/xc7series/block_type.cc - xilinx/xc7series/frame_address.cc + xilinx/xc7series/configuration_bus.cc + xilinx/xc7series/configuration_column.cc xilinx/xc7series/configuration_frame_range.cc xilinx/xc7series/configuration_packet.cc xilinx/xc7series/configuration_register.cc + xilinx/xc7series/frame_address.cc + xilinx/xc7series/global_clock_region.cc xilinx/xc7series/part.cc + xilinx/xc7series/row.cc ) target_include_directories(libprjxray PUBLIC "include") target_link_libraries(libprjxray absl::optional absl::strings absl::span yaml-cpp) @@ -40,9 +44,13 @@ if (PRJXRAY_BUILD_TESTING) xilinx/xc7series/bitstream_reader_test.cc xilinx/xc7series/block_type_test.cc xilinx/xc7series/frame_address_test.cc + xilinx/xc7series/configuration_bus_test.cc + xilinx/xc7series/configuration_column_test.cc xilinx/xc7series/configuration_test.cc xilinx/xc7series/configuration_packet_test.cc - xilinx/xc7series/part_test.cc) + xilinx/xc7series/global_clock_region_test.cc + xilinx/xc7series/part_test.cc + xilinx/xc7series/row_test.cc) target_link_libraries(xilinx_xc7series_test libprjxray gtest_main) add_test(NAME xilinx_xc7series_test COMMAND xilinx_xc7series_test diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_bus.h b/lib/include/prjxray/xilinx/xc7series/configuration_bus.h new file mode 100644 index 00000000..8b3e9bdf --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_bus.h @@ -0,0 +1,93 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_BUS_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_BUS_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +// ConfigurationBus represents a bus for sending frames to a specific BlockType +// within a Row. An instance of ConfigurationBus will contain one or more +// ConfigurationColumns. +class ConfigurationBus { + public: + ConfigurationBus() = default; + + // Constructs a ConfigurationBus from iterators yielding + // FrameAddresses. The frame address need not be contiguous or sorted + // but they must all have the same block type, row half, and row + // address components. + template + ConfigurationBus(T first, T last); + + // Returns true if the provided address falls into a valid segment of + // the address range on this bus. Only the column and minor components + // of the address are considered as all other components are outside + // the scope of a bus. + bool IsValidFrameAddress(FrameAddress address) const; + + // Returns the next valid address on the bus in numerically increasing + // order. If the next address would fall outside this bus, no object is + // returned. + absl::optional GetNextFrameAddress( + FrameAddress address) const; + + private: + friend class YAML::convert; + + std::map configuration_columns_; +}; + +template +ConfigurationBus::ConfigurationBus(T first, T last) { + assert( + std::all_of(first, last, [&](const typename T::value_type& addr) { + return (addr.block_type() == first->block_type() && + addr.is_bottom_half_rows() == + first->is_bottom_half_rows() && + addr.row() == first->row()); + })); + + std::sort(first, last, + [](const FrameAddress& lhs, const FrameAddress& rhs) { + return lhs.column() < rhs.column(); + }); + + for (auto col_first = first; col_first != last;) { + auto col_last = std::upper_bound( + col_first, last, col_first->column(), + [](const unsigned int& lhs, const FrameAddress& rhs) { + return lhs < rhs.column(); + }); + + configuration_columns_.emplace( + col_first->column(), + std::move(ConfigurationColumn(col_first, col_last))); + col_first = col_last; + } +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace YAML { +template <> +struct convert { + static Node encode( + const prjxray::xilinx::xc7series::ConfigurationBus& rhs); + static bool decode(const Node& node, + prjxray::xilinx::xc7series::ConfigurationBus& lhs); +}; +} // namespace YAML + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_BUS_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_column.h b/lib/include/prjxray/xilinx/xc7series/configuration_column.h new file mode 100644 index 00000000..b4615c5b --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_column.h @@ -0,0 +1,78 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_COLUMN_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_COLUMN_H_ + +#include +#include + +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +// ConfigurationColumn represents an endpoint on a ConfigurationBus. +class ConfigurationColumn { + public: + ConfigurationColumn() = default; + ConfigurationColumn(unsigned int frame_count) + : frame_count_(frame_count) {} + + // Returns a ConfigurationColumn that describes a continguous range of + // minor addresses that encompasses the given + // FrameAddresses. The provided addresses must only + // differ only by their minor addresses. + template + ConfigurationColumn(T first, T last); + + // Returns true if the minor field of the address is within the valid + // range of this column. + bool IsValidFrameAddress(FrameAddress address) const; + + // Returns the next address in numerical order. If the next address + // would be outside this column, return no object. + absl::optional GetNextFrameAddress( + FrameAddress address) const; + + private: + friend class YAML::convert; + + unsigned int frame_count_; +}; + +template +ConfigurationColumn::ConfigurationColumn(T first, T last) { + assert( + std::all_of(first, last, [&](const typename T::value_type& addr) { + return (addr.block_type() == first->block_type() && + addr.is_bottom_half_rows() == + first->is_bottom_half_rows() && + addr.row() == first->row() && + addr.column() == first->column()); + })); + + auto max_minor = std::max_element( + first, last, [](const FrameAddress& lhs, const FrameAddress& rhs) { + return lhs.minor() < rhs.minor(); + }); + + frame_count_ = max_minor->minor() + 1; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace YAML { +template <> +struct convert { + static Node encode( + const prjxray::xilinx::xc7series::ConfigurationColumn& rhs); + static bool decode( + const Node& node, + prjxray::xilinx::xc7series::ConfigurationColumn& lhs); +}; +} // namespace YAML + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_COLUMN_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/global_clock_region.h b/lib/include/prjxray/xilinx/xc7series/global_clock_region.h new file mode 100644 index 00000000..39747f3b --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/global_clock_region.h @@ -0,0 +1,93 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_GLOBAL_CLOCK_REGION_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_GLOBAL_CLOCK_REGION_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +// GlobalClockRegion represents all the resources associated with a single +// global clock buffer (BUFG) tile. In 7-Series FPGAs, there are two BUFG +// tiles that divide the chip into top and bottom "halves". Each half may +// contains any number of rows, buses, and columns. +class GlobalClockRegion { + public: + GlobalClockRegion() = default; + + // Construct a GlobalClockRegion from iterators that yield + // FrameAddresses which are known to be valid. The addresses may be + // noncontinguous and/or unordered but they must share the same row + // half address component. + template + GlobalClockRegion(T first, T last); + + // Returns true if the address falls within a valid range inside the + // global clock region. The row half address component is ignored as it + // is outside the context of a global clock region. + bool IsValidFrameAddress(FrameAddress address) const; + + // Returns the next numerically increasing address known within this + // global clock region. If the next address would fall outside this + // global clock region, no address is returned. If the next address + // would jump to a different block type, no address is returned as the + // same block type in other global clock regions come numerically + // before other block types. + absl::optional GetNextFrameAddress( + FrameAddress address) const; + + private: + friend class YAML::convert; + + std::map rows_; +}; + +template +GlobalClockRegion::GlobalClockRegion(T first, T last) { + assert( + std::all_of(first, last, [&](const typename T::value_type& addr) { + return addr.is_bottom_half_rows() == + first->is_bottom_half_rows(); + })); + + std::sort(first, last, + [](const FrameAddress& lhs, const FrameAddress& rhs) { + return lhs.row() < rhs.row(); + }); + + for (auto row_first = first; row_first != last;) { + auto row_last = std::upper_bound( + row_first, last, row_first->row(), + [](const uint8_t& lhs, const FrameAddress& rhs) { + return lhs < rhs.row(); + }); + + rows_.emplace(row_first->row(), + std::move(Row(row_first, row_last))); + row_first = row_last; + } +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace YAML { +template <> +struct convert { + static Node encode( + const prjxray::xilinx::xc7series::GlobalClockRegion& rhs); + static bool decode(const Node& node, + prjxray::xilinx::xc7series::GlobalClockRegion& lhs); +}; +} // namespace YAML + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_GLOBAL_CLOCK_REGION_H_ diff --git a/lib/include/prjxray/xilinx/xc7series/part.h b/lib/include/prjxray/xilinx/xc7series/part.h index ad5eaff7..ca7749d0 100644 --- a/lib/include/prjxray/xilinx/xc7series/part.h +++ b/lib/include/prjxray/xilinx/xc7series/part.h @@ -1,11 +1,15 @@ #ifndef PRJXRAY_LIB_XILINX_XC7SERIES_PART_H_ #define PRJXRAY_LIB_XILINX_XC7SERIES_PART_H_ +#include +#include +#include +#include #include #include -#include -#include +#include +#include namespace prjxray { namespace xilinx { @@ -13,33 +17,47 @@ namespace xc7series { class Part { public: + constexpr static uint32_t kInvalidIdcode = 0; + static absl::optional FromFile(const std::string& path); // Constructs an invalid part with a zero IDCODE. Required for YAML // conversion but shouldn't be used otherwise. - Part() : idcode_(0), frame_ranges_() {} + Part() : idcode_(kInvalidIdcode) {} - Part(uint32_t idcode, - const std::vector& ranges) - : idcode_(idcode), frame_ranges_(std::move(ranges)) {} + template + Part(uint32_t idcode, T collection) + : Part(idcode, std::begin(collection), std::end(collection)) {} + + template + Part(uint32_t idcode, T first, T last); uint32_t idcode() const { return idcode_; } - const std::vector& configuration_frame_ranges() - const { - return frame_ranges_; - } + bool IsValidFrameAddress(FrameAddress address) const; absl::optional GetNextFrameAddress( FrameAddress address) const; private: - uint32_t idcode_; + friend class YAML::convert; - // Ranges are expected to be non-overlapping. - std::vector frame_ranges_; + uint32_t idcode_; + GlobalClockRegion top_region_; + GlobalClockRegion bottom_region_; }; +template +Part::Part(uint32_t idcode, T first, T last) : idcode_(idcode) { + auto first_of_top = + std::partition(first, last, [](const FrameAddress& addr) { + return addr.is_bottom_half_rows(); + }); + + top_region_ = GlobalClockRegion(first_of_top, last); + bottom_region_ = GlobalClockRegion(first, first_of_top); +} + } // namespace xc7series } // namespace xilinx } // namespace prjxray diff --git a/lib/include/prjxray/xilinx/xc7series/row.h b/lib/include/prjxray/xilinx/xc7series/row.h new file mode 100644 index 00000000..8dd8d9cc --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/row.h @@ -0,0 +1,90 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_ROW_H_ +#define PRJXRAY_LIB_XILINX_XC7SERIES_ROW_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +class Row { + public: + Row() = default; + + // Construct a row from a range of iterators that yield FrameAddresses. + // The addresses may be noncontinguous and/or unsorted but all must + // share the same row half and row components. + template + Row(T first, T last); + + // Returns true if the provided address falls within a valid range + // attributed to this row. Only the block type, column, and minor + // address components are considerd as the remaining components are + // outside the scope of a row. + bool IsValidFrameAddress(FrameAddress address) const; + + // Returns the next numerically increasing address within the Row. If + // the next address would fall outside the Row, no object is returned. + // If the next address would cross from one block type to another, no + // object is returned as other rows of the same block type come before + // other block types numerically. + absl::optional GetNextFrameAddress( + FrameAddress address) const; + + private: + friend class YAML::convert; + + std::map configuration_buses_; +}; + +template +Row::Row(T first, T last) { + assert( + std::all_of(first, last, [&](const typename T::value_type& addr) { + return (addr.is_bottom_half_rows() == + first->is_bottom_half_rows() && + addr.row() == first->row()); + })); + + std::sort(first, last, + [](const FrameAddress& lhs, const FrameAddress& rhs) { + return lhs.block_type() < rhs.block_type(); + }); + + for (auto bus_first = first; bus_first != last;) { + auto bus_last = std::upper_bound( + bus_first, last, bus_first->block_type(), + [](const BlockType& lhs, const FrameAddress& rhs) { + return lhs < rhs.block_type(); + }); + + configuration_buses_.emplace( + bus_first->block_type(), + std::move(ConfigurationBus(bus_first, bus_last))); + bus_first = bus_last; + } +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace YAML { +template <> +struct convert { + static Node encode(const prjxray::xilinx::xc7series::Row& rhs); + static bool decode(const Node& node, + prjxray::xilinx::xc7series::Row& lhs); +}; +} // namespace YAML + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_ROW_H_ diff --git a/lib/xilinx/xc7series/configuration_bus.cc b/lib/xilinx/xc7series/configuration_bus.cc new file mode 100644 index 00000000..e0a2105d --- /dev/null +++ b/lib/xilinx/xc7series/configuration_bus.cc @@ -0,0 +1,77 @@ +#include + +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +bool ConfigurationBus::IsValidFrameAddress(FrameAddress address) const { + auto addr_column = configuration_columns_.find(address.column()); + if (addr_column == configuration_columns_.end()) + return false; + + return addr_column->second.IsValidFrameAddress(address); +} + +absl::optional ConfigurationBus::GetNextFrameAddress( + FrameAddress address) const { + // Find the column for the current address. + auto addr_column = configuration_columns_.find(address.column()); + + // If the current address isn't in a known column, no way to know the + // next address. + if (addr_column == configuration_columns_.end()) + return {}; + + // Ask the column for the next address. + absl::optional next_address = + addr_column->second.GetNextFrameAddress(address); + if (next_address) + return next_address; + + // The current column doesn't know what the next address is. Assume + // that the next valid address is the beginning of the next column. + if (++addr_column != configuration_columns_.end()) { + auto next_address = FrameAddress( + address.block_type(), address.is_bottom_half_rows(), + address.row(), addr_column->first, 0); + if (addr_column->second.IsValidFrameAddress(next_address)) + return next_address; + } + + // Not in this bus. + return {}; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace xc7series = prjxray::xilinx::xc7series; + +namespace YAML { + +Node convert::encode( + const xc7series::ConfigurationBus& rhs) { + Node node; + node.SetTag("xilinx/xc7series/configuration_bus"); + node["configuration_columns"] = rhs.configuration_columns_; + return node; +} + +bool convert::decode( + const Node& node, + xc7series::ConfigurationBus& lhs) { + if (!node.Tag().empty() && + node.Tag() != "xilinx/xc7series/configuration_bus") { + return false; + } + + lhs.configuration_columns_ = + node["configuration_columns"] + .as>(); + return true; +} + +} // namespace YAML diff --git a/lib/xilinx/xc7series/configuration_bus_test.cc b/lib/xilinx/xc7series/configuration_bus_test.cc new file mode 100644 index 00000000..c665d9df --- /dev/null +++ b/lib/xilinx/xc7series/configuration_bus_test.cc @@ -0,0 +1,72 @@ +#include + +#include + +namespace xc7series = prjxray::xilinx::xc7series; + +TEST(ConfigurationBusTest, IsValidFrameAddress) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 1)); + + xc7series::ConfigurationBus bus(addresses.begin(), addresses.end()); + + EXPECT_TRUE(bus.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0))); + EXPECT_TRUE(bus.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 1))); + + EXPECT_FALSE(bus.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); +} + +TEST(ConfigurationBusTest, GetNextFrameAddressYieldNextAddressInBus) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 1)); + + xc7series::ConfigurationBus bus(addresses.begin(), addresses.end()); + + auto next_address = bus.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, + false, 0, 0, 1)); + + next_address = bus.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, + false, 0, 1, 0)); +} + +TEST(ConfigurationBusTest, GetNextFrameAddressYieldNothingAtEndOfBus) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 1)); + + xc7series::ConfigurationBus bus(addresses.begin(), addresses.end()); + + EXPECT_FALSE(bus.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 1, 1))); +} diff --git a/lib/xilinx/xc7series/configuration_column.cc b/lib/xilinx/xc7series/configuration_column.cc new file mode 100644 index 00000000..f9793839 --- /dev/null +++ b/lib/xilinx/xc7series/configuration_column.cc @@ -0,0 +1,52 @@ +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +bool ConfigurationColumn::IsValidFrameAddress(FrameAddress address) const { + return address.minor() < frame_count_; +} + +absl::optional ConfigurationColumn::GetNextFrameAddress( + FrameAddress address) const { + if (!IsValidFrameAddress(address)) + return {}; + + if (static_cast(address.minor() + 1) < frame_count_) { + return address + 1; + } + + // Next address is not in this column. + return {}; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace xc7series = prjxray::xilinx::xc7series; + +namespace YAML { + +Node convert::encode( + const xc7series::ConfigurationColumn& rhs) { + Node node; + node.SetTag("xilinx/xc7series/configuration_column"); + node["frame_count"] = rhs.frame_count_; + return node; +} + +bool convert::decode( + const Node& node, + xc7series::ConfigurationColumn& lhs) { + if (!node.Tag().empty() && + node.Tag() != "xilinx/xc7series/configuration_column") { + return false; + } + + lhs.frame_count_ = node["frame_count"].as(); + return true; +} + +} // namespace YAML diff --git a/lib/xilinx/xc7series/configuration_column_test.cc b/lib/xilinx/xc7series/configuration_column_test.cc new file mode 100644 index 00000000..154a3d18 --- /dev/null +++ b/lib/xilinx/xc7series/configuration_column_test.cc @@ -0,0 +1,65 @@ +#include + +#include +#include +#include +#include + +namespace xc7series = prjxray::xilinx::xc7series; + +TEST(ConfigurationColumnTest, IsValidFrameAddress) { + xc7series::ConfigurationColumn column(10); + + // Inside this column. + EXPECT_TRUE(column.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 3))); + // Past this column's frame width. + EXPECT_FALSE(column.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 10))); +} + +TEST(ConfigurationColumnTest, GetNextFrameAddressYieldNextAddressInColumn) { + xc7series::ConfigurationColumn column(10); + + auto next_address = column.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 3)); + EXPECT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 1, 2, 4)); +} + +TEST(ConfigurationColumnTest, GetNextFrameAddressYieldNothingAtEndOfColumn) { + xc7series::ConfigurationColumn column(10); + + EXPECT_FALSE(column.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 9))); +} + +TEST(ConfigurationColumnTest, GetNextFrameAddressYieldNothingOutsideColumn) { + xc7series::ConfigurationColumn column(10); + + // Just past last frame in column. + EXPECT_FALSE(column.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 10))); +} + +TEST(ConfigurationColumnTest, YamlEncodeTest) { + xc7series::ConfigurationColumn column(10); + + YAML::Node node(column); + EXPECT_TRUE(node["frame_count"]); + EXPECT_EQ(node["frame_count"].as(), 10); +} + +TEST(ConfigurationColumnTest, YAMLDecodeTest) { + YAML::Node node; + node.SetTag("xilinx/xc7series/configuration_column"); + node["frame_count"] = 10; + + auto column = node.as(); + EXPECT_TRUE(column.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 8))); + EXPECT_FALSE(column.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 2, 9))); +} diff --git a/lib/xilinx/xc7series/configuration_test.cc b/lib/xilinx/xc7series/configuration_test.cc index 9275a900..4b94e583 100644 --- a/lib/xilinx/xc7series/configuration_test.cc +++ b/lib/xilinx/xc7series/configuration_test.cc @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -8,16 +9,18 @@ #include #include #include +#include #include +#include namespace xc7series = prjxray::xilinx::xc7series; TEST(ConfigurationTest, ConstructFromPacketsWithSingleFrame) { - std::vector test_part_ranges; - test_part_ranges.push_back( - xc7series::ConfigurationFrameRange(0x4567, 0x4568)); + std::vector test_part_addresses; + test_part_addresses.push_back(0x4567); + test_part_addresses.push_back(0x4568); - xc7series::Part test_part(0x1234, test_part_ranges); + xc7series::Part test_part(0x1234, test_part_addresses); std::vector idcode{0x1234}; std::vector cmd{0x0001}; @@ -61,13 +64,15 @@ TEST(ConfigurationTest, ConstructFromPacketsWithSingleFrame) { } TEST(ConfigurationTest, ConstructFromPacketsWithAutoincrement) { - std::vector test_part_ranges; - test_part_ranges.push_back( - xc7series::ConfigurationFrameRange(0x4560, 0x4570)); - test_part_ranges.push_back( - xc7series::ConfigurationFrameRange(0x4580, 0x4590)); + std::vector test_part_addresses; + for (int ii = 0x4560; ii < 0x4570; ++ii) { + test_part_addresses.push_back(ii); + } + for (int ii = 0x4580; ii < 0x4590; ++ii) { + test_part_addresses.push_back(ii); + } - xc7series::Part test_part(0x1234, test_part_ranges); + xc7series::Part test_part(0x1234, test_part_addresses); std::vector idcode{0x1234}; std::vector cmd{0x0001}; diff --git a/lib/xilinx/xc7series/global_clock_region.cc b/lib/xilinx/xc7series/global_clock_region.cc new file mode 100644 index 00000000..638cb461 --- /dev/null +++ b/lib/xilinx/xc7series/global_clock_region.cc @@ -0,0 +1,71 @@ +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +bool GlobalClockRegion::IsValidFrameAddress(FrameAddress address) const { + auto addr_row = rows_.find(address.row()); + if (addr_row == rows_.end()) + return false; + return addr_row->second.IsValidFrameAddress(address); +} + +absl::optional GlobalClockRegion::GetNextFrameAddress( + FrameAddress address) const { + // Find the row for the current address. + auto addr_row = rows_.find(address.row()); + + // If the current address isn't in a known row, no way to know the next. + if (addr_row == rows_.end()) + return {}; + + // Ask the row for the next address. + absl::optional next_address = + addr_row->second.GetNextFrameAddress(address); + if (next_address) + return next_address; + + // The current row doesn't know what the next address is. Assume that + // the next valid address is the beginning of the next row. + if (++addr_row != rows_.end()) { + auto next_address = FrameAddress(address.block_type(), + address.is_bottom_half_rows(), + addr_row->first, 0, 0); + if (addr_row->second.IsValidFrameAddress(next_address)) + return next_address; + } + + // Must be in a different global clock region. + return {}; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace xc7series = prjxray::xilinx::xc7series; + +namespace YAML { + +Node convert::encode( + const xc7series::GlobalClockRegion& rhs) { + Node node; + node.SetTag("xilinx/xc7series/global_clock_region"); + node["rows"] = rhs.rows_; + return node; +} + +bool convert::decode( + const Node& node, + xc7series::GlobalClockRegion& lhs) { + if (!node.Tag().empty() && + node.Tag() != "xilinx/xc7series/global_clock_region") { + return false; + } + + lhs.rows_ = node["rows"].as>(); + return true; +} + +} // namespace YAML diff --git a/lib/xilinx/xc7series/global_clock_region_test.cc b/lib/xilinx/xc7series/global_clock_region_test.cc new file mode 100644 index 00000000..466e3109 --- /dev/null +++ b/lib/xilinx/xc7series/global_clock_region_test.cc @@ -0,0 +1,147 @@ +#include + +#include + +namespace xc7series = prjxray::xilinx::xc7series; + +TEST(GlobalClockRegionTest, IsValidFrameAddress) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + + xc7series::GlobalClockRegion global_clock_region(addresses.begin(), + addresses.end()); + + EXPECT_TRUE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0))); + EXPECT_TRUE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0))); + EXPECT_TRUE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); + EXPECT_TRUE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0))); + + EXPECT_FALSE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 2))); + EXPECT_FALSE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 2, 0))); + EXPECT_FALSE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 2, 0, 0))); + EXPECT_FALSE( + global_clock_region.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CFG_CLB, false, 0, 0, 2))); +} + +TEST(GlobalClockRegionTest, + GetNextFrameAddressYieldNextAddressInGlobalClockRegion) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + + xc7series::GlobalClockRegion global_clock_region(addresses.begin(), + addresses.end()); + + auto next_address = + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 0, 1)); + + next_address = + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 1, 0)); + + next_address = + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 1, 0, 0)); + + next_address = + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, + false, 0, 0, 2)); +} + +TEST(GlobalClockRegionTest, + GetNextFrameAddressYieldNothingAtEndOfGlobalClockRegion) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + + xc7series::GlobalClockRegion global_clock_region(addresses.begin(), + addresses.end()); + + EXPECT_FALSE( + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1))); + EXPECT_FALSE( + global_clock_region.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); +} diff --git a/lib/xilinx/xc7series/part.cc b/lib/xilinx/xc7series/part.cc index 2ce2bc32..eca5cc58 100644 --- a/lib/xilinx/xc7series/part.cc +++ b/lib/xilinx/xc7series/part.cc @@ -16,32 +16,48 @@ absl::optional Part::FromFile(const std::string& path) { } } +bool Part::IsValidFrameAddress(FrameAddress address) const { + if (address.is_bottom_half_rows()) { + return bottom_region_.IsValidFrameAddress(address); + } else { + return top_region_.IsValidFrameAddress(address); + } +} + absl::optional Part::GetNextFrameAddress( FrameAddress address) const { - // Start with the next linear address. - FrameAddress target_address(address + 1); + // Ask the current global clock region first. + absl::optional next_address = + (address.is_bottom_half_rows() + ? bottom_region_.GetNextFrameAddress(address) + : top_region_.GetNextFrameAddress(address)); + if (next_address) + return next_address; - // 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; - int32_t closest_distance; - for (auto iter = frame_ranges_.begin(); iter != frame_ranges_.end(); - ++iter) { - if (iter->Contains(target_address)) { - return target_address; - } - - int32_t distance = iter->begin() - target_address; - if (distance > 0 && - (!closest_address || distance < closest_distance)) { - closest_address = iter->begin(); - closest_distance = distance; - } + // If the current address is in the top region, the bottom region is + // next numerically. + if (!address.is_bottom_half_rows()) { + next_address = + FrameAddress(address.block_type(), true, 0, 0, 0); + if (bottom_region_.IsValidFrameAddress(*next_address)) + return next_address; } - return closest_address; + // Block types are next numerically. + if (address.block_type() < BlockType::BLOCK_RAM) { + next_address = + FrameAddress(BlockType::BLOCK_RAM, false, 0, 0, 0); + if (IsValidFrameAddress(*next_address)) + return next_address; + } + + if (address.block_type() < BlockType::CFG_CLB) { + next_address = FrameAddress(BlockType::CFG_CLB, false, 0, 0, 0); + if (IsValidFrameAddress(*next_address)) + return next_address; + } + + return {}; } } // namespace xc7series @@ -57,23 +73,43 @@ Node convert::encode(const xc7series::Part& rhs) { node.SetTag("xilinx/xc7series/part"); std::ostringstream idcode_str; - idcode_str << "0x" << std::hex << rhs.idcode(); + idcode_str << "0x" << std::hex << rhs.idcode_; node["idcode"] = idcode_str.str(); - - node["configuration_ranges"] = rhs.configuration_frame_ranges(); + node["global_clock_regions"]["top"] = rhs.top_region_; + node["global_clock_regions"]["bottom"] = rhs.bottom_region_; return node; } bool convert::decode(const Node& node, xc7series::Part& lhs) { - if (node.Tag() != "xilinx/xc7series/part" || !node["idcode"] || - !node["configuration_ranges"]) + if (!node.Tag().empty() && node.Tag() != "xilinx/xc7series/part") return false; - lhs = xc7series::Part( - node["idcode"].as(), - node["configuration_ranges"] - .as>()); + if (!node["global_clock_regions"] && !node["configuration_ranges"]) { + return false; + } + + lhs.idcode_ = node["idcode"].as(); + + if (node["global_clock_regions"]) { + lhs.top_region_ = node["global_clock_regions"]["top"] + .as(); + lhs.bottom_region_ = node["global_clock_regions"]["bottom"] + .as(); + } else if (node["configuration_ranges"]) { + std::vector addresses; + for (auto range : node["configuration_ranges"]) { + auto begin = + range["begin"].as(); + auto end = range["end"].as(); + for (uint32_t cur = begin; cur < end; ++cur) { + addresses.push_back(cur); + } + } + + lhs = xc7series::Part(lhs.idcode_, addresses); + } + return true; -} +}; } // namespace YAML diff --git a/lib/xilinx/xc7series/part_test.cc b/lib/xilinx/xc7series/part_test.cc index 45c8c701..ed5a0311 100644 --- a/lib/xilinx/xc7series/part_test.cc +++ b/lib/xilinx/xc7series/part_test.cc @@ -4,37 +4,146 @@ namespace xc7series = prjxray::xilinx::xc7series; -TEST(PartTest, GetNextAddressWhereNextIsInValidRange) { - std::vector ranges; - ranges.push_back(xc7series::ConfigurationFrameRange(0x0, 0xF)); - ranges.push_back(xc7series::ConfigurationFrameRange(0x20, 0x2F)); +TEST(PartTest, IsValidFrameAddress) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 1)); - xc7series::Part part(0x1234, ranges); + xc7series::Part part(0x1234, addresses.begin(), addresses.end()); - auto next_address = part.GetNextFrameAddress(0x4); - EXPECT_TRUE(next_address); - EXPECT_EQ(static_cast(0x5), *next_address); + EXPECT_TRUE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0))); + EXPECT_TRUE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0))); + EXPECT_TRUE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); + EXPECT_TRUE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0))); + EXPECT_TRUE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 0))); + + EXPECT_FALSE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 2))); + EXPECT_FALSE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 2, 0))); + EXPECT_FALSE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 2, 0, 0))); + EXPECT_FALSE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CFG_CLB, false, 0, 0, 2))); + EXPECT_FALSE(part.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 1, 0))); } -TEST(PartTest, GetNextAddressWhereNextIsBetweenRanges) { - std::vector ranges; - ranges.push_back(xc7series::ConfigurationFrameRange(0x0, 0xF)); - ranges.push_back(xc7series::ConfigurationFrameRange(0x20, 0x2F)); +TEST(PartTest, GetNextFrameAddressYieldNextAddressInPart) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 1)); - xc7series::Part part(0x1234, ranges); + xc7series::Part part(0x1234, addresses.begin(), addresses.end()); - auto next_address = part.GetNextFrameAddress(0xF); - EXPECT_TRUE(next_address); - EXPECT_EQ(static_cast(0x20), *next_address); + auto next_address = part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 0, 1)); + + next_address = part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 1, 0)); + + next_address = part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 1, 0, 0)); + + next_address = part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + true, 0, 0, 0)); + + next_address = part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, + false, 0, 0, 0)); } -TEST(PartTest, GetNextAddressWhereNextWouldBePastLastRange) { - std::vector ranges; - ranges.push_back(xc7series::ConfigurationFrameRange(0x0, 0xF)); - ranges.push_back(xc7series::ConfigurationFrameRange(0x20, 0x2F)); +TEST(PartTest, GetNextFrameAddressYieldNothingAtEndOfPart) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 1, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, true, 0, 0, 1)); - xc7series::Part part(0x1234, ranges); + xc7series::Part part(0x1234, addresses.begin(), addresses.end()); - auto next_address = part.GetNextFrameAddress(0x2F); - EXPECT_FALSE(next_address); + EXPECT_FALSE(part.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); } diff --git a/lib/xilinx/xc7series/row.cc b/lib/xilinx/xc7series/row.cc new file mode 100644 index 00000000..5f737164 --- /dev/null +++ b/lib/xilinx/xc7series/row.cc @@ -0,0 +1,62 @@ +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +bool Row::IsValidFrameAddress(FrameAddress address) const { + auto addr_bus = configuration_buses_.find(address.block_type()); + if (addr_bus == configuration_buses_.end()) + return false; + return addr_bus->second.IsValidFrameAddress(address); +} + +absl::optional Row::GetNextFrameAddress( + FrameAddress address) const { + // Find the bus for the current address. + auto addr_bus = configuration_buses_.find(address.block_type()); + + // If the current address isn't in a known bus, no way to know the next. + if (addr_bus == configuration_buses_.end()) + return {}; + + // Ask the bus for the next address. + absl::optional next_address = + addr_bus->second.GetNextFrameAddress(address); + if (next_address) + return next_address; + + // The current bus doesn't know what the next address is. Rows come next + // in frame address numerical order so punt back to the caller to figure + // it out. + return {}; +} + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +namespace xc7series = prjxray::xilinx::xc7series; + +namespace YAML { + +Node convert::encode(const xc7series::Row& rhs) { + Node node; + node.SetTag("xilinx/xc7series/row"); + node["configuration_buses"] = rhs.configuration_buses_; + return node; +} + +bool convert::decode(const Node& node, xc7series::Row& lhs) { + if (!node.Tag().empty() && node.Tag() != "xilinx/xc7series/row") { + return false; + } + + lhs.configuration_buses_ = + node["configuration_buses"] + .as>(); + return true; +} + +} // namespace YAML diff --git a/lib/xilinx/xc7series/row_test.cc b/lib/xilinx/xc7series/row_test.cc new file mode 100644 index 00000000..2475f90b --- /dev/null +++ b/lib/xilinx/xc7series/row_test.cc @@ -0,0 +1,115 @@ +#include + +#include + +namespace xc7series = prjxray::xilinx::xc7series; + +TEST(RowTest, IsValidFrameAddress) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + + xc7series::Row row(addresses.begin(), addresses.end()); + + EXPECT_TRUE(row.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0))); + EXPECT_TRUE(row.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0))); + EXPECT_TRUE(row.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); + + EXPECT_FALSE(row.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 2))); + EXPECT_FALSE(row.IsValidFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 2, 0))); +} + +TEST(RowTest, GetNextFrameAddressYieldNextAddressInRow) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + + xc7series::Row row(addresses.begin(), addresses.end()); + + auto next_address = row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 0, 1)); + + next_address = row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::CLB_IO_CLK, + false, 0, 1, 0)); + + // Rows have unique behavior for GetNextFrameAddress() at the end of a + // bus. Since the addresses need to be returned in numerically + // increasing order, all of the rows need to be returned before moving + // to a different bus. That means that Row::GetNextFrameAddress() needs + // to return no object at the end of a bus and let the caller use that + // as a signal to try the next row. + next_address = row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + EXPECT_FALSE(next_address); + + next_address = row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + ASSERT_TRUE(next_address); + EXPECT_EQ(*next_address, + xc7series::FrameAddress(xc7series::BlockType::BLOCK_RAM, + false, 0, 0, 2)); + + next_address = row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + EXPECT_FALSE(next_address); +} + +TEST(RowTest, GetNextFrameAddressYieldNothingAtEndOfRow) { + std::vector addresses; + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::CLB_IO_CLK, false, 0, 1, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 0)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 1)); + addresses.push_back(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2)); + + xc7series::Row row(addresses.begin(), addresses.end()); + + EXPECT_FALSE(row.GetNextFrameAddress(xc7series::FrameAddress( + xc7series::BlockType::BLOCK_RAM, false, 0, 0, 2))); +} diff --git a/tools/gen_part_base_yaml.cc b/tools/gen_part_base_yaml.cc index 957e5410..9767bce2 100644 --- a/tools/gen_part_base_yaml.cc +++ b/tools/gen_part_base_yaml.cc @@ -1,13 +1,17 @@ #include +#include #include +#include +#include #include #include #include #include #include -#include +#include +#include #include #include @@ -37,7 +41,7 @@ int main(int argc, char* argv[]) { } bool found_fdri_write = false; - std::vector frame_addresses; + std::vector frame_addresses; absl::optional idcode; for (auto packet : *reader) { if (packet.opcode() != @@ -72,26 +76,9 @@ int main(int argc, char* argv[]) { return 1; } - // So far, the addresses appear to be written in increasing order but - // there is no guarantee. Sort them just in case. - std::sort(frame_addresses.begin(), frame_addresses.end()); - - std::vector ranges; - for (auto start_of_range = frame_addresses.begin(); - start_of_range != frame_addresses.end();) { - auto end_of_range = start_of_range; - while (end_of_range + 1 != frame_addresses.end() && - *(end_of_range + 1) == *end_of_range + 1) { - ++end_of_range; - } - - ranges.push_back(xc7series::ConfigurationFrameRange( - *start_of_range, *end_of_range + 1)); - - start_of_range = ++end_of_range; - } - - std::cout << YAML::Node(xc7series::Part(*idcode, ranges)) << std::endl; + auto part = xc7series::Part(*idcode, frame_addresses.begin(), + frame_addresses.end()); + std::cout << YAML::Node(part) << std::endl; return 0; } From 2da520bea3036020a73719f16bc42c4df0ecd2d0 Mon Sep 17 00:00:00 2001 From: Rick Altherr Date: Tue, 9 Jan 2018 13:15:43 -0800 Subject: [PATCH 3/3] Remove unused ConfigurationFrameRange Signed-off-by: Rick Altherr --- lib/CMakeLists.txt | 1 - .../xc7series/configuration_frame_range.h | 47 ------------------- .../xc7series/configuration_frame_range.cc | 41 ---------------- 3 files changed, 89 deletions(-) delete mode 100644 lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h delete mode 100644 lib/xilinx/xc7series/configuration_frame_range.cc diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 759f5eb4..2edffb1d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -6,7 +6,6 @@ add_library(libprjxray xilinx/xc7series/block_type.cc xilinx/xc7series/configuration_bus.cc xilinx/xc7series/configuration_column.cc - xilinx/xc7series/configuration_frame_range.cc xilinx/xc7series/configuration_packet.cc xilinx/xc7series/configuration_register.cc xilinx/xc7series/frame_address.cc diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h b/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h deleted file mode 100644 index 30397039..00000000 --- a/lib/include/prjxray/xilinx/xc7series/configuration_frame_range.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_RANGE_H_ -#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_RANGE_H_ - -#include - -#include -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -class ConfigurationFrameRange { - public: - ConfigurationFrameRange() : begin_(0), end_(0) {} - - ConfigurationFrameRange(FrameAddress begin, FrameAddress end) - : begin_(begin), end_(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(FrameAddress address) const; - - private: - FrameAddress begin_; - FrameAddress end_; -}; - -} // namespace xc7series -} // namespace xilinx -} // namespace prjxray - -namespace YAML { -template <> -struct convert { - static Node encode( - const prjxray::xilinx::xc7series::ConfigurationFrameRange& rhs); - static bool decode( - const Node& node, - prjxray::xilinx::xc7series::ConfigurationFrameRange& lhs); -}; -} // namespace YAML -#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_FRAME_RANGE_H_ diff --git a/lib/xilinx/xc7series/configuration_frame_range.cc b/lib/xilinx/xc7series/configuration_frame_range.cc deleted file mode 100644 index 3fb69235..00000000 --- a/lib/xilinx/xc7series/configuration_frame_range.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include - -namespace prjxray { -namespace xilinx { -namespace xc7series { - -bool ConfigurationFrameRange::Contains(FrameAddress address) const { - return address >= begin_ && address < end_; -} - -} // namespace xc7series -} // namespace xilinx -} // namespace prjxray - -namespace xc7series = prjxray::xilinx::xc7series; - -namespace YAML { - -Node convert::encode( - const xc7series::ConfigurationFrameRange& rhs) { - Node node; - node.SetTag("xilinx/xc7series/configuration_frame_range"); - node["begin"] = rhs.begin(); - node["end"] = rhs.end(); - return node; -} - -bool convert::decode( - const Node& node, - xc7series::ConfigurationFrameRange& lhs) { - if (node.Tag() != "xilinx/xc7series/configuration_frame_range" || - !node["begin"] || !node["end"]) - return false; - - lhs = xc7series::ConfigurationFrameRange( - node["begin"].as(), - node["end"].as()); - return true; -} - -} // namespace YAML