| #ifndef PRJXRAY_LIB_XILINX_XC7SERIES_GLOBAL_CLOCK_REGION_H_ |
| #define PRJXRAY_LIB_XILINX_XC7SERIES_GLOBAL_CLOCK_REGION_H_ |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <map> |
| #include <memory> |
| |
| #include <absl/types/optional.h> |
| #include <prjxray/xilinx/xc7series/configuration_row.h> |
| #include <prjxray/xilinx/xc7series/frame_address.h> |
| #include <yaml-cpp/yaml.h> |
| |
| 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 <typename T> |
| 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<FrameAddress> GetNextFrameAddress( |
| FrameAddress address) const; |
| |
| private: |
| friend struct YAML::convert<GlobalClockRegion>; |
| |
| std::map<unsigned int, Row> rows_; |
| }; |
| |
| template <typename T> |
| 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<prjxray::xilinx::xc7series::GlobalClockRegion> { |
| 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_ |