diff options
| -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")  | 
