aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc
diff options
context:
space:
mode:
authorJonathon Pendlum <jonathon.pendlum@ettus.com>2022-02-12 21:20:21 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2022-03-23 16:21:24 -0500
commit5d20a5a40155e888484f7d57a277bdcebed44207 (patch)
tree3171010abd7a74ed2abda35938904bf87e87b2fe /host/lib/rfnoc
parente57d22d525d93a72f9bc99fa1359aad0c51c921e (diff)
downloaduhd-5d20a5a40155e888484f7d57a277bdcebed44207.tar.gz
uhd-5d20a5a40155e888484f7d57a277bdcebed44207.tar.bz2
uhd-5d20a5a40155e888484f7d57a277bdcebed44207.zip
rfnoc: fir filter: Add support for multiple channels to block controller
Diffstat (limited to 'host/lib/rfnoc')
-rw-r--r--host/lib/rfnoc/fir_filter_block_control.cpp171
1 files changed, 117 insertions, 54 deletions
diff --git a/host/lib/rfnoc/fir_filter_block_control.cpp b/host/lib/rfnoc/fir_filter_block_control.cpp
index 1de15e237..e5f713dec 100644
--- a/host/lib/rfnoc/fir_filter_block_control.cpp
+++ b/host/lib/rfnoc/fir_filter_block_control.cpp
@@ -6,97 +6,160 @@
#include <uhd/exception.hpp>
#include <uhd/rfnoc/defaults.hpp>
-#include <uhd/rfnoc/fir_filter_block_control.hpp>
+#include <uhd/rfnoc/multichan_register_iface.hpp>
#include <uhd/rfnoc/property.hpp>
#include <uhd/rfnoc/registry.hpp>
+#include <uhd/rfnoc/fir_filter_block_control.hpp>
using namespace uhd::rfnoc;
-const uint32_t fir_filter_block_control::REG_FIR_MAX_NUM_COEFFS_ADDR = 0;
-const uint32_t fir_filter_block_control::REG_FIR_LOAD_COEFF_ADDR = 4;
-const uint32_t fir_filter_block_control::REG_FIR_LOAD_COEFF_LAST_ADDR = 8;
+const uint32_t fir_filter_block_control::REG_FIR_BLOCK_SIZE = 1 << 4;
+const uint32_t fir_filter_block_control::REG_FIR_MAX_NUM_COEFFS_ADDR = 0x00;
+const uint32_t fir_filter_block_control::REG_FIR_LOAD_COEFF_ADDR = 0x04;
+const uint32_t fir_filter_block_control::REG_FIR_LOAD_COEFF_LAST_ADDR = 0x08;
+
+// User property names
+const char* const PROP_KEY_MAX_NUM_COEFFS = "max_num_coeffs";
class fir_filter_block_control_impl : public fir_filter_block_control
{
public:
- RFNOC_BLOCK_CONSTRUCTOR(fir_filter_block_control)
- , _max_num_coeffs(this->regs().peek32(REG_FIR_MAX_NUM_COEFFS_ADDR)),
- _coeffs(_max_num_coeffs, int16_t(0))
+ RFNOC_BLOCK_CONSTRUCTOR(fir_filter_block_control),
+ _fir_filter_reg_iface(*this, 0, REG_FIR_BLOCK_SIZE)
{
- // register edge properties
- register_property(&_prop_type_in);
- register_property(&_prop_type_out);
-
- // add resolvers for type (keeps it constant)
- add_property_resolver({&_prop_type_in}, {&_prop_type_in}, [this]() {
- _prop_type_in.set(IO_TYPE_SC16);
- });
- add_property_resolver({&_prop_type_out}, {&_prop_type_out}, [this]() {
- _prop_type_out.set(IO_TYPE_SC16);
- });
-
- // initialize hardware with an impulse response
- _coeffs[0] = std::numeric_limits<int16_t>::max();
- _program_coefficients();
+ UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports());
+ _register_props();
}
- size_t get_max_num_coefficients() const override
+ size_t get_max_num_coefficients(const size_t chan = 0) const override
{
- return _max_num_coeffs;
+ if (chan >= get_num_input_ports()) {
+ std::string error_msg =
+ "Cannot get max number of coefficients for FIR Filter channel "
+ + std::to_string(chan) + ", channel value must be less than "
+ "or equal to " + std::to_string(get_num_input_ports()-1);
+ throw uhd::value_error(error_msg);
+ }
+ return _max_num_coeffs.at(chan);
}
- void set_coefficients(const std::vector<int16_t>& coeffs) override
+ void set_coefficients(const std::vector<int16_t>& coeffs, const size_t chan = 0) override
{
- if (coeffs.size() > _max_num_coeffs) {
+ if (chan >= get_num_input_ports()) {
std::string error_msg =
- "Too many filter coefficients specified (max " +
- std::to_string(_max_num_coeffs) + ")";
+ "Cannot set coefficients for FIR Filter channel "
+ + std::to_string(chan) + ", channel value must be less than "
+ "or equal to " + std::to_string(get_num_input_ports()-1);
+ throw uhd::value_error(error_msg);
+ }
+ if (coeffs.size() > _max_num_coeffs.at(chan)) {
+ std::string error_msg = "Too many filter coefficients specified (max "
+ + std::to_string(_max_num_coeffs.at(chan)) + ")";
throw uhd::value_error(error_msg);
}
- // save the new coefficients...
- _coeffs = coeffs;
- // ...and expand it to the number supported by the hardware,
- // padding with zeroes
- _coeffs.resize(_max_num_coeffs, 0);
- _program_coefficients();
+ _coeffs[chan] = coeffs;
+ // Expand coefficients to the number supported by the hardware,
+ // by padding with zeroes
+ _coeffs[chan].resize(_max_num_coeffs.at(chan), 0);
+ _program_coefficients(chan);
}
- std::vector<int16_t> get_coefficients() const override
+ std::vector<int16_t> get_coefficients(const size_t chan = 0) const override
{
- return _coeffs;
+ if (chan >= get_num_input_ports()) {
+ std::string error_msg =
+ "Cannot get coefficients for FIR Filter channel "
+ + std::to_string(chan) + ", channel value must be less than "
+ "or equal to " + std::to_string(get_num_input_ports()-1);
+ throw uhd::value_error(error_msg);
+ }
+ return _coeffs.at(chan);
}
private:
- void _program_coefficients()
+ void _register_props()
{
- // Write coefficients [0..num_coeffs-2]..
- std::vector<uint32_t> coeffs_addr(_max_num_coeffs - 1, REG_FIR_LOAD_COEFF_ADDR);
- std::vector<uint32_t> coeffs_minus_last(_max_num_coeffs - 1);
- std::transform(_coeffs.begin(),
- _coeffs.end() - 1,
+ const size_t num_chans = get_num_input_ports();
+ _max_num_coeffs.reserve(num_chans);
+ _coeffs.reserve(num_chans);
+ _prop_max_num_coeffs.reserve(num_chans);
+ _prop_type_in.reserve(num_chans);
+ _prop_type_out.reserve(num_chans);
+
+ for (size_t chan = 0; chan < num_chans; chan++) {
+ const uint32_t max_num_coeffs =
+ _fir_filter_reg_iface.peek32(REG_FIR_MAX_NUM_COEFFS_ADDR, chan);
+ _max_num_coeffs.emplace_back(max_num_coeffs);
+
+ // set impulse as default filter for each channel
+ std::vector<int16_t> impulse_coeffs(max_num_coeffs, 0);
+ impulse_coeffs.front() = std::numeric_limits<int16_t>::max();
+ _coeffs.emplace_back(impulse_coeffs);
+ _program_coefficients(chan);
+
+ // register user properties
+ _prop_max_num_coeffs.emplace_back(property_t<int>{PROP_KEY_MAX_NUM_COEFFS,
+ static_cast<int>(max_num_coeffs),
+ {res_source_info::USER, chan}});
+ register_property(&_prop_max_num_coeffs.back());
+ add_property_resolver({&ALWAYS_DIRTY},
+ {&_prop_max_num_coeffs.back()},
+ [this, chan, max_num_coeffs]() { _prop_max_num_coeffs.at(chan).set(max_num_coeffs); });
+
+ // 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); });
+ }
+ }
+
+ void _program_coefficients(const size_t chan = 0)
+ {
+ // Write coefficients [0..num_coeffs-2]...
+ const size_t num_coeffs = _coeffs.at(chan).size();
+ std::vector<uint32_t> coeffs_addr(num_coeffs - 1, REG_FIR_LOAD_COEFF_ADDR);
+ std::vector<uint32_t> coeffs_minus_last(num_coeffs - 1);
+ std::transform(_coeffs.at(chan).begin(),
+ _coeffs.at(chan).end() - 1,
coeffs_minus_last.begin(),
[](int16_t value) -> uint32_t { return static_cast<uint32_t>(value); });
- this->regs().multi_poke32(coeffs_addr, coeffs_minus_last);
- // ...and the final coefficients (num_coeffs-1)
- this->regs().poke32(
- REG_FIR_LOAD_COEFF_LAST_ADDR, _coeffs.at(_max_num_coeffs - 1));
+ _fir_filter_reg_iface.multi_poke32(coeffs_addr, coeffs_minus_last, chan);
+ // ...and the final coefficient (num_coeffs-1)
+ _fir_filter_reg_iface.poke32(REG_FIR_LOAD_COEFF_LAST_ADDR,
+ static_cast<uint32_t>(_coeffs.at(chan).at(num_coeffs - 1)),
+ chan);
}
- //! Number of coefficients supported by the FIR filter
- const size_t _max_num_coeffs;
+ //! Maximum number of coefficients supported by the FIR filter
+ std::vector<size_t> _max_num_coeffs;
- //! Current FIR filter coefficients
- std::vector<int16_t> _coeffs;
+ //! Current fir filter coefficients
+ std::vector<std::vector<int16_t>> _coeffs;
/**************************************************************************
* Attributes
*************************************************************************/
- property_t<std::string> _prop_type_in = property_t<std::string>{
- PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE}};
- property_t<std::string> _prop_type_out = property_t<std::string>{
- PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::OUTPUT_EDGE}};
+ std::vector<property_t<std::string>> _prop_type_in;
+ std::vector<property_t<std::string>> _prop_type_out;
+ std::vector<property_t<int>> _prop_max_num_coeffs;
+
+ /**************************************************************************
+ * Register interface
+ *************************************************************************/
+ multichan_register_iface _fir_filter_reg_iface;
};
UHD_RFNOC_BLOCK_REGISTER_DIRECT(