blob: 64b19a950623f7b4d6155392e988c686140e966d [file] [log] [blame]
#ifndef PRJXRAY_LIB_XILINX_XCUSERIES_CONFIGURATION_BUS_H_
#define PRJXRAY_LIB_XILINX_XCUSERIES_CONFIGURATION_BUS_H_
#include <algorithm>
#include <cassert>
#include <map>
#include <memory>
#include <absl/types/optional.h>
#include <prjxray/xilinx/xcuseries/configuration_column.h>
#include <prjxray/xilinx/xcuseries/frame_address.h>
#include <yaml-cpp/yaml.h>
namespace prjxray {
namespace xilinx {
namespace xcuseries {
// 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 <typename T>
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<FrameAddress> GetNextFrameAddress(
FrameAddress address) const;
private:
friend struct YAML::convert<ConfigurationBus>;
std::map<unsigned int, ConfigurationColumn> configuration_columns_;
};
template <typename T>
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.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 xcuseries
} // namespace xilinx
} // namespace prjxray
namespace YAML {
template <>
struct convert<prjxray::xilinx::xcuseries::ConfigurationBus> {
static Node encode(
const prjxray::xilinx::xcuseries::ConfigurationBus& rhs);
static bool decode(const Node& node,
prjxray::xilinx::xcuseries::ConfigurationBus& lhs);
};
} // namespace YAML
#endif // PRJXRAY_LIB_XILINX_XCUSERIES_CONFIGURATION_BUS_H_