1 // 2 // Copyright 2020 Ettus Research, a National Instruments Brand 3 // 4 // SPDX-License-Identifier: GPL-3.0-or-later 5 // 6 7 #include <uhd/rfnoc/defaults.hpp> 8 #include <uhd/rfnoc/multichan_register_iface.hpp> 9 #include <uhd/rfnoc/property.hpp> 10 #include <uhd/rfnoc/registry.hpp> 11 #include <uhd/rfnoc/switchboard_block_control.hpp> 12 13 using namespace uhd::rfnoc; 14 15 // Register offsets 16 const uint32_t switchboard_block_control::REG_BLOCK_SIZE = 8; 17 const uint32_t switchboard_block_control::REG_DEMUX_SELECT_ADDR = 0; 18 const uint32_t switchboard_block_control::REG_MUX_SELECT_ADDR = 4; 19 20 // User properties 21 const char* const PROP_KEY_INPUT_SELECT = "input_select"; 22 const char* const PROP_KEY_OUTPUT_SELECT = "output_select"; 23 24 class switchboard_block_control_impl : public switchboard_block_control 25 { 26 public: RFNOC_BLOCK_CONSTRUCTOR(switchboard_block_control)27 RFNOC_BLOCK_CONSTRUCTOR(switchboard_block_control), 28 _num_input_ports(get_num_input_ports()), 29 _num_output_ports(get_num_output_ports()), 30 _switchboard_reg_iface(*this, 0, REG_BLOCK_SIZE) 31 { 32 UHD_ASSERT_THROW(_num_input_ports > 0 && _num_output_ports > 0); 33 34 _register_props(); 35 36 // Configure property propagation and action forwarding behavior. 37 set_prop_forwarding_policy(forwarding_policy_t::USE_MAP); 38 set_action_forwarding_policy(forwarding_policy_t::USE_MAP); 39 40 _update_forwarding_map(); 41 } 42 connect(const size_t input,const size_t output)43 void connect(const size_t input, const size_t output) 44 { 45 set_property<int>(PROP_KEY_INPUT_SELECT, static_cast<int>(input), output); 46 set_property<int>(PROP_KEY_OUTPUT_SELECT, static_cast<int>(output), input); 47 48 _update_forwarding_map(); 49 } 50 51 private: 52 const size_t _num_input_ports; 53 const size_t _num_output_ports; 54 _register_props()55 void _register_props() 56 { 57 _input_select.reserve(_num_output_ports); 58 _output_select.reserve(_num_input_ports); 59 60 // Register _input_select properties 61 for (size_t output_port = 0; output_port < _num_output_ports; output_port++) { 62 _input_select.emplace_back(property_t<int>( 63 PROP_KEY_INPUT_SELECT, 0, {res_source_info::USER, output_port})); 64 65 register_property(&_input_select.back(), [this, output_port]() { 66 int select_val = _input_select.at(output_port).get(); 67 if (select_val < 0 68 || static_cast<unsigned int>(select_val) >= _num_input_ports) 69 throw uhd::value_error("Index out of bounds"); 70 _switchboard_reg_iface.poke32( 71 REG_MUX_SELECT_ADDR, select_val, output_port); 72 }); 73 } 74 75 // Register _output_select properties 76 for (size_t input_port = 0; input_port < _num_input_ports; input_port++) { 77 _output_select.emplace_back(property_t<int>( 78 PROP_KEY_OUTPUT_SELECT, 0, {res_source_info::USER, input_port})); 79 80 register_property(&_output_select.back(), [this, input_port]() { 81 int select_val = _output_select.at(input_port).get(); 82 if (select_val < 0 83 || static_cast<unsigned int>(select_val) >= _num_output_ports) 84 throw uhd::value_error("Index out of bounds"); 85 _switchboard_reg_iface.poke32( 86 REG_DEMUX_SELECT_ADDR, select_val, input_port); 87 }); 88 } 89 } 90 _update_forwarding_map()91 void _update_forwarding_map() 92 { 93 node_t::forwarding_map_t prop_fwd_map; 94 node_t::forwarding_map_t action_fwd_map; 95 96 // Property propagation scheme: 97 // Connected inputs and outputs will propagate to each other. 98 // Unconnected inputs and outputs do not propagate. 99 for (size_t input_port = 0; input_port < _num_input_ports; input_port++) { 100 size_t linked_output_port = _output_select.at(input_port).get(); 101 size_t linked_input_port = _input_select.at(linked_output_port).get(); 102 if (linked_input_port == input_port) { 103 prop_fwd_map.insert({{res_source_info::INPUT_EDGE, linked_input_port}, 104 {{res_source_info::OUTPUT_EDGE, linked_output_port}}}); 105 prop_fwd_map.insert({{res_source_info::OUTPUT_EDGE, linked_output_port}, 106 {{res_source_info::INPUT_EDGE, linked_input_port}}}); 107 action_fwd_map.insert({{res_source_info::INPUT_EDGE, linked_input_port}, 108 {{res_source_info::OUTPUT_EDGE, linked_output_port}}}); 109 action_fwd_map.insert({{res_source_info::OUTPUT_EDGE, linked_output_port}, 110 {{res_source_info::INPUT_EDGE, linked_input_port}}}); 111 } 112 } 113 set_prop_forwarding_map(prop_fwd_map); 114 set_action_forwarding_map(action_fwd_map); 115 } 116 117 /************************************************************************** 118 * Attributes 119 *************************************************************************/ 120 std::vector<property_t<int>> _input_select; 121 std::vector<property_t<int>> _output_select; 122 123 /************************************************************************** 124 * Register Interface 125 *************************************************************************/ 126 multichan_register_iface _switchboard_reg_iface; 127 }; 128 129 UHD_RFNOC_BLOCK_REGISTER_DIRECT( 130 switchboard_block_control, SWITCHBOARD_BLOCK, "Switchboard", CLOCK_KEY_GRAPH, "bus_clk") 131