uhd/host/lib/rfnoc/switchboard_block_control.cpp
Martin Braun 7f660c232e rfnoc: Update the MTU forwarding property for some blocks
Note that the default MTU forwarding policy is ONE_TO_ONE, therefore,
it is only strictly necessary to modify the MTU forwarding policy for
blocks that route data in a different manner. However, it may be nice to
explicitly state the forwarding policy for the benefit of the reader.

The following blocks had their policies updated:
- addsub: ONE_TO_FAN
- duc: ONE_TO_ONE
- dmafifo: ONE_TO_ONE
- null block: DROP
- replay block: DROP
- split stream: ONE_TO_FAN
- switchboard: ONE_TO_FAN
2022-04-01 14:36:35 -05:00

135 lines
5.5 KiB
C++

//
// 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);
// MTU forwarding doesn't allow for USE_MAP, but we assume that packets
// coming in may potentially go to any output port. We thus fan out the
// MTU propagation.
set_mtu_forwarding_policy(forwarding_policy_t::ONE_TO_FAN);
_update_forwarding_map();
}
void connect(const size_t input, const size_t output) override
{
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")