diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/rfnoc/switchboard_block_control.cpp | 130 |
2 files changed, 131 insertions, 0 deletions
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index 63bdccf4d..a9c3c9ed0 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -53,6 +53,7 @@ LIBUHD_APPEND_SOURCES( ${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}/switchboard_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vector_iir_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/window_block_control.cpp ) diff --git a/host/lib/rfnoc/switchboard_block_control.cpp b/host/lib/rfnoc/switchboard_block_control.cpp new file mode 100644 index 000000000..229c224e9 --- /dev/null +++ b/host/lib/rfnoc/switchboard_block_control.cpp @@ -0,0 +1,130 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/rfnoc/defaults.hpp> +#include <uhd/rfnoc/multichan_register_iface.hpp> +#include <uhd/rfnoc/property.hpp> +#include <uhd/rfnoc/registry.hpp> +#include <uhd/rfnoc/switchboard_block_control.hpp> + +using namespace uhd::rfnoc; + +// Register offsets +const uint32_t switchboard_block_control::REG_BLOCK_SIZE = 8; +const uint32_t switchboard_block_control::REG_DEMUX_SELECT_ADDR = 0; +const uint32_t switchboard_block_control::REG_MUX_SELECT_ADDR = 4; + +// User properties +const char* const PROP_KEY_INPUT_SELECT = "input_select"; +const char* const PROP_KEY_OUTPUT_SELECT = "output_select"; + +class switchboard_block_control_impl : public switchboard_block_control +{ +public: + RFNOC_BLOCK_CONSTRUCTOR(switchboard_block_control), + _num_input_ports(get_num_input_ports()), + _num_output_ports(get_num_output_ports()), + _switchboard_reg_iface(*this, 0, REG_BLOCK_SIZE) + { + UHD_ASSERT_THROW(_num_input_ports > 0 && _num_output_ports > 0); + + _register_props(); + + // Configure property propagation and action forwarding behavior. + set_prop_forwarding_policy(forwarding_policy_t::USE_MAP); + set_action_forwarding_policy(forwarding_policy_t::USE_MAP); + + _update_forwarding_map(); + } + + void connect(const size_t input, const size_t output) + { + set_property<int>(PROP_KEY_INPUT_SELECT, static_cast<int>(input), output); + set_property<int>(PROP_KEY_OUTPUT_SELECT, static_cast<int>(output), input); + + _update_forwarding_map(); + } + +private: + const size_t _num_input_ports; + const size_t _num_output_ports; + + void _register_props() + { + _input_select.reserve(_num_output_ports); + _output_select.reserve(_num_input_ports); + + // Register _input_select properties + for (size_t output_port = 0; output_port < _num_output_ports; output_port++) { + _input_select.emplace_back(property_t<int>( + PROP_KEY_INPUT_SELECT, 0, {res_source_info::USER, output_port})); + + register_property(&_input_select.back(), [this, output_port]() { + int select_val = _input_select.at(output_port).get(); + if (select_val < 0 + || static_cast<unsigned int>(select_val) >= _num_input_ports) + throw uhd::value_error("Index out of bounds"); + _switchboard_reg_iface.poke32( + REG_MUX_SELECT_ADDR, select_val, output_port); + }); + } + + // Register _output_select properties + for (size_t input_port = 0; input_port < _num_input_ports; input_port++) { + _output_select.emplace_back(property_t<int>( + PROP_KEY_OUTPUT_SELECT, 0, {res_source_info::USER, input_port})); + + register_property(&_output_select.back(), [this, input_port]() { + int select_val = _output_select.at(input_port).get(); + if (select_val < 0 + || static_cast<unsigned int>(select_val) >= _num_output_ports) + throw uhd::value_error("Index out of bounds"); + _switchboard_reg_iface.poke32( + REG_DEMUX_SELECT_ADDR, select_val, input_port); + }); + } + } + + void _update_forwarding_map() + { + node_t::forwarding_map_t prop_fwd_map; + node_t::forwarding_map_t action_fwd_map; + + // Property propagation scheme: + // Connected inputs and outputs will propagate to each other. + // Unconnected inputs and outputs do not propagate. + for (size_t input_port = 0; input_port < _num_input_ports; input_port++) { + size_t linked_output_port = _output_select.at(input_port).get(); + size_t linked_input_port = _input_select.at(linked_output_port).get(); + if (linked_input_port == input_port) { + prop_fwd_map.insert({{res_source_info::INPUT_EDGE, linked_input_port}, + {{res_source_info::OUTPUT_EDGE, linked_output_port}}}); + prop_fwd_map.insert({{res_source_info::OUTPUT_EDGE, linked_output_port}, + {{res_source_info::INPUT_EDGE, linked_input_port}}}); + action_fwd_map.insert({{res_source_info::INPUT_EDGE, linked_input_port}, + {{res_source_info::OUTPUT_EDGE, linked_output_port}}}); + action_fwd_map.insert({{res_source_info::OUTPUT_EDGE, linked_output_port}, + {{res_source_info::INPUT_EDGE, linked_input_port}}}); + } + } + set_prop_forwarding_map(prop_fwd_map); + set_action_forwarding_map(action_fwd_map); + } + + /************************************************************************** + * Attributes + *************************************************************************/ + std::vector<property_t<int>> _input_select; + std::vector<property_t<int>> _output_select; + + /************************************************************************** + * Register Interface + *************************************************************************/ + multichan_register_iface _switchboard_reg_iface; +}; + +UHD_RFNOC_BLOCK_REGISTER_DIRECT( + switchboard_block_control, SWITCHBOARD_BLOCK, "Switchboard", CLOCK_KEY_GRAPH, "bus_clk") |