| #ifndef PRJXRAY_LIB_XILINX_XCUSERIES_ROW_H_ | |
| #define PRJXRAY_LIB_XILINX_XCUSERIES_ROW_H_ | |
| #include <algorithm> | |
| #include <cassert> | |
| #include <map> | |
| #include <memory> | |
| #include <absl/types/optional.h> | |
| #include <prjxray/xilinx/xcuseries/block_type.h> | |
| #include <prjxray/xilinx/xcuseries/configuration_bus.h> | |
| #include <prjxray/xilinx/xcuseries/frame_address.h> | |
| #include <yaml-cpp/yaml.h> | |
| namespace prjxray { | |
| namespace xilinx { | |
| namespace xcuseries { | |
| 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 <typename T> | |
| 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<FrameAddress> GetNextFrameAddress( | |
| FrameAddress address) const; | |
| private: | |
| friend struct YAML::convert<Row>; | |
| std::map<BlockType, ConfigurationBus> configuration_buses_; | |
| }; | |
| template <typename T> | |
| Row::Row(T first, T last) { | |
| assert( | |
| std::all_of(first, last, [&](const typename T::value_type& addr) { | |
| return (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 xcuseries | |
| } // namespace xilinx | |
| } // namespace prjxray | |
| namespace YAML { | |
| template <> | |
| struct convert<prjxray::xilinx::xcuseries::Row> { | |
| static Node encode(const prjxray::xilinx::xcuseries::Row& rhs); | |
| static bool decode(const Node& node, | |
| prjxray::xilinx::xcuseries::Row& lhs); | |
| }; | |
| } // namespace YAML | |
| #endif // PRJXRAY_LIB_XILINX_XCUSERIES_ROW_H_ |