aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Rossetto <aaron.rossetto@ni.com>2020-03-19 09:38:51 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-05-28 14:49:32 -0500
commit9c67396ec175acc84667085a9c8ab2b9247b6eb8 (patch)
tree146f7fe58690bdb45919f451e5a844191934bd3f
parent2f134ac1a745491094951d409fcf3f4588d66348 (diff)
downloaduhd-9c67396ec175acc84667085a9c8ab2b9247b6eb8.tar.gz
uhd-9c67396ec175acc84667085a9c8ab2b9247b6eb8.tar.bz2
uhd-9c67396ec175acc84667085a9c8ab2b9247b6eb8.zip
rfnoc: Add support for Split Stream RFNoC block
The split stream RFNoC block is an RFNoC block that takes in a single CHDR stream and duplicates it, creating a number of output streams for each input stream. Consult the split_stream_block_control class header file for more details on block configuration and behavior, including how property and action forwarding is handled by the block.
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt1
-rw-r--r--host/include/uhd/rfnoc/defaults.hpp1
-rw-r--r--host/include/uhd/rfnoc/split_stream_block_control.hpp63
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/split_stream_block_control.cpp109
5 files changed, 175 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
index 24409fbf9..f86c04850 100644
--- a/host/include/uhd/rfnoc/CMakeLists.txt
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -39,6 +39,7 @@ UHD_INSTALL(FILES
fosphor_block_control.hpp
null_block_control.hpp
radio_control.hpp
+ split_stream_block_control.hpp
vector_iir_block_control.hpp
DESTINATION ${INCLUDE_DIR}/uhd/rfnoc
diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp
index 053834335..ba9907a11 100644
--- a/host/include/uhd/rfnoc/defaults.hpp
+++ b/host/include/uhd/rfnoc/defaults.hpp
@@ -77,6 +77,7 @@ static const noc_id_t DUC_BLOCK = 0xD0C00000;
static const noc_id_t DDC_BLOCK = 0xDDC00000;
static const noc_id_t FIR_FILTER_BLOCK = 0xf1120000;
static const noc_id_t FOSPHOR_BLOCK = 0x666F0000;
+static const noc_id_t SPLIT_STREAM_BLOCK = 0x57570000;
static const noc_id_t VECTOR_IIR_BLOCK = 0x11120000;
}} // namespace uhd::rfnoc
diff --git a/host/include/uhd/rfnoc/split_stream_block_control.hpp b/host/include/uhd/rfnoc/split_stream_block_control.hpp
new file mode 100644
index 000000000..596d7f19c
--- /dev/null
+++ b/host/include/uhd/rfnoc/split_stream_block_control.hpp
@@ -0,0 +1,63 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/config.hpp>
+#include <uhd/rfnoc/noc_block_base.hpp>
+
+namespace uhd { namespace rfnoc {
+
+/*! Split Stream Block Control Class
+ *
+ * The Split Stream Block is an RFNoC block that takes in a single CHDR
+ * stream and duplicates it, creating a number of output streams for each
+ * input stream. The number of streams is defined by the NUM_PORTS parameter
+ * used to instantiate the RFNoC block in the image, while the number of
+ * output branches is defined by the NUM_BRANCH parameter. In software, this
+ * corresponds to an RFNoC block having NUM_PORTS input ports and
+ * NUM_PORTS * NUM_BRANCH output ports.
+ *
+ * Given the following example of a split stream RFNoC block with
+ * NUM_PORTS = 2 and NUM_BRANCH = 3, the input streams map to output branches
+ * and streams as follows. The number located at each input and output
+ * indicates the port number corresponding to that stream and branch:
+ *
+ * +----------+
+ * Stream A --->|0 0|---> Stream A } Branch 0
+ * Stream B --->|1 1|---> Stream B
+ * | 2|---> Stream A } Branch 1
+ * | 3|---> Stream B
+ * | 4|---> Stream A } Branch 2
+ * | 5|---> Stream B
+ * +----------+
+ *
+ * In other words, the port number corresponding to stream S of branch B is
+ * given by B * (num_input_ports) + S.
+ *
+ * \section ss_fwd_behavior Property Propagation and Action Forwarding Behavior
+ *
+ * The default behavior of the split stream block controller is to propagate
+ * properties received on a particular stream to all branches of that stream.
+ * For example, if a property is received at branch 0, stream B in the example
+ * above, that property will be propagated to stream B in branches 1 and 2
+ * AND to stream B in the input. The property will not propagate across
+ * streams.
+ *
+ * For actions, an action received on a particular stream is forwarded to
+ * that stream on *all opposite* branches. If in the example above, an action
+ * is received at branch 2, stream A, it will be forwarded to stream A on the
+ * input side. Similarly, if an action is received on stream B of the input,
+ * it will be forwarded to stream B on branches 0, 1, AND 2.
+ */
+class UHD_API split_stream_block_control : public noc_block_base
+{
+public:
+ RFNOC_DECLARE_BLOCK(split_stream_block_control)
+};
+
+}} // namespace uhd::rfnoc
+
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index c095e86f9..d7c2006d2 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -49,6 +49,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/fosphor_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/null_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/split_stream_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/vector_iir_block_control.cpp
)
diff --git a/host/lib/rfnoc/split_stream_block_control.cpp b/host/lib/rfnoc/split_stream_block_control.cpp
new file mode 100644
index 000000000..17485882a
--- /dev/null
+++ b/host/lib/rfnoc/split_stream_block_control.cpp
@@ -0,0 +1,109 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/convert.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/rfnoc/defaults.hpp>
+#include <uhd/rfnoc/split_stream_block_control.hpp>
+#include <uhd/rfnoc/property.hpp>
+#include <uhd/rfnoc/registry.hpp>
+#include <string>
+
+using namespace uhd::rfnoc;
+
+
+class split_stream_block_control_impl : public split_stream_block_control
+{
+public:
+ RFNOC_BLOCK_CONSTRUCTOR(split_stream_block_control)
+ {
+ // Ensure that the block is configured correctly, i.e., that the
+ // number of output ports is an integer multiple of the number of
+ // input ports, and that there are at least two output branches.
+ const size_t num_input_ports = get_num_input_ports();
+ const size_t num_output_ports = get_num_output_ports();
+ const size_t num_branches = num_output_ports / num_input_ports;
+ UHD_ASSERT_THROW((num_output_ports % num_input_ports == 0) && (num_branches > 1));
+
+ //! Little helper to calculate the output port number given the branch
+ // (0..num_branches) and stream (0..num_input_ports()) numbers.
+ auto calculate_output_port = [num_input_ports, num_branches](
+ size_t branch, size_t stream) -> size_t {
+ UHD_ASSERT_THROW(branch < num_branches);
+ UHD_ASSERT_THROW(stream < num_input_ports);
+ return branch * num_input_ports + stream;
+ };
+
+ // Configure property propagation and action forwarding behavior for
+ // the split stream block.
+ set_prop_forwarding_policy(forwarding_policy_t::USE_MAP);
+ set_action_forwarding_policy(forwarding_policy_t::USE_MAP);
+
+ // Property propagation scheme (X --> Y means 'Properties received on
+ // X propagate to Y'):
+ // Input stream S --> {output branch Bo, stream S} for all
+ // S in streams and Bo in branches
+ // Output branch Bo, stream S --> input stream S for all
+ // S in streams and Bo in branches
+ // Output branch Bo, stream S --> {output branch Bp, stream S}
+ // for all S in stream and Bo, Bp in branches (Bo != Bp)
+ node_t::forwarding_map_t prop_fwd_map;
+ for (size_t stream = 0; stream < num_input_ports; stream++) {
+ std::vector<res_source_info> dest_ports;
+ for (size_t branch = 0; branch < num_branches; branch++) {
+ size_t output_port = calculate_output_port(branch, stream);
+ dest_ports.push_back({res_source_info::OUTPUT_EDGE, output_port});
+ }
+ // Input stream S --> {all output branches, stream S}
+ prop_fwd_map.insert({{res_source_info::INPUT_EDGE, stream}, dest_ports});
+
+ for (size_t branch_a = 0; branch_a < num_branches; branch_a++) {
+ size_t output_port_a = calculate_output_port(branch_a, stream);
+ // The first entry in the back propagation vector is
+ // output branch A, stream S --> input stream S
+ std::vector<res_source_info> dest_ports_back{
+ {res_source_info::INPUT_EDGE, stream}};
+
+ for (size_t branch_b = 0; branch_b < num_branches; branch_b++) {
+ if (branch_a == branch_b) {
+ continue;
+ }
+ size_t output_port_b = calculate_output_port(branch_b, stream);
+ // Add all output branches that are not the 'source'
+ // output port
+ dest_ports_back.push_back(
+ {res_source_info::OUTPUT_EDGE, output_port_b});
+ }
+ prop_fwd_map.insert(
+ {{res_source_info::OUTPUT_EDGE, output_port_a}, dest_ports_back});
+ }
+ }
+ set_prop_forwarding_map(prop_fwd_map);
+
+ // Action forwarding scheme (X --> Y means 'Actions received on
+ // X forward to Y'):
+ // Input stream S --> {output branch Bo, stream S} for all
+ // S in streams and Bo in branches
+ // Output branch Bo, stream S --> input stream S for all
+ // S in streams and Bo in branches
+ node_t::forwarding_map_t action_fwd_map;
+ for (size_t stream = 0; stream < num_input_ports; stream++) {
+ std::vector<res_source_info> dest_ports;
+ for (size_t branch = 0; branch < num_branches; branch++) {
+ size_t output_port = calculate_output_port(branch, stream);
+ dest_ports.push_back({res_source_info::OUTPUT_EDGE, output_port});
+
+ action_fwd_map.insert({{res_source_info::OUTPUT_EDGE, output_port},
+ {{res_source_info::INPUT_EDGE, stream}}});
+ }
+ action_fwd_map.insert({{res_source_info::INPUT_EDGE, stream}, dest_ports});
+ }
+ set_action_forwarding_map(action_fwd_map);
+ }
+};
+
+UHD_RFNOC_BLOCK_REGISTER_DIRECT(
+ split_stream_block_control, SPLIT_STREAM_BLOCK, "SplitStream", CLOCK_KEY_GRAPH, "bus_clk")