diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/defaults.hpp | 7 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/fir_filter_block_control.hpp | 69 | ||||
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/rfnoc/fir_filter_block_control.cpp | 101 |
5 files changed, 176 insertions, 3 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt index bb3cc0190..6435ec2a6 100644 --- a/host/include/uhd/rfnoc/CMakeLists.txt +++ b/host/include/uhd/rfnoc/CMakeLists.txt @@ -35,6 +35,7 @@ UHD_INSTALL(FILES duc_block_control.hpp dmafifo_block_control.hpp fft_block_control.hpp + fir_filter_block_control.hpp null_block_control.hpp radio_control.hpp diff --git a/host/include/uhd/rfnoc/defaults.hpp b/host/include/uhd/rfnoc/defaults.hpp index 0b95ddc2e..b786bfdef 100644 --- a/host/include/uhd/rfnoc/defaults.hpp +++ b/host/include/uhd/rfnoc/defaults.hpp @@ -72,9 +72,10 @@ static const device_type_t N320 = 0x1320; static const device_type_t X300 = 0xA300; // block identifiers -static const noc_id_t RADIO_BLOCK = 0x12AD1000; -static const noc_id_t DUC_BLOCK = 0xD0C00000; -static const noc_id_t DDC_BLOCK = 0xDDC00000; +static const noc_id_t RADIO_BLOCK = 0x12AD1000; +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; }} // namespace uhd::rfnoc diff --git a/host/include/uhd/rfnoc/fir_filter_block_control.hpp b/host/include/uhd/rfnoc/fir_filter_block_control.hpp new file mode 100644 index 000000000..5652f68ee --- /dev/null +++ b/host/include/uhd/rfnoc/fir_filter_block_control.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_FIR_FILTER_BLOCK_CONTROL_HPP +#define INCLUDED_LIBUHD_FIR_FILTER_BLOCK_CONTROL_HPP + +#include <uhd/config.hpp> +#include <uhd/rfnoc/noc_block_base.hpp> +#include <uhd/types/ranges.hpp> + +namespace uhd { namespace rfnoc { + +/*! FIR Filter Block Control Class + * + * The FIR Filter Block is a finite impulse response filter block for RFNoC. + * + * The RFNoC FIR block supports one input and output port of sc16 data + * (16-bit fixed-point complex samples) and a configurable (but fixed) + * number of taps. + */ +class UHD_API fir_filter_block_control : public noc_block_base +{ +public: + RFNOC_DECLARE_BLOCK(fir_filter_block_control) + + // Block registers + static const uint32_t REG_FIR_MAX_NUM_COEFFS_ADDR; + static const uint32_t REG_FIR_LOAD_COEFF_ADDR; + static const uint32_t REG_FIR_LOAD_COEFF_LAST_ADDR; + + /*! Get the maximum number of filter coefficients supported by this block + * + * Get the maximum number of filter coefficients supported by this + * block. + * + * \returns The maximum number of filter coefficients supported by this block + */ + virtual size_t get_max_num_coefficients() const = 0; + + /*! Set the filter coefficients + * + * Set the filter coefficients for this FIR block. The number of + * coefficients must be equal to or less than the maximum number of + * coefficients supported by the block. If the vector of coefficients + * passed to this function is smaller than the maximum number of + * coefficients supported by the block, it will automatically be padded + * with zeroes. If the vector of coefficients passed to this function is + * larger than the maximum number of coefficients supported by the block, + * a `uhd::value_error` is thrown. + * + * \param coeffs A vector of integer coefficients for the FIR filter + */ + virtual void set_coefficients(const std::vector<int16_t>& coeffs) = 0; + + /*! Get the filter coefficients + * + * Return a vector with the current filter coefficients. + * + * \returns The vector of current filter coefficients + */ + virtual std::vector<int16_t> get_coefficients() const = 0; +}; + +}} // namespace uhd::rfnoc + +#endif /* INCLUDED_LIBUHD_FIR_FILTER_BLOCK_CONTROL_HPP */ diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index ea774b2c8..4edfe4009 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -45,6 +45,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/duc_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dmafifo_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/fft_block_control.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fir_filter_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/null_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp ) diff --git a/host/lib/rfnoc/fir_filter_block_control.cpp b/host/lib/rfnoc/fir_filter_block_control.cpp new file mode 100644 index 000000000..38a0e4b9c --- /dev/null +++ b/host/lib/rfnoc/fir_filter_block_control.cpp @@ -0,0 +1,101 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/exception.hpp> +#include <uhd/rfnoc/defaults.hpp> +#include <uhd/rfnoc/fir_filter_block_control.hpp> +#include <uhd/rfnoc/property.hpp> +#include <uhd/rfnoc/registry.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; + +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)) + { + // 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(); + } + + size_t get_max_num_coefficients() const + { + return _max_num_coeffs; + } + + void set_coefficients(const std::vector<int16_t>& coeffs) + { + if (coeffs.size() > _max_num_coeffs) { + std::string error_msg = + "Too many filter coefficients specified (max " + + std::to_string(_max_num_coeffs) + ")"; + 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(); + } + + std::vector<int16_t> get_coefficients() const + { + return _coeffs; + } + +private: + void _program_coefficients() + { + // 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, coeffs_minus_last.begin(), + [this](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)); + } + + //! Number of coefficients supported by the FIR filter + const size_t _max_num_coeffs; + + //! Current FIR filter coefficients + 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}}; +}; + +UHD_RFNOC_BLOCK_REGISTER_DIRECT( + fir_filter_block_control, FIR_FILTER_BLOCK, "FIR", CLOCK_KEY_GRAPH, "bus_clk") |