diff options
author | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-05-08 08:59:54 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-06-29 13:41:15 -0500 |
commit | 619f9d637224627d5359e7d63e88a70660164a86 (patch) | |
tree | f62b37bd1ec471dced82113a2937dde7d19b5c54 /host | |
parent | 38caced6946243f0390c541df54160c45e4959cc (diff) | |
download | uhd-619f9d637224627d5359e7d63e88a70660164a86.tar.gz uhd-619f9d637224627d5359e7d63e88a70660164a86.tar.bz2 uhd-619f9d637224627d5359e7d63e88a70660164a86.zip |
rfnoc: Add window RFNoC block controller
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/defaults.hpp | 1 | ||||
-rw-r--r-- | host/include/uhd/rfnoc/window_block_control.hpp | 74 | ||||
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/rfnoc/window_block_control.cpp | 143 |
5 files changed, 220 insertions, 0 deletions
diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt index 9c389af03..cc91a6125 100644 --- a/host/include/uhd/rfnoc/CMakeLists.txt +++ b/host/include/uhd/rfnoc/CMakeLists.txt @@ -42,6 +42,7 @@ UHD_INSTALL(FILES radio_control.hpp split_stream_block_control.hpp vector_iir_block_control.hpp + window_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 e8f1c11e7..2104e8416 100644 --- a/host/include/uhd/rfnoc/defaults.hpp +++ b/host/include/uhd/rfnoc/defaults.hpp @@ -81,5 +81,6 @@ static const noc_id_t FOSPHOR_BLOCK = 0x666F0000; static const noc_id_t SPLIT_STREAM_BLOCK = 0x57570000; static const noc_id_t RADIO_BLOCK = 0x12AD1000; static const noc_id_t VECTOR_IIR_BLOCK = 0x11120000; +static const noc_id_t WINDOW_BLOCK = 0xD0530000; }} // namespace uhd::rfnoc diff --git a/host/include/uhd/rfnoc/window_block_control.hpp b/host/include/uhd/rfnoc/window_block_control.hpp new file mode 100644 index 000000000..316a1a288 --- /dev/null +++ b/host/include/uhd/rfnoc/window_block_control.hpp @@ -0,0 +1,74 @@ +// +// 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> +#include <uhd/types/ranges.hpp> + +namespace uhd { namespace rfnoc { + +/*! Window Block Control Class + * + * The Window Block is a windowing block for RFNoC that is intended to be + * used with the FFT block. The block can be configured with coefficients, + * by which the samples in each input packet are multiplied before begin + * output. The first sample of the first packet is multiplied by the first + * first coefficient, the second sample is multiplied by the second + * coefficient, and so on. + * + * The RFNoC window block supports a configurable number of pairs of input + * and output ports of sc16 data (16-bit fixed-point complex samples) and + * a configurable window length and coefficients for each. + */ +class UHD_API window_block_control : public noc_block_base +{ +public: + RFNOC_DECLARE_BLOCK(window_block_control) + + // Block registers + static const uint32_t REG_WINDOW_BLOCK_SIZE; + + static const uint32_t REG_WINDOW_LEN_OFFSET; + static const uint32_t REG_WINDOW_MAX_LEN_OFFSET; + static const uint32_t REG_WINDOW_LOAD_COEFF_OFFSET; + static const uint32_t REG_WINDOW_LOAD_COEFF_LAST_OFFSET; + + /*! Get the maximum number of window coefficients supported by this block + * + * Get the maximum number of window coefficients supported by this + * block. + * + * \param chan The channel to retrieve the maximum number of coefficients from + * \returns The maximum number of window coefficients supported by this block + */ + virtual size_t get_max_num_coefficients(const size_t chan) const = 0; + + /*! Set the window coefficients + * + * Set the window coefficients for a given channel. The number of + * coefficients must be equal to or less than the maximum number of + * coefficients supported by the given channel of the block. + * + * \param coeffs A vector of integer coefficients for the window + * \param chan The channel to apply the coefficients to + */ + virtual void set_coefficients( + const std::vector<int16_t>& coeffs, const size_t chan) = 0; + + /*! Get the window coefficients + * + * Return a vector with the current window coefficients for a given channel. + * + * \param chan The channel to retrieve the current window coefficients from + * \returns The vector of current window coefficients + */ + virtual std::vector<int16_t> get_coefficients(const size_t chan) const = 0; +}; + +}} // namespace uhd::rfnoc + diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index 8f74e9e6f..1a45ab1ff 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -52,5 +52,6 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/split_stream_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vector_iir_block_control.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/window_block_control.cpp ) diff --git a/host/lib/rfnoc/window_block_control.cpp b/host/lib/rfnoc/window_block_control.cpp new file mode 100644 index 000000000..1bd6a1295 --- /dev/null +++ b/host/lib/rfnoc/window_block_control.cpp @@ -0,0 +1,143 @@ +// +// 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/multichan_register_iface.hpp> +#include <uhd/rfnoc/property.hpp> +#include <uhd/rfnoc/registry.hpp> +#include <uhd/rfnoc/window_block_control.hpp> + +using namespace uhd::rfnoc; + +const uint32_t window_block_control::REG_WINDOW_BLOCK_SIZE = 1 << 4; +const uint32_t window_block_control::REG_WINDOW_LEN_OFFSET = 0x00; +const uint32_t window_block_control::REG_WINDOW_MAX_LEN_OFFSET = 0x04; +const uint32_t window_block_control::REG_WINDOW_LOAD_COEFF_OFFSET = 0x08; +const uint32_t window_block_control::REG_WINDOW_LOAD_COEFF_LAST_OFFSET = 0x0C; + +// User property names +const char* const PROP_KEY_MAX_LEN = "max_len"; + +class window_block_control_impl : public window_block_control +{ +public: + RFNOC_BLOCK_CONSTRUCTOR(window_block_control), + _window_reg_iface(*this, 0, REG_WINDOW_BLOCK_SIZE) + { + UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports()); + _register_props(); + } + + size_t get_max_num_coefficients(const size_t chan) const + { + return _max_len.at(chan); + } + + void set_coefficients(const std::vector<int16_t>& coeffs, const size_t chan) + { + if (coeffs.size() > _max_len.at(chan)) { + std::string error_msg = "Too many window coefficients specified (max " + + std::to_string(_max_len.at(chan)) + ")"; + throw uhd::value_error(error_msg); + } + + _coeffs[chan] = coeffs; + _program_coefficients(chan); + } + + std::vector<int16_t> get_coefficients(const size_t chan) const + { + return _coeffs.at(chan); + } + +private: + void _register_props() + { + const size_t num_chans = get_num_input_ports(); + _max_len.reserve(num_chans); + _coeffs.reserve(num_chans); + _prop_max_len.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_len = + _window_reg_iface.peek32(REG_WINDOW_MAX_LEN_OFFSET, chan); + _max_len.emplace_back(max_len); + + // set a default rectangular window for each channel + std::vector<int16_t> rect_coeffs( + max_len, std::numeric_limits<int16_t>::max()); + _coeffs.emplace_back(rect_coeffs); + _program_coefficients(chan); + + // register user properties + _prop_max_len.emplace_back(property_t<int>{PROP_KEY_MAX_LEN, + static_cast<int>(max_len), + {res_source_info::USER, chan}}); + register_property(&_prop_max_len.back()); + add_property_resolver({&ALWAYS_DIRTY}, + {&_prop_max_len.back()}, + [this, chan, max_len]() { _prop_max_len.at(chan).set(max_len); }); + + // 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(size_t chan) + { + // 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_WINDOW_LOAD_COEFF_OFFSET); + 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(), + [this](int16_t value) -> uint32_t { return static_cast<uint32_t>(value); }); + + _window_reg_iface.multi_poke32(coeffs_addr, coeffs_minus_last, chan); + // ...and the final coefficient (num_coeffs-1) + _window_reg_iface.poke32(REG_WINDOW_LOAD_COEFF_LAST_OFFSET, + static_cast<uint32_t>(_coeffs.at(chan).at(num_coeffs - 1)), + chan); + } + + //! Maximum length of window + std::vector<size_t> _max_len; + + //! Current window coefficients + std::vector<std::vector<int16_t>> _coeffs; + + /************************************************************************** + * Attributes + *************************************************************************/ + 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_len; + + /************************************************************************** + * Register interface + *************************************************************************/ + multichan_register_iface _window_reg_iface; +}; + +UHD_RFNOC_BLOCK_REGISTER_DIRECT( + window_block_control, WINDOW_BLOCK, "Window", CLOCK_KEY_GRAPH, "bus_clk") |