aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/CMakeLists.txt1
-rw-r--r--host/include/uhd/rfnoc/defaults.hpp1
-rw-r--r--host/include/uhd/rfnoc/vector_iir_block_control.hpp109
-rw-r--r--host/lib/rfnoc/CMakeLists.txt1
-rw-r--r--host/lib/rfnoc/vector_iir_block_control.cpp173
5 files changed, 285 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt
index 098c79562..24409fbf9 100644
--- a/host/include/uhd/rfnoc/CMakeLists.txt
+++ b/host/include/uhd/rfnoc/CMakeLists.txt
@@ -39,6 +39,7 @@ UHD_INSTALL(FILES
fosphor_block_control.hpp
null_block_control.hpp
radio_control.hpp
+ vector_iir_block_control.hpp
DESTINATION ${INCLUDE_DIR}/uhd/rfnoc
COMPONENT headers
diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp
index 38ae57242..053834335 100644
--- a/host/include/uhd/rfnoc/defaults.hpp
+++ b/host/include/uhd/rfnoc/defaults.hpp
@@ -77,5 +77,6 @@ static const noc_id_t DUC_BLOCK = 0xD0C00000;
static const noc_id_t DDC_BLOCK = 0xDDC00000;
static const noc_id_t FIR_FILTER_BLOCK = 0xf1120000;
static const noc_id_t FOSPHOR_BLOCK = 0x666F0000;
+static const noc_id_t VECTOR_IIR_BLOCK = 0x11120000;
}} // namespace uhd::rfnoc
diff --git a/host/include/uhd/rfnoc/vector_iir_block_control.hpp b/host/include/uhd/rfnoc/vector_iir_block_control.hpp
new file mode 100644
index 000000000..d23340a82
--- /dev/null
+++ b/host/include/uhd/rfnoc/vector_iir_block_control.hpp
@@ -0,0 +1,109 @@
+//
+// Copyright 2020 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <uhd/config.hpp>
+#include <uhd/rfnoc/noc_block_base.hpp>
+
+namespace uhd { namespace rfnoc {
+
+/*! Vector IIR Block Control Class
+ *
+ * The Vector IIR Block is an RFNoC block that implements an infinite
+ * impulse filter with a variable length delay line. The transfer
+ * function is defined as follows:
+ *
+ * beta
+ * H(z) = ------------------------
+ * 1 - alpha * z ^ -delay
+ *
+ * where
+ * - beta is the feedforward tap
+ * - alpha is the feedback tap
+ * - delay (a.k.a. vector length) is the feedback tap delay
+ */
+class UHD_API vector_iir_block_control : public noc_block_base
+{
+public:
+ RFNOC_DECLARE_BLOCK(vector_iir_block_control)
+
+ static const uint32_t REG_BLOCK_SIZE;
+
+ static const uint32_t REG_DELAY_OFFSET;
+ static const uint32_t REG_ALPHA_OFFSET;
+ static const uint32_t REG_BETA_OFFSET;
+
+ /*! Set the feedback tap value
+ *
+ * Sets the feedback tap value for channel \p chan of the IIR filter.
+ *
+ * \param alpha The feedback tap value for the filter
+ * \param chan The channel to apply the feedback tap value to
+ */
+ virtual void set_alpha(const double alpha, const size_t chan) = 0;
+
+ /*! Return the feedback tap value
+ *
+ * Returns the feedback tap value for channel \p chan of the IIR filter.
+ *
+ * \param chan The channel to retrieve the feedback tap value from
+ * \returns The feedback tap value for the filter
+ */
+ virtual double get_alpha(const size_t chan) const = 0;
+
+ /*! Set the feedforward tap value
+ *
+ * Sets the feedforward tap value for channel \p chan of the IIR filter.
+ *
+ * \param beta The feedforward tap value for the filter
+ * \param chan The channel to apply the feedforward tap value to
+ */
+ virtual void set_beta(const double beta, const size_t chan) = 0;
+
+ /*! Return the feedforward tap value
+ *
+ * Returns the feedforward tap value for channel \p chan of the IIR filter.
+ *
+ * \param chan The channel to retrieve the feedforward tap value from
+ * \returns The feedforward tap value for the filter
+ */
+ virtual double get_beta(const size_t chan) const = 0;
+
+ /*! Set the feedback tap delay
+ *
+ * Sets the feedback tap delay in samples for channel \p chan of the IIR
+ * filter. The delay value for the filter must be less than or equal to
+ * the maximum delay length supported by the filter.
+ *
+ * \param delay The feedback tap delay of the filter in samples
+ * \param chan The channel to apply the feedback tap delay to
+ */
+ virtual void set_delay(const uint16_t delay, const size_t chan) = 0;
+
+ /*! Return the feedback tap delay
+ *
+ * Returns the feedback tap delay value in samples for channel \p chan
+ * of the IIR filter.
+ *
+ * \param chan The channel to retrieve the feedback tap delay value from
+ * \returns The feedback tap delay of the filter in samples
+ */
+ virtual uint16_t get_delay(const size_t chan) const = 0;
+
+ /*! Return the maximum filter delay
+ *
+ * Returns the maximum allowable filter delay value, in samples, for
+ * channel \p chan.
+ *
+ * \param chan The channel to retrieve the maximum delay from
+ * \returns The maximum filter delay
+ */
+ virtual uint16_t get_max_delay(const size_t chan) const = 0;
+};
+
+}} // namespace uhd::rfnoc
+
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index 6881a57e8..c095e86f9 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -49,5 +49,6 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/fosphor_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/null_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/vector_iir_block_control.cpp
)
diff --git a/host/lib/rfnoc/vector_iir_block_control.cpp b/host/lib/rfnoc/vector_iir_block_control.cpp
new file mode 100644
index 000000000..404e85aa8
--- /dev/null
+++ b/host/lib/rfnoc/vector_iir_block_control.cpp
@@ -0,0 +1,173 @@
+//
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <uhd/convert.hpp>
+#include <uhd/exception.hpp>
+#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/vector_iir_block_control.hpp>
+#include <string>
+
+using namespace uhd::rfnoc;
+
+const uint32_t vector_iir_block_control::REG_BLOCK_SIZE = 1 << 4;
+const uint32_t vector_iir_block_control::REG_DELAY_OFFSET = 0;
+const uint32_t vector_iir_block_control::REG_ALPHA_OFFSET = 4;
+const uint32_t vector_iir_block_control::REG_BETA_OFFSET = 8;
+
+constexpr uint32_t DELAY_REG_MAX_DELAY_SHIFT = 16;
+constexpr uint32_t DELAY_REG_DELAY_MASK = 0x0000ffff;
+
+// User property names
+const char* const PROP_KEY_ALPHA = "alpha";
+const char* const PROP_KEY_BETA = "beta";
+const char* const PROP_KEY_DELAY = "delay";
+const char* const PROP_KEY_MAX_DELAY = "max_delay";
+
+class vector_iir_block_control_impl : public vector_iir_block_control
+{
+public:
+ RFNOC_BLOCK_CONSTRUCTOR(vector_iir_block_control),
+ _vector_iir_reg_iface(*this, 0, REG_BLOCK_SIZE)
+ {
+ UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports());
+ _register_props();
+ }
+
+ void set_alpha(const double alpha, const size_t chan)
+ {
+ set_property<double>(PROP_KEY_ALPHA, alpha, chan);
+ }
+
+ double get_alpha(const size_t chan) const
+ {
+ return _prop_alpha.at(chan).get();
+ }
+
+ void set_beta(const double beta, const size_t chan)
+ {
+ set_property<double>(PROP_KEY_BETA, beta, chan);
+ }
+
+ double get_beta(const size_t chan) const
+ {
+ return _prop_beta.at(chan).get();
+ }
+
+ void set_delay(const uint16_t delay, const size_t chan)
+ {
+ set_property<int>(PROP_KEY_DELAY, delay, chan);
+ }
+
+ uint16_t get_delay(const size_t chan) const
+ {
+ return _prop_delay.at(chan).get();
+ }
+
+ uint16_t get_max_delay(const size_t chan) const
+ {
+ return _prop_max_delay.at(chan).get();
+ }
+
+ /**************************************************************************
+ * Initialization
+ *************************************************************************/
+private:
+ void _register_props()
+ {
+ const size_t num_inputs = get_num_input_ports();
+ _prop_type_in.reserve(num_inputs);
+ _prop_type_out.reserve(num_inputs);
+ _prop_alpha.reserve(num_inputs);
+ _prop_beta.reserve(num_inputs);
+ _prop_delay.reserve(num_inputs);
+ _prop_max_delay.reserve(num_inputs);
+
+ for (size_t chan = 0; chan < num_inputs; chan++) {
+ const uint16_t max_delay =
+ static_cast<uint16_t>(_vector_iir_reg_iface.peek32(REG_DELAY_OFFSET, chan)
+ >> DELAY_REG_MAX_DELAY_SHIFT);
+
+ // register user properties
+ _prop_alpha.emplace_back(
+ property_t<double>{PROP_KEY_ALPHA, 0.9, {res_source_info::USER, chan}});
+ _prop_beta.emplace_back(
+ property_t<double>{PROP_KEY_BETA, 0.9, {res_source_info::USER, chan}});
+ _prop_delay.emplace_back(
+ property_t<int>{PROP_KEY_DELAY, max_delay, {res_source_info::USER, chan}});
+ _prop_max_delay.emplace_back(
+ property_t<int>{PROP_KEY_MAX_DELAY, max_delay, {res_source_info::USER, chan}});
+
+ register_property(&_prop_alpha.back(), [this, chan]() {
+ double alpha = _prop_alpha.at(chan).get();
+ if (alpha < 0.0 || alpha > 1.0) {
+ throw uhd::value_error("Alpha value must be in [0.0, 1.0]");
+ }
+ _vector_iir_reg_iface.poke32(
+ REG_ALPHA_OFFSET, uint32_t(alpha * pow(2, 31)), chan);
+ });
+ register_property(&_prop_beta.back(), [this, chan]() {
+ double beta = _prop_beta.at(chan).get();
+ if (beta < 0.0 || beta > 1.0) {
+ throw uhd::value_error("Beta value must be in [0.0, 1.0]");
+ }
+ _vector_iir_reg_iface.poke32(
+ REG_BETA_OFFSET, uint32_t(beta * pow(2, 31)), chan);
+ });
+ register_property(&_prop_delay.back(), [this, chan, max_delay]() {
+ int length = _prop_delay.at(chan).get();
+ if (length < 5 || length > static_cast<int>(max_delay)) {
+ throw uhd::value_error(
+ "Delay value must be in [5, " + std::to_string(max_delay) + "]");
+ }
+ _vector_iir_reg_iface.poke32(
+ REG_DELAY_OFFSET, uint32_t(length) & DELAY_REG_DELAY_MASK, chan);
+ });
+
+ register_property(&_prop_max_delay.back());
+ add_property_resolver({&ALWAYS_DIRTY},
+ {&_prop_max_delay.back()},
+ [this, chan, max_delay]() { _prop_max_delay.at(chan).set(max_delay); });
+
+ // register edge properties
+ _prop_type_in.emplace_back(property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE, chan}});
+ _prop_type_out.emplace_back(property_t<std::string>{
+ PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::OUTPUT_EDGE, chan}});
+ register_property(&_prop_type_in.back());
+ register_property(&_prop_type_out.back());
+
+ // add resolvers for type
+ add_property_resolver({&_prop_type_in.back()},
+ {&_prop_type_in.back()},
+ [this, chan]() { _prop_type_in.at(chan).set(IO_TYPE_SC16); });
+ add_property_resolver({&_prop_type_out.back()},
+ {&_prop_type_out.back()},
+ [this, chan]() { _prop_type_out.at(chan).set(IO_TYPE_SC16); });
+ }
+ }
+
+ /**************************************************************************
+ * Attributes
+ *************************************************************************/
+ std::vector<property_t<std::string>> _prop_type_in;
+ std::vector<property_t<std::string>> _prop_type_out;
+ std::vector<property_t<double>> _prop_alpha;
+ std::vector<property_t<double>> _prop_beta;
+ std::vector<property_t<int>> _prop_delay;
+ std::vector<property_t<int>> _prop_max_delay;
+
+
+ /**************************************************************************
+ * Register interface
+ *************************************************************************/
+ multichan_register_iface _vector_iir_reg_iface;
+};
+
+UHD_RFNOC_BLOCK_REGISTER_DIRECT(
+ vector_iir_block_control, VECTOR_IIR_BLOCK, "VectorIIR", CLOCK_KEY_GRAPH, "bus_clk")