diff options
author | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-03-19 09:38:51 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-05-28 14:49:32 -0500 |
commit | 9c67396ec175acc84667085a9c8ab2b9247b6eb8 (patch) | |
tree | 146f7fe58690bdb45919f451e5a844191934bd3f | |
parent | 2f134ac1a745491094951d409fcf3f4588d66348 (diff) | |
download | uhd-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.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/defaults.hpp | 1 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/split_stream_block_control.hpp | 63 | ||||
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/rfnoc/split_stream_block_control.cpp | 109 |
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") |