diff options
author | Lars Amsel <lars.amsel@ni.com> | 2021-12-03 13:02:09 +0100 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2022-01-10 14:56:35 -0600 |
commit | 3e5e4eb06c0ea6337464cbda0648a75bf76cca17 (patch) | |
tree | a39eb76a91b19ba5f38aacafd844e869bc459319 /host/lib/rfnoc | |
parent | 0e7553cd1a8758a8488afc2efaff7295b351e7fe (diff) | |
download | uhd-3e5e4eb06c0ea6337464cbda0648a75bf76cca17.tar.gz uhd-3e5e4eb06c0ea6337464cbda0648a75bf76cca17.tar.bz2 uhd-3e5e4eb06c0ea6337464cbda0648a75bf76cca17.zip |
rfnoc: Add atomic item size property for RFNoC blocks
An RFNoC block (like the radio) might require a minimal number of
items in each clock cycle, e.g. the radio has to process
SPC (samples per cycle). Because data in RFNoC is transmitted and
processed in packets, we have to make sure the items inside these
packets are a multiple of the items processed in each cycle.
This commit adds an atomic item size properties which is set by
the radio and adapted by the streamers. The streamers adapt the
SPP property of the radio block controller depending on the MTU
value. This might lead to an SPP value which does not align with
the SPC value of the radio block, hence we add a property resolver
for the atomic item size.
Diffstat (limited to 'host/lib/rfnoc')
-rw-r--r-- | host/lib/rfnoc/radio_control_impl.cpp | 37 | ||||
-rw-r--r-- | host/lib/rfnoc/rfnoc_rx_streamer.cpp | 33 | ||||
-rw-r--r-- | host/lib/rfnoc/rfnoc_tx_streamer.cpp | 32 |
3 files changed, 92 insertions, 10 deletions
diff --git a/host/lib/rfnoc/radio_control_impl.cpp b/host/lib/rfnoc/radio_control_impl.cpp index a5c69e229..a08470d8a 100644 --- a/host/lib/rfnoc/radio_control_impl.cpp +++ b/host/lib/rfnoc/radio_control_impl.cpp @@ -9,6 +9,7 @@ #include <uhd/rfnoc/multichan_register_iface.hpp> #include <uhd/rfnoc/register_iface.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/math.hpp> #include <uhdlib/rfnoc/radio_control_impl.hpp> #include <uhdlib/utils/compat_check.hpp> #include <map> @@ -106,6 +107,8 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args) }); // Register spp properties and resolvers _spp_prop.reserve(get_num_output_ports()); + _atomic_item_size_in.reserve(get_num_input_ports()); + _atomic_item_size_out.reserve(get_num_output_ports()); _samp_rate_in.reserve(get_num_input_ports()); _samp_rate_out.reserve(get_num_output_ports()); _type_in.reserve(get_num_input_ports()); @@ -116,6 +119,14 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args) get_max_spp(get_max_payload_size({res_source_info::OUTPUT_EDGE, chan})); _spp_prop.push_back( property_t<int>(PROP_KEY_SPP, default_spp, {res_source_info::USER, chan})); + _atomic_item_size_in.push_back( + property_t<size_t>(PROP_KEY_ATOMIC_ITEM_SIZE, + get_atomic_item_size(), + {res_source_info::INPUT_EDGE, chan})); + _atomic_item_size_out.push_back( + property_t<size_t>(PROP_KEY_ATOMIC_ITEM_SIZE, + get_atomic_item_size(), + {res_source_info::OUTPUT_EDGE, chan})); _samp_rate_in.push_back(property_t<double>( PROP_KEY_SAMP_RATE, get_tick_rate(), {res_source_info::INPUT_EDGE, chan})); _samp_rate_out.push_back(property_t<double>( @@ -132,6 +143,8 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args) _radio_reg_iface.poke32( regmap::REG_RX_MAX_WORDS_PER_PKT, words_per_pkt, chan); }); + register_property(&_atomic_item_size_in.back()); + register_property(&_atomic_item_size_out.back()); register_property(&_samp_rate_in.back()); register_property(&_samp_rate_out.back()); register_property(&_type_in.back()); @@ -163,6 +176,30 @@ radio_control_impl::radio_control_impl(make_args_ptr make_args) "spp must be greater than zero! Coercing to " << spp.get()); } }); + add_property_resolver({&_atomic_item_size_in.back(), + get_mtu_prop_ref({res_source_info::INPUT_EDGE, chan})}, + {&_atomic_item_size_in.back()}, + [this, chan, + &ais_in = _atomic_item_size_in.back()]() { + ais_in = uhd::math::lcm<size_t>(ais_in, get_atomic_item_size()); + ais_in = std::min<size_t>(ais_in, get_mtu({res_source_info::INPUT_EDGE, chan})); + if (ais_in.get() % get_atomic_item_size() > 0) { + ais_in = ais_in - (ais_in.get() % get_atomic_item_size()); + } + RFNOC_LOG_TRACE("Resolve atomic item size in to " << ais_in); + }); + add_property_resolver({&_atomic_item_size_out.back(), + get_mtu_prop_ref({res_source_info::OUTPUT_EDGE, chan})}, + {&_atomic_item_size_out.back()}, + [this, chan, + &ais_out = _atomic_item_size_out.back()]() { + ais_out = uhd::math::lcm<size_t>(ais_out, get_atomic_item_size()); + ais_out = std::min<size_t>(ais_out, get_mtu({res_source_info::OUTPUT_EDGE, chan})); + if (ais_out.get() % get_atomic_item_size() > 0) { + ais_out = ais_out - (ais_out.get() % get_atomic_item_size()); + } + RFNOC_LOG_TRACE("Resolve atomic item size out to " << ais_out); + }); // Note: The following resolver calls coerce_rate(), which is virtual. // At run time, it will use the implementation by the child class. add_property_resolver({&_samp_rate_in.back(), &_samp_rate_out.back()}, diff --git a/host/lib/rfnoc/rfnoc_rx_streamer.cpp b/host/lib/rfnoc/rfnoc_rx_streamer.cpp index d57b8aab2..5e6dddcbe 100644 --- a/host/lib/rfnoc/rfnoc_rx_streamer.cpp +++ b/host/lib/rfnoc/rfnoc_rx_streamer.cpp @@ -59,6 +59,7 @@ rfnoc_rx_streamer::rfnoc_rx_streamer(const size_t num_chans, _tick_rate_in.reserve(num_chans); _type_in.reserve(num_chans); _mtu_in.reserve(num_chans); + _atomic_item_size_in.reserve(num_chans); for (size_t i = 0; i < num_chans; i++) { _register_props(i, stream_args.otw_format); @@ -188,13 +189,16 @@ void rfnoc_rx_streamer::_register_props(const size_t chan, const std::string& ot PROP_KEY_TYPE, otw_format, {res_source_info::INPUT_EDGE, chan})); _mtu_in.emplace_back( property_t<size_t>(PROP_KEY_MTU, get_mtu(), {res_source_info::INPUT_EDGE, chan})); + _atomic_item_size_in.emplace_back( + property_t<size_t>(PROP_KEY_ATOMIC_ITEM_SIZE, 1, {res_source_info::INPUT_EDGE, chan})); // Give us some shorthands for the rest of this function - property_t<double>* scaling_in = &_scaling_in.back(); - property_t<double>* samp_rate_in = &_samp_rate_in.back(); - property_t<double>* tick_rate_in = &_tick_rate_in.back(); - property_t<std::string>* type_in = &_type_in.back(); - property_t<size_t>* mtu_in = &_mtu_in.back(); + property_t<double>* scaling_in = &_scaling_in.back(); + property_t<double>* samp_rate_in = &_samp_rate_in.back(); + property_t<double>* tick_rate_in = &_tick_rate_in.back(); + property_t<std::string>* type_in = &_type_in.back(); + property_t<size_t>* mtu_in = &_mtu_in.back(); + property_t<size_t>* atomic_item_size_in = &_atomic_item_size_in.back(); // Register them register_property(scaling_in); @@ -202,6 +206,7 @@ void rfnoc_rx_streamer::_register_props(const size_t chan, const std::string& ot register_property(tick_rate_in); register_property(type_in); register_property(mtu_in); + register_property(atomic_item_size_in); // Add resolvers add_property_resolver({scaling_in}, {}, [& scaling_in = *scaling_in, chan, this]() { @@ -228,6 +233,24 @@ void rfnoc_rx_streamer::_register_props(const size_t chan, const std::string& ot this->set_tick_rate(tick_rate_in.get()); } }); + + add_property_resolver( + {atomic_item_size_in, mtu_in}, {}, [&ais = *atomic_item_size_in, chan, this]() { + const auto UHD_UNUSED(log_chan) = chan; + RFNOC_LOG_TRACE("Calling resolver for `atomic_item_size'@" << chan); + if (ais.is_valid()) { + const auto spp = this->rx_streamer_impl::get_max_num_samps(); + if (spp < ais.get()) { + throw uhd::value_error("samples per package must not be smaller than atomic item size"); + } + const auto misalignment = spp % ais.get(); + RFNOC_LOG_TRACE("Check atomic item size " << ais.get() << " divides spp " << spp); + if (misalignment > 0) { + RFNOC_LOG_TRACE("Reduce spp by " << misalignment << " to align with atomic item size"); + this->rx_streamer_impl::set_max_num_samps(spp - misalignment); + } + } + }); } void rfnoc_rx_streamer::_handle_rx_event_action( diff --git a/host/lib/rfnoc/rfnoc_tx_streamer.cpp b/host/lib/rfnoc/rfnoc_tx_streamer.cpp index 969c41ae6..411affe62 100644 --- a/host/lib/rfnoc/rfnoc_tx_streamer.cpp +++ b/host/lib/rfnoc/rfnoc_tx_streamer.cpp @@ -47,6 +47,7 @@ rfnoc_tx_streamer::rfnoc_tx_streamer(const size_t num_chans, _tick_rate_out.reserve(num_chans); _type_out.reserve(num_chans); _mtu_out.reserve(num_chans); + _atomic_item_size_out.reserve(num_chans); for (size_t i = 0; i < num_chans; i++) { _register_props(i, stream_args.otw_format); @@ -171,13 +172,16 @@ void rfnoc_tx_streamer::_register_props(const size_t chan, const std::string& ot PROP_KEY_TYPE, otw_format, {res_source_info::OUTPUT_EDGE, chan})); _mtu_out.push_back(property_t<size_t>( PROP_KEY_MTU, get_mtu(), {res_source_info::OUTPUT_EDGE, chan})); + _atomic_item_size_out.push_back( + property_t<size_t>(PROP_KEY_ATOMIC_ITEM_SIZE, 1, {res_source_info::OUTPUT_EDGE, chan})); // Give us some shorthands for the rest of this function - property_t<double>* scaling_out = &_scaling_out.back(); - property_t<double>* samp_rate_out = &_samp_rate_out.back(); - property_t<double>* tick_rate_out = &_tick_rate_out.back(); - property_t<std::string>* type_out = &_type_out.back(); - property_t<size_t>* mtu_out = &_mtu_out.back(); + property_t<double>* scaling_out = &_scaling_out.back(); + property_t<double>* samp_rate_out = &_samp_rate_out.back(); + property_t<double>* tick_rate_out = &_tick_rate_out.back(); + property_t<std::string>* type_out = &_type_out.back(); + property_t<size_t>* mtu_out = &_mtu_out.back(); + property_t<size_t>* atomic_item_size_out = &_atomic_item_size_out.back(); // Register them register_property(scaling_out); @@ -185,6 +189,7 @@ void rfnoc_tx_streamer::_register_props(const size_t chan, const std::string& ot register_property(tick_rate_out); register_property(type_out); register_property(mtu_out); + register_property(atomic_item_size_out); // Add resolvers add_property_resolver( @@ -212,6 +217,23 @@ void rfnoc_tx_streamer::_register_props(const size_t chan, const std::string& ot this->set_tick_rate(tick_rate_out.get()); } }); + add_property_resolver( + {atomic_item_size_out, mtu_out}, {}, [&ais = *atomic_item_size_out, chan, this]() { + const auto UHD_UNUSED(log_chan) = chan; + RFNOC_LOG_TRACE("Calling resolver for `atomic_item_size'@" << chan); + if (ais.is_valid()) { + const auto spp = this->tx_streamer_impl::get_max_num_samps(); + if (spp < ais.get()) { + throw uhd::value_error("samples per package must not be smaller than atomic item size"); + } + const auto misalignment = spp % ais.get(); + RFNOC_LOG_TRACE("Check atomic item size " << ais.get() << " divides spp " << spp); + if (misalignment > 0) { + RFNOC_LOG_TRACE("Reduce spp by " << misalignment << " to align with atomic item size"); + this->tx_streamer_impl::set_max_num_samps(spp - misalignment); + } + } + }); } void rfnoc_tx_streamer::_handle_tx_event_action( |