aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorLars Amsel <lars.amsel@ni.com>2021-12-03 13:02:09 +0100
committerAaron Rossetto <aaron.rossetto@ni.com>2022-01-10 14:56:35 -0600
commit3e5e4eb06c0ea6337464cbda0648a75bf76cca17 (patch)
treea39eb76a91b19ba5f38aacafd844e869bc459319 /host/lib
parent0e7553cd1a8758a8488afc2efaff7295b351e7fe (diff)
downloaduhd-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')
-rw-r--r--host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp9
-rw-r--r--host/lib/include/uhdlib/rfnoc/rfnoc_rx_streamer.hpp1
-rw-r--r--host/lib/include/uhdlib/rfnoc/rfnoc_tx_streamer.hpp1
-rw-r--r--host/lib/include/uhdlib/transport/rx_streamer_impl.hpp6
-rw-r--r--host/lib/include/uhdlib/transport/tx_streamer_impl.hpp6
-rw-r--r--host/lib/rfnoc/radio_control_impl.cpp37
-rw-r--r--host/lib/rfnoc/rfnoc_rx_streamer.cpp33
-rw-r--r--host/lib/rfnoc/rfnoc_tx_streamer.cpp32
8 files changed, 115 insertions, 10 deletions
diff --git a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
index de83c403c..ace5b7a45 100644
--- a/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
+++ b/host/lib/include/uhdlib/rfnoc/radio_control_impl.hpp
@@ -323,6 +323,13 @@ protected:
return _rate;
}
+ /*
+ * Returns the number of bytes to be processed in each clock cycle.
+ */
+ size_t get_atomic_item_size() const
+ {
+ return (_samp_width / 8) * _spc;
+ }
//! Properties for samp_rate (one per port)
std::vector<property_t<double>> _samp_rate_in;
//! Properties for samp_rate (one per port)
@@ -380,6 +387,8 @@ private:
const uint32_t _spc;
std::vector<property_t<int>> _spp_prop;
+ std::vector<property_t<size_t>> _atomic_item_size_in;
+ std::vector<property_t<size_t>> _atomic_item_size_out;
//! Properties for type_in (one per port)
std::vector<property_t<io_type_t>> _type_in;
//! Properties for type_out (one per port)
diff --git a/host/lib/include/uhdlib/rfnoc/rfnoc_rx_streamer.hpp b/host/lib/include/uhdlib/rfnoc/rfnoc_rx_streamer.hpp
index ca569e338..2ed11182a 100644
--- a/host/lib/include/uhdlib/rfnoc/rfnoc_rx_streamer.hpp
+++ b/host/lib/include/uhdlib/rfnoc/rfnoc_rx_streamer.hpp
@@ -110,6 +110,7 @@ private:
std::vector<property_t<double>> _tick_rate_in;
std::vector<property_t<std::string>> _type_in;
std::vector<property_t<size_t>> _mtu_in;
+ std::vector<property_t<size_t>> _atomic_item_size_in;
// Streamer unique ID
const std::string _unique_id;
diff --git a/host/lib/include/uhdlib/rfnoc/rfnoc_tx_streamer.hpp b/host/lib/include/uhdlib/rfnoc/rfnoc_tx_streamer.hpp
index a071d7248..76369474f 100644
--- a/host/lib/include/uhdlib/rfnoc/rfnoc_tx_streamer.hpp
+++ b/host/lib/include/uhdlib/rfnoc/rfnoc_tx_streamer.hpp
@@ -113,6 +113,7 @@ private:
std::vector<property_t<double>> _tick_rate_out;
std::vector<property_t<std::string>> _type_out;
std::vector<property_t<size_t>> _mtu_out;
+ std::vector<property_t<size_t>> _atomic_item_size_out;
// Streamer unique ID
const std::string _unique_id;
diff --git a/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp b/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
index 1b25b308b..03cd3824a 100644
--- a/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
+++ b/host/lib/include/uhdlib/transport/rx_streamer_impl.hpp
@@ -208,6 +208,12 @@ protected:
_converters[chan]->set_scalar(scale_factor);
}
+ //! set maximum number of sample (per packet)
+ void set_max_num_samps(const size_t value)
+ {
+ _spp = value;
+ }
+
//! Returns the maximum payload size
size_t get_mtu() const
{
diff --git a/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp b/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
index 6b34c1c10..38f16671a 100644
--- a/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
+++ b/host/lib/include/uhdlib/transport/tx_streamer_impl.hpp
@@ -329,6 +329,12 @@ protected:
return _zero_copy_streamer.get_tick_rate();
}
+ //! set maximum number of sample (per packet)
+ void set_max_num_samps(const size_t value)
+ {
+ _spp = value;
+ }
+
//! Returns the maximum payload size
size_t get_mtu() const
{
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(