aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc/rfnoc_graph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/rfnoc/rfnoc_graph.cpp')
-rw-r--r--host/lib/rfnoc/rfnoc_graph.cpp494
1 files changed, 265 insertions, 229 deletions
diff --git a/host/lib/rfnoc/rfnoc_graph.cpp b/host/lib/rfnoc/rfnoc_graph.cpp
index dd3dd7b90..4bf35cff1 100644
--- a/host/lib/rfnoc/rfnoc_graph.cpp
+++ b/host/lib/rfnoc/rfnoc_graph.cpp
@@ -15,12 +15,18 @@
#include <uhdlib/rfnoc/graph.hpp>
#include <uhdlib/rfnoc/graph_stream_manager.hpp>
#include <uhdlib/rfnoc/rfnoc_device.hpp>
+#include <uhdlib/rfnoc/rfnoc_rx_streamer.hpp>
+#include <uhdlib/rfnoc/rfnoc_tx_streamer.hpp>
#include <uhdlib/utils/narrow.hpp>
+#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp> // FIXME remove when rfnoc_device is ready
#include <memory>
using namespace uhd::rfnoc;
+namespace {
+const std::string LOG_ID("RFNOC::GRAPH");
+}
class rfnoc_graph_impl : public rfnoc_graph
{
@@ -33,6 +39,7 @@ public:
, _graph(std::make_unique<uhd::rfnoc::detail::graph_t>())
{
setup_graph(dev_addr);
+ _init_sep_map();
_init_static_connections();
}
@@ -76,31 +83,136 @@ public:
}
if (!has_block(dst_blk)) {
throw uhd::lookup_error(
- std::string("Cannot connect blocks, source block not found: ")
- + src_blk.to_string());
+ std::string("Cannot connect blocks, destination block not found: ")
+ + dst_blk.to_string());
}
+ auto edge_type = _physical_connect(src_blk, src_port, dst_blk, dst_port);
_connect(get_block(src_blk),
src_port,
get_block(dst_blk),
dst_port,
+ edge_type,
skip_property_propagation);
- _physical_connect(src_blk, src_port, dst_blk, dst_port);
}
- void connect(uhd::tx_streamer& /*streamer*/,
- size_t /*strm_port*/,
- const block_id_t& /*dst_blk*/,
- size_t /*dst_port*/)
+ void connect(uhd::tx_streamer::sptr streamer,
+ size_t strm_port,
+ const block_id_t& dst_blk,
+ size_t dst_port)
{
- throw uhd::not_implemented_error("");
+ // Verify the streamer was created by us
+ auto rfnoc_streamer = boost::dynamic_pointer_cast<rfnoc_tx_streamer>(streamer);
+ if (!rfnoc_streamer) {
+ throw uhd::type_error("Streamer is not rfnoc capable");
+ }
+
+ // Verify src_blk even exists in this graph
+ if (!has_block(dst_blk)) {
+ throw uhd::lookup_error(
+ std::string("Cannot connect block to streamer, source block not found: ")
+ + dst_blk.to_string());
+ }
+
+ // Verify src_blk has an SEP upstream
+ graph_edge_t dst_static_edge = _assert_edge(
+ _get_static_edge(
+ [dst_blk_id = dst_blk.to_string(), dst_port](const graph_edge_t& edge) {
+ return edge.dst_blockid == dst_blk_id && edge.dst_port == dst_port;
+ }),
+ dst_blk.to_string());
+ if (block_id_t(dst_static_edge.src_blockid).get_block_name() != NODE_ID_SEP) {
+ const std::string err_msg =
+ dst_blk.to_string() + ":" + std::to_string(dst_port)
+ + " is not connected to an SEP! Routing impossible.";
+ UHD_LOG_ERROR(LOG_ID, err_msg);
+ throw uhd::routing_error(err_msg);
+ }
+
+ // Now get the name and address of the SEP
+ const std::string sep_block_id = dst_static_edge.src_blockid;
+ const sep_addr_t sep_addr = _sep_map.at(sep_block_id);
+
+ const sw_buff_t pyld_fmt =
+ bits_to_sw_buff(rfnoc_streamer->get_otw_item_comp_bit_width());
+ const sw_buff_t mdata_fmt = BUFF_U64;
+
+ auto xport = _gsm->create_host_to_device_data_stream(sep_addr,
+ pyld_fmt,
+ mdata_fmt,
+ rfnoc_streamer->get_stream_args().args);
+
+ rfnoc_streamer->connect_channel(strm_port, std::move(xport));
+
+ //// If this worked, then also connect the streamer in the BGL graph
+ auto dst = get_block(dst_blk);
+ graph_edge_t edge_info(strm_port, dst_port, graph_edge_t::TX_STREAM, true);
+ _graph->connect(rfnoc_streamer.get(), dst.get(), edge_info);
}
- void connect(const block_id_t& /*src_blk*/,
- size_t /*src_port*/,
- uhd::rx_streamer& /*streamer*/,
- size_t /*strm_port*/)
+ void connect(const block_id_t& src_blk,
+ size_t src_port,
+ uhd::rx_streamer::sptr streamer,
+ size_t strm_port)
{
- throw uhd::not_implemented_error("");
+ // Verify the streamer was created by us
+ auto rfnoc_streamer = boost::dynamic_pointer_cast<rfnoc_rx_streamer>(streamer);
+ if (!rfnoc_streamer) {
+ throw uhd::type_error("Streamer is not rfnoc capable");
+ }
+
+ // Verify src_blk even exists in this graph
+ if (!has_block(src_blk)) {
+ throw uhd::lookup_error(
+ std::string("Cannot connect block to streamer, source block not found: ")
+ + src_blk.to_string());
+ }
+
+ // Verify src_blk has an SEP downstream
+ graph_edge_t src_static_edge = _assert_edge(
+ _get_static_edge(
+ [src_blk_id = src_blk.to_string(), src_port](const graph_edge_t& edge) {
+ return edge.src_blockid == src_blk_id && edge.src_port == src_port;
+ }),
+ src_blk.to_string());
+ if (block_id_t(src_static_edge.dst_blockid).get_block_name() != NODE_ID_SEP) {
+ const std::string err_msg =
+ src_blk.to_string() + ":" + std::to_string(src_port)
+ + " is not connected to an SEP! Routing impossible.";
+ UHD_LOG_ERROR(LOG_ID, err_msg);
+ throw uhd::routing_error(err_msg);
+ }
+
+ // Now get the name and address of the SEP
+ const std::string sep_block_id = src_static_edge.dst_blockid;
+ const sep_addr_t sep_addr = _sep_map.at(sep_block_id);
+
+ const sw_buff_t pyld_fmt =
+ bits_to_sw_buff(rfnoc_streamer->get_otw_item_comp_bit_width());
+ const sw_buff_t mdata_fmt = BUFF_U64;
+
+ auto xport = _gsm->create_device_to_host_data_stream(sep_addr,
+ pyld_fmt,
+ mdata_fmt,
+ rfnoc_streamer->get_stream_args().args);
+
+ rfnoc_streamer->connect_channel(strm_port, std::move(xport));
+
+ // If this worked, then also connect the streamer in the BGL graph
+ auto src = get_block(src_blk);
+ graph_edge_t edge_info(src_port, strm_port, graph_edge_t::RX_STREAM, true);
+ _graph->connect(src.get(), rfnoc_streamer.get(), edge_info);
+ }
+
+ uhd::rx_streamer::sptr create_rx_streamer(
+ const size_t num_chans, const uhd::stream_args_t& args)
+ {
+ return boost::make_shared<rfnoc_rx_streamer>(num_chans, args);
+ }
+
+ uhd::tx_streamer::sptr create_tx_streamer(
+ const size_t num_chans, const uhd::stream_args_t& args)
+ {
+ return boost::make_shared<rfnoc_tx_streamer>(num_chans, args);
}
std::shared_ptr<mb_controller> get_mb_controller(const size_t mb_index = 0)
@@ -152,7 +264,7 @@ private:
throw uhd::key_error(std::string("Found no RFNoC devices for ----->\n")
+ dev_addr.to_pp_string());
}
- _tree = _device->get_tree();
+ _tree = _device->get_tree();
_num_mboards = _tree->list("/mboards").size();
for (size_t i = 0; i < _num_mboards; ++i) {
_mb_controllers.emplace(i, _device->get_mb_controller(i));
@@ -170,7 +282,8 @@ private:
try {
_gsm = graph_stream_manager::make(pkt_factory, epid_alloc, links);
} catch (uhd::io_error& ex) {
- UHD_LOG_ERROR("RFNOC::GRAPH", "IO Error during GSM initialization. " << ex.what());
+ UHD_LOG_ERROR(
+ "RFNOC::GRAPH", "IO Error during GSM initialization. " << ex.what());
throw;
}
@@ -187,6 +300,9 @@ private:
_gsm->connect_host_to_device(ctrl_sep_addr);
// Grab and stash the Client Zero for this mboard
detail::client_zero::sptr mb_cz = _gsm->get_client_zero(ctrl_sep_addr);
+ // Client zero port numbers are based on the control xbar numbers,
+ // which have the client 0 interface first, followed by stream
+ // endpoints, and then the blocks.
_client_zeros.emplace(mb_idx, mb_cz);
const size_t num_blocks = mb_cz->get_num_blocks();
@@ -204,7 +320,7 @@ private:
// Iterate through and register each of the blocks in this mboard
for (size_t portno = 0; portno < num_blocks; ++portno) {
- auto noc_id = mb_cz->get_noc_id(portno + first_block_port);
+ auto noc_id = mb_cz->get_noc_id(portno + first_block_port);
auto block_factory_info = factory::get_block_factory(noc_id);
auto block_info = mb_cz->get_block_info(portno + first_block_port);
block_id_t block_id(mb_idx,
@@ -222,24 +338,25 @@ private:
// iface object through the mb_iface
auto ctrlport_clk_iface =
mb.get_clock_iface(block_factory_info.ctrlport_clk);
- auto tb_clk_iface = (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) ?
- std::make_shared<clock_iface>(CLOCK_KEY_GRAPH) :
- mb.get_clock_iface(block_factory_info.timebase_clk);
+ auto tb_clk_iface =
+ (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH)
+ ? std::make_shared<clock_iface>(CLOCK_KEY_GRAPH)
+ : mb.get_clock_iface(block_factory_info.timebase_clk);
// A "graph" clock is always "running"
if (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) {
tb_clk_iface->set_running(true);
}
- auto block_reg_iface = _gsm->get_block_register_iface(ctrl_sep_addr,
+ auto block_reg_iface = _gsm->get_block_register_iface(ctrl_sep_addr,
portno,
*ctrlport_clk_iface.get(),
*tb_clk_iface.get());
- auto make_args_uptr = std::make_unique<noc_block_base::make_args_t>();
+ auto make_args_uptr = std::make_unique<noc_block_base::make_args_t>();
make_args_uptr->noc_id = noc_id;
- make_args_uptr->block_id = block_id;
- make_args_uptr->num_input_ports = block_info.num_inputs;
- make_args_uptr->num_output_ports = block_info.num_outputs;
- make_args_uptr->reg_iface = block_reg_iface;
- make_args_uptr->tb_clk_iface = tb_clk_iface;
+ make_args_uptr->block_id = block_id;
+ make_args_uptr->num_input_ports = block_info.num_inputs;
+ make_args_uptr->num_output_ports = block_info.num_outputs;
+ make_args_uptr->reg_iface = block_reg_iface;
+ make_args_uptr->tb_clk_iface = tb_clk_iface;
make_args_uptr->ctrlport_clk_iface = ctrlport_clk_iface;
make_args_uptr->mb_control = (factory::has_requested_mb_access(noc_id)
? _mb_controllers.at(mb_idx)
@@ -262,40 +379,43 @@ private:
_block_registry->init_props();
}
+ void _init_sep_map()
+ {
+ for (size_t mb_idx = 0; mb_idx < get_num_mboards(); ++mb_idx) {
+ auto remote_device_id = _device->get_mb_iface(mb_idx).get_remote_device_id();
+ auto& cz = _client_zeros.at(mb_idx);
+ for (size_t sep_idx = 0; sep_idx < cz->get_num_stream_endpoints();
+ ++sep_idx) {
+ // Register ID in _port_block_map
+ block_id_t id(mb_idx, NODE_ID_SEP, sep_idx);
+ _port_block_map.insert({{mb_idx, sep_idx + 1}, id});
+ _sep_map.insert({id.to_string(), sep_addr_t(remote_device_id, sep_idx)});
+ }
+ }
+ }
+
void _init_static_connections()
{
UHD_LOG_TRACE("RFNOC::GRAPH", "Identifying static connections...");
for (auto& kv_cz : _client_zeros) {
- auto& adjacency_list = kv_cz.second->get_adjacency_list();
- const size_t first_block_port = 1 + kv_cz.second->get_num_stream_endpoints();
-
+ auto& adjacency_list = kv_cz.second->get_adjacency_list();
for (auto& edge : adjacency_list) {
// Assemble edge
auto graph_edge = graph_edge_t();
- if (edge.src_blk_index < first_block_port) {
- block_id_t id(kv_cz.first, NODE_ID_SEP, edge.src_blk_index - 1);
- _port_block_map.insert({{kv_cz.first, edge.src_blk_index}, id});
- graph_edge.src_blockid = id.to_string();
- } else {
- graph_edge.src_blockid =
- _port_block_map.at({kv_cz.first, edge.src_blk_index});
- }
- if (edge.dst_blk_index < first_block_port) {
- block_id_t id(kv_cz.first, NODE_ID_SEP, edge.dst_blk_index - 1);
- _port_block_map.insert({{kv_cz.first, edge.dst_blk_index}, id});
- graph_edge.dst_blockid = id.to_string();
- } else {
- graph_edge.dst_blockid =
- _port_block_map.at({kv_cz.first, edge.dst_blk_index});
- }
+ UHD_ASSERT_THROW(
+ _port_block_map.count({kv_cz.first, edge.src_blk_index}));
+ graph_edge.src_blockid =
+ _port_block_map.at({kv_cz.first, edge.src_blk_index});
+ UHD_ASSERT_THROW(
+ _port_block_map.count({kv_cz.first, edge.dst_blk_index}));
+ graph_edge.dst_blockid =
+ _port_block_map.at({kv_cz.first, edge.dst_blk_index});
graph_edge.src_port = edge.src_blk_port;
graph_edge.dst_port = edge.dst_blk_port;
graph_edge.edge = graph_edge_t::edge_t::STATIC;
_static_edges.push_back(graph_edge);
- UHD_LOG_TRACE("RFNOC::GRAPH",
- "Static connection: "
- << graph_edge.src_blockid << ":" << graph_edge.src_port << " -> "
- << graph_edge.dst_blockid << ":" << graph_edge.dst_port);
+ UHD_LOG_TRACE(
+ "RFNOC::GRAPH", "Static connection: " << graph_edge.to_string());
}
}
}
@@ -312,214 +432,98 @@ private:
size_t src_port,
std::shared_ptr<node_t> dst_blk,
size_t dst_port,
+ graph_edge_t::edge_t edge_type,
bool skip_property_propagation)
{
graph_edge_t edge_info(
- src_port, dst_port, graph_edge_t::DYNAMIC, not skip_property_propagation);
+ src_port, dst_port, edge_type, not skip_property_propagation);
edge_info.src_blockid = src_blk->get_unique_id();
edge_info.dst_blockid = dst_blk->get_unique_id();
_graph->connect(src_blk.get(), dst_blk.get(), edge_info);
}
- /*! Helper method to find a stream endpoint connected to a block
- *
- * \param blk_id the block connected to the stream endpoint
- * \param port the port connected to the stream endpoint
- * \param blk_is_src true if the block is a data source, false if it is a
- * destination
- * \return the address of the stream endpoint, or boost::none if it is not
- * directly connected to a stream endpoint
- */
- boost::optional<sep_addr_t> _get_adjacent_sep(
- const block_id_t& blk_id, const size_t port, const bool blk_is_src) const
- {
- const std::string block_id_str = get_block(blk_id)->get_block_id().to_string();
- UHD_LOG_TRACE("RFNOC::GRAPH",
- "Finding SEP for " << (blk_is_src ? "source" : "dst") << " block "
- << block_id_str << ":" << port);
- // TODO: This is an attempt to simplify the algo, but it turns out to be
- // as many lines as before:
- //auto edge_predicate = [blk_is_src, block_id_str](const graph_edge_t edge) {
- //if (blk_is_src) {
- //return edge.src_blockid == block_id_str;
- //}
- //return edge.dst_blockid == block_id_str;
- //};
-
- //auto blk_edge_it =
- //std::find_if(_static_edges.cbegin(), _static_edges.cend(), edge_predicate);
- //if (blk_edge_it == _static_edges.cend()) {
- //return boost::none;
- //}
-
- //const std::string sep_block_id = blk_is_src ?
- //blk_edge_it->dst_blockid : blk_edge_it->src_blockid;
- //UHD_LOG_TRACE("RFNOC::GRAPH",
- //"Found SEP: " << sep_block_id);
-
- //auto port_map_result = std::find_if(_port_block_map.cbegin(),
- //_port_block_map.cend,
- //[sep_block_id](std::pair<std::pair<size_t, size_t>, block_id_t> port_block) {
- //return port_block.second == sep_block_id;
- //});
- //if (port_map_result == _port_block_map.cend()) {
- //throw uhd::lookup_error(
- //std::string("SEP `") + sep_block_id + "' not found in port/block map!");
- //}
- //const auto dev = _device->get_mb_iface(mb_idx).get_remote_device_id();
- //const sep_inst_t sep_inst = blk_is_src ?
- //edge.dst_blk_index - 1 : edge.src_blk_index - 1;
- //return sep_addr_t(dev, sep_inst);
-
- const auto& info = _xbar_block_config.at(block_id_str);
- const auto mb_idx = blk_id.get_device_no();
- const auto cz = _client_zeros.at(mb_idx);
-
- const size_t first_block_port = 1 + cz->get_num_stream_endpoints();
-
- for (const auto& edge : cz->get_adjacency_list()) {
- const auto edge_blk_idx = blk_is_src ? edge.src_blk_index
- : edge.dst_blk_index;
- const auto edge_blk_port = blk_is_src ? edge.src_blk_port : edge.dst_blk_port;
-
- if ((edge_blk_idx == info.xbar_port + first_block_port)
- and (edge_blk_port == port)) {
- UHD_LOGGER_DEBUG("RFNOC::GRAPH")
- << boost::format("Block found in adjacency list. %d:%d->%d:%d")
- % edge.src_blk_index
- % static_cast<unsigned int>(edge.src_blk_port)
- % edge.dst_blk_index
- % static_cast<unsigned int>(edge.dst_blk_port);
-
- // Check that the block is connected to a stream endpoint. The
- // minus one here is because index zero is client 0.
- const sep_inst_t sep_inst = blk_is_src ?
- edge.dst_blk_index - 1 : edge.src_blk_index - 1;
-
- if (sep_inst < cz->get_num_stream_endpoints()) {
- const auto dev = _device->get_mb_iface(mb_idx).get_remote_device_id();
- return sep_addr_t(dev, sep_inst);
- } else {
- // Block is connected to another block
- return boost::none;
- }
- }
- }
- return boost::none;
- }
-
/*! Internal physical connection helper
*
* Make the connections in the physical device
*
- * \throws connect_disallowed_on_src
- * if the source port is statically connected to a *different* block
- * \throws connect_disallowed_on_dst
- * if the destination port is statically connected to a *different* block
+ * \throws uhd::routing_error
+ * if the blocks are statically connected to something else
*/
- void _physical_connect(const block_id_t& src_blk,
+ graph_edge_t::edge_t _physical_connect(const block_id_t& src_blk,
size_t src_port,
const block_id_t& dst_blk,
size_t dst_port)
{
- auto src_blk_ctrl = get_block(src_blk);
- auto dst_blk_ctrl = get_block(dst_blk);
-
- /*
- * Start by determining if the connection can be made
- * Get the adjacency list and check if the connection is in it already
- */
- // Read the adjacency list for the source and destination blocks
- auto src_mb_idx = src_blk.get_device_no();
- auto src_cz = _gsm->get_client_zero(
- sep_addr_t(_device->get_mb_iface(src_mb_idx).get_remote_device_id(), 0));
- std::vector<detail::client_zero::edge_def_t>& adj_list =
- src_cz->get_adjacency_list();
- // Check the src_blk
- auto src_blk_xbar_info =
- _xbar_block_config.at(src_blk_ctrl->get_block_id().to_string());
- // This "xbar_port" starts at the first block, so we need to add the client zero
- // and stream endpoint ports
- const auto src_xbar_port =
- src_blk_xbar_info.xbar_port + src_cz->get_num_stream_endpoints() + 1;
- // We can also find out which stream endpoint the src block is connected to
- sep_inst_t src_sep;
- for (detail::client_zero::edge_def_t edge : adj_list) {
- if ((edge.src_blk_index == src_xbar_port)
- and (edge.src_blk_port == src_port)) {
- UHD_LOGGER_DEBUG("RFNOC::GRAPH")
- << boost::format("Block found in adjacency list. %d:%d->%d:%d")
- % edge.src_blk_index
- % static_cast<unsigned int>(edge.src_blk_port)
- % edge.dst_blk_index
- % static_cast<unsigned int>(edge.dst_blk_port);
- if (edge.dst_blk_index <= src_cz->get_num_stream_endpoints()) {
- src_sep =
- edge.dst_blk_index - 1 /* minus 1 because port 0 is client zero*/;
- } else {
- // TODO connect_disallowed_on_src?
- // TODO put more info in exception
- throw uhd::routing_error(
- "Unable to connect to statically connected source port");
- }
- }
+ const std::string src_blk_info =
+ src_blk.to_string() + ":" + std::to_string(src_port);
+ const std::string dst_blk_info =
+ dst_blk.to_string() + ":" + std::to_string(dst_port);
+
+ // Find the static edge for src_blk:src_port
+ graph_edge_t src_static_edge = _assert_edge(
+ _get_static_edge(
+ [src_blk_id = src_blk.to_string(), src_port](const graph_edge_t& edge) {
+ return edge.src_blockid == src_blk_id && edge.src_port == src_port;
+ }),
+ src_blk_info);
+
+ // Now see if it's already connected to the destination
+ if (src_static_edge.dst_blockid == dst_blk.to_string()
+ && src_static_edge.dst_port == dst_port) {
+ UHD_LOG_TRACE(LOG_ID,
+ "Blocks " << src_blk_info << " and " << dst_blk_info
+ << " are already statically connected, no physical connection "
+ "required.");
+ return graph_edge_t::STATIC;
}
- // Read the dst adjacency list if its different
- // TODO they may be on the same mboard, which would make this redundant
- auto dst_mb_idx = dst_blk.get_device_no();
- auto dst_cz = _gsm->get_client_zero(
- sep_addr_t(_device->get_mb_iface(dst_mb_idx).get_remote_device_id(), 0));
- adj_list = dst_cz->get_adjacency_list();
- // Check the dst blk
- auto dst_blk_xbar_info =
- _xbar_block_config.at(dst_blk_ctrl->get_block_id().to_string());
- // This "xbar_port" starts at the first block, so we need to add the client zero
- // and stream endpoint ports
- const auto dst_xbar_port =
- dst_blk_xbar_info.xbar_port + dst_cz->get_num_stream_endpoints() + 1;
- // We can also find out which stream endpoint the dst block is connected to
- sep_inst_t dst_sep;
- for (detail::client_zero::edge_def_t edge : adj_list) {
- if ((edge.dst_blk_index == dst_xbar_port)
- and (edge.dst_blk_port == dst_port)) {
- UHD_LOGGER_DEBUG("RFNOC::GRAPH")
- << boost::format("Block found in adjacency list. %d:%d->%d:%d")
- % edge.src_blk_index
- % static_cast<unsigned int>(edge.src_blk_port)
- % edge.dst_blk_index
- % static_cast<unsigned int>(edge.dst_blk_port);
- if (edge.src_blk_index <= dst_cz->get_num_stream_endpoints()) {
- dst_sep =
- edge.src_blk_index - 1 /* minus 1 because port 0 is client zero*/;
- } else {
- // TODO connect_disallowed_on_dst?
- // TODO put more info in exception
- throw uhd::routing_error(
- "Unable to connect to statically connected destination port");
- }
- }
+ // If they're not statically connected, the source *must* be connected
+ // to an SEP, or this route is impossible
+ if (block_id_t(src_static_edge.dst_blockid).get_block_name() != NODE_ID_SEP) {
+ const std::string err_msg =
+ src_blk_info + " is neither statically connected to " + dst_blk_info
+ + " nor to an SEP! Routing impossible.";
+ UHD_LOG_ERROR(LOG_ID, err_msg);
+ throw uhd::routing_error(err_msg);
}
- /* TODO: we checked if either port is used in a static connection (and its not if
- * we've made it this far). We also need to check something else, but I can't
- * remember what...
- */
-
- // At this point, we know the attempted connection is valid, so let's go ahead and
- // make it
- sep_addr_t src_sep_addr(
- _device->get_mb_iface(src_mb_idx).get_remote_device_id(), src_sep);
- sep_addr_t dst_sep_addr(
- _device->get_mb_iface(dst_mb_idx).get_remote_device_id(), dst_sep);
+ // OK, now we know which source SEP we have
+ const std::string src_sep_info = src_static_edge.dst_blockid;
+ const sep_addr_t src_sep_addr = _sep_map.at(src_sep_info);
+
+ // Now find the static edge for the destination SEP
+ auto dst_static_edge = _assert_edge(
+ _get_static_edge(
+ [dst_blk_id = dst_blk.to_string(), dst_port](const graph_edge_t& edge) {
+ return edge.dst_blockid == dst_blk_id && edge.dst_port == dst_port;
+ }),
+ dst_blk_info);
+
+ // If they're not statically connected, the source *must* be connected
+ // to an SEP, or this route is impossible
+ if (block_id_t(dst_static_edge.src_blockid).get_block_name() != NODE_ID_SEP) {
+ const std::string err_msg =
+ dst_blk_info + " is neither statically connected to " + src_blk_info
+ + " nor to an SEP! Routing impossible.";
+ UHD_LOG_ERROR(LOG_ID, err_msg);
+ throw uhd::routing_error(err_msg);
+ }
+
+ // OK, now we know which destination SEP we have
+ const std::string dst_sep_info = dst_static_edge.src_blockid;
+ const sep_addr_t dst_sep_addr = _sep_map.at(dst_sep_info);
+
+ // Now all we need to do is dynamically connect those SEPs
auto strm_info = _gsm->create_device_to_device_data_stream(
dst_sep_addr, src_sep_addr, false, 0.1, 0.0, false);
- UHD_LOGGER_INFO("RFNOC::GRAPH")
+ UHD_LOGGER_DEBUG(LOG_ID)
<< boost::format("Data stream between EPID %d and EPID %d established "
"where downstream buffer can hold %lu bytes and %u packets")
% std::get<0>(strm_info).first % std::get<0>(strm_info).second
% std::get<1>(strm_info).bytes % std::get<1>(strm_info).packets;
+
+ return graph_edge_t::DYNAMIC;
}
//! Flush and reset each connected port on the mboard
@@ -541,6 +545,35 @@ private:
mb_cz->reset_ctrl(block_portno);
}
}
+
+ /*! Find the static edge that matches \p pred
+ *
+ * \throws uhd::assertion_error if the edge can't be found. So be careful!
+ */
+ template <typename UnaryPredicate>
+ boost::optional<graph_edge_t> _get_static_edge(UnaryPredicate&& pred)
+ {
+ auto edge_it = std::find_if(_static_edges.cbegin(), _static_edges.cend(), pred);
+ if (edge_it == _static_edges.cend()) {
+ return boost::none;
+ }
+ return *edge_it;
+ }
+
+ /*! Make sure an optional edge info is valid, or throw.
+ */
+ graph_edge_t _assert_edge(
+ boost::optional<graph_edge_t> edge_o, const std::string& blk_info)
+ {
+ if (!bool(edge_o)) {
+ const std::string err_msg = std::string("Cannot connect block ") + blk_info
+ + ", port is unconnected in the FPGA!";
+ UHD_LOG_ERROR("RFNOC::GRAPH", err_msg);
+ throw uhd::routing_error(err_msg);
+ }
+ return edge_o.get();
+ }
+
/**************************************************************************
* Attributes
*************************************************************************/
@@ -580,6 +613,9 @@ private:
// or SEP
std::map<std::pair<size_t, size_t>, block_id_t> _port_block_map;
+ //! Map SEP block ID (e.g. 0/SEP#0) onto a sep_addr_t
+ std::unordered_map<std::string, sep_addr_t> _sep_map;
+
//! List of statically connected edges. Includes SEPs too!
std::vector<graph_edge_t> _static_edges;