1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
//
// Copyright 2019 Ettus Research, a National Instruments Branch
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <uhd/rfnoc/block_id.hpp>
#include <uhd/rfnoc/defaults.hpp>
#include <uhd/rfnoc/graph_edge.hpp>
#include <uhd/rfnoc/noc_block_base.hpp>
#include <uhd/utils/graph_utils.hpp>
#include <uhd/utils/log.hpp>
#include <boost/format.hpp>
#include <numeric>
#include <utility>
namespace uhd { namespace rfnoc {
//! Returns whether or not a block (and port) is know to to terminate data paths
bool check_terminator_block(const block_id_t blk_id, const size_t port)
{
const std::string blk_id_str = blk_id.get_block_name();
for (auto term_block : TERMINATOR_BLOCKS) {
auto optional_port = std::get<1>(term_block);
if (blk_id_str == std::get<0>(term_block)
&& (!optional_port || port == optional_port.get())) {
return true;
}
}
return false;
}
std::vector<graph_edge_t> get_block_chain(const rfnoc_graph::sptr graph,
const block_id_t start_block,
const size_t port,
const bool source_chain)
{
// Enumerate blocks in the chain
auto edges = graph->enumerate_static_connections();
std::vector<graph_edge_t> block_chain;
std::string current_block = start_block.to_string();
size_t current_port = port;
while (true) {
UHD_LOG_TRACE("GRAPH_UTILS",
"Looking for current block " << current_block << ", port " << current_port);
bool next_found = false;
for (auto& edge : edges) {
if ((source_chain)
? (edge.src_blockid == current_block && edge.src_port == current_port)
: (edge.dst_blockid == current_block
&& edge.dst_port == current_port)) {
// If the current block is the edge's source, make the edge's
// destination the current block
next_found = true;
UHD_LOG_TRACE("GRAPH_UTILS", "Found next block: " + edge.dst_blockid);
block_chain.push_back(edge);
current_block = (source_chain) ? edge.dst_blockid : edge.src_blockid;
current_port = (source_chain) ? edge.dst_port : edge.src_port;
// Compare our current block and port
if (check_terminator_block(current_block, current_port)) {
// If we've found a terminating block, stop iterating through the
// edges
break;
}
}
}
if (not next_found) {
UHD_LOG_TRACE(
"GRAPH_UTILS", "Failed to find current block in static connections");
break;
}
if (check_terminator_block(current_block, current_port)) {
// If we've found a terminating block, stop iterating through the edges
break;
}
}
return block_chain;
}
void connect_through_blocks(rfnoc_graph::sptr graph,
const block_id_t src_blk,
const size_t src_port,
const block_id_t dst_blk,
const size_t dst_port)
{
// First, create a chain from the source block to a stream endpoint
auto block_chain = get_block_chain(graph, src_blk, src_port, true);
UHD_LOG_TRACE("GRAPH_UTILS", "Found source chain for " + src_blk.to_string());
// See if dst_blk is in our block_chain already
const bool dst_found = std::accumulate(block_chain.begin(),
block_chain.end(),
false,
[dst_blk, dst_port](bool dst_found, const graph_edge_t edge) {
// This is our "accumulator" function that checks if the current_blk's ID and
// input port match what we're looking for
return dst_found
|| (dst_blk.to_string() == edge.dst_blockid
&& dst_port == edge.dst_port);
});
// If our dst_blk is in the chain already, make sure its the last element and continue
if (dst_found) {
UHD_LOG_TRACE(
"GRAPH_UTILS", "Found dst_blk (" + dst_blk.to_string() + ") in source chain");
while (dst_blk.to_string() == block_chain.back().dst_blockid
&& dst_port == block_chain.back().dst_port) {
UHD_LOG_TRACE("GRAPH_UTILS",
boost::format(
"Last block (%s:%d) doesn't match dst_blk (%s:%d); removing.")
% block_chain.back().dst_blockid % block_chain.back().dst_port
% dst_blk.to_string() % dst_port);
block_chain.pop_back();
}
} else {
// If we hadn't found dst_blk, find it now, then merge the two chain
auto dest_chain = get_block_chain(graph, dst_blk, dst_port, false);
block_chain.insert(block_chain.end(), dest_chain.begin(), dest_chain.end());
UHD_LOG_TRACE(
"GRAPH_UTILS", "Found destination chain for " + dst_blk.to_string());
}
// Finally, make all of the connections in our chain.
// If we have SEPs in the chain, find them and directly
// call connect on the src and dst blocks since calling
// connect on SEPs is invalid
std::string src_to_sep_id;
size_t src_to_sep_port;
std::string sep_to_dst_id;
size_t sep_to_dst_port;
bool has_sep_connection = false;
for (auto edge : block_chain) {
if(uhd::rfnoc::block_id_t(edge.dst_blockid).match(uhd::rfnoc::NODE_ID_SEP)) {
has_sep_connection = true;
src_to_sep_id = edge.src_blockid;
src_to_sep_port = edge.src_port;
} else if(uhd::rfnoc::block_id_t(edge.src_blockid).match(uhd::rfnoc::NODE_ID_SEP)) {
has_sep_connection = true;
sep_to_dst_id = edge.dst_blockid;
sep_to_dst_port = edge.dst_port;
} else{
graph->connect(edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
}
}
if(has_sep_connection) {
graph->connect(src_to_sep_id, src_to_sep_port, sep_to_dst_id, sep_to_dst_port);
}
}
}} // namespace uhd::rfnoc
|