diff options
author | Martin Braun <martin.braun@ettus.com> | 2018-06-22 14:50:19 +0100 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-06-22 09:13:11 -0700 |
commit | 1ae324575c203dc5fdb7ac4833562fd8c9860235 (patch) | |
tree | c3487e234b7f13e3954ce503277537dbba0e2ed2 /host/lib/rfnoc | |
parent | b5be620d1922e924eb5da5bf26955b570eab2584 (diff) | |
download | uhd-1ae324575c203dc5fdb7ac4833562fd8c9860235.tar.gz uhd-1ae324575c203dc5fdb7ac4833562fd8c9860235.tar.bz2 uhd-1ae324575c203dc5fdb7ac4833562fd8c9860235.zip |
RFNoC: Add FIR, Null, and Window block controllers
Diffstat (limited to 'host/lib/rfnoc')
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 4 | ||||
-rw-r--r-- | host/lib/rfnoc/fir_block_ctrl_impl.cpp | 77 | ||||
-rw-r--r-- | host/lib/rfnoc/null_block_ctrl_impl.cpp | 107 | ||||
-rw-r--r-- | host/lib/rfnoc/window_block_ctrl_impl.cpp | 94 |
4 files changed, 282 insertions, 0 deletions
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index 9ee4970a3..527c99e14 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -34,7 +34,11 @@ LIBUHD_APPEND_SOURCES( # Default block control classes: ${CMAKE_CURRENT_SOURCE_DIR}/ddc_block_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/duc_block_ctrl_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/fir_block_ctrl_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/null_block_ctrl_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/window_block_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/siggen_block_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dma_fifo_block_ctrl_impl.cpp ) diff --git a/host/lib/rfnoc/fir_block_ctrl_impl.cpp b/host/lib/rfnoc/fir_block_ctrl_impl.cpp new file mode 100644 index 000000000..4267e0b22 --- /dev/null +++ b/host/lib/rfnoc/fir_block_ctrl_impl.cpp @@ -0,0 +1,77 @@ +// +// Copyright 2014-2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/rfnoc/fir_block_ctrl.hpp> +#include <uhd/convert.hpp> +#include <uhd/utils/log.hpp> + +using namespace uhd::rfnoc; + +class fir_block_ctrl_impl : public fir_block_ctrl +{ +public: + static const uint32_t RB_NUM_TAPS = 0; + static const uint32_t SR_RELOAD = 128; + static const uint32_t SR_RELOAD_TLAST = 129; + static const uint32_t SR_CONFIG = 130; + + UHD_RFNOC_BLOCK_CONSTRUCTOR(fir_block_ctrl), + _item_type("sc16") // We only support sc16 in this block + { + _n_taps = uint32_t(user_reg_read64(RB_NUM_TAPS)); + UHD_LOGGER_DEBUG(unique_id()) + << "fir_block::fir_block() n_taps ==" << _n_taps << std::endl; + UHD_ASSERT_THROW(_n_taps); + + // Default to Dirac impulse + std::vector<int> default_taps(1, 20000); + set_taps(default_taps); + } + + void set_taps(const std::vector<int> &taps_) + { + UHD_LOGGER_TRACE(unique_id()) << "fir_block::set_taps()" << std::endl; + if (taps_.size() > _n_taps) { + throw uhd::value_error(str( + boost::format("FIR block: Too many filter coefficients! Provided %d, FIR allows %d.\n") + % taps_.size() % _n_taps + )); + } + for (size_t i = 0; i < taps_.size(); i++) { + if (taps_[i] > 32767 || taps_[i] < -32768) { + throw uhd::value_error(str( + boost::format("FIR block: Coefficient %d out of range! Value %d, Allowed range [-32768,32767].\n") + % i % taps_[i])); + } + } + std::vector<int> taps = taps_; + if (taps.size() < _n_taps) { + taps.resize(_n_taps, 0); + } + + // Write taps via the reload bus + for (size_t i = 0; i < taps.size() - 1; i++) { + sr_write(SR_RELOAD, uint32_t(taps[i])); + } + // Assert tlast when sending the spinal tap (haha, it's actually the final tap). + sr_write(SR_RELOAD_TLAST, uint32_t(taps.back())); + // Send the configuration word to replace the existing coefficients with the new ones. + // Note: This configuration bus does not require tlast + sr_write(SR_CONFIG, 0); + } + + //! Returns the number of filter taps in this block. + size_t get_n_taps() const + { + return _n_taps; + } + +private: + const std::string _item_type; + size_t _n_taps; +}; + +UHD_RFNOC_BLOCK_REGISTER(fir_block_ctrl, "FIR"); diff --git a/host/lib/rfnoc/null_block_ctrl_impl.cpp b/host/lib/rfnoc/null_block_ctrl_impl.cpp new file mode 100644 index 000000000..7e62a2b3e --- /dev/null +++ b/host/lib/rfnoc/null_block_ctrl_impl.cpp @@ -0,0 +1,107 @@ +// +// Copyright 2014-2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/utils/log.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/rfnoc/null_block_ctrl.hpp> +#include <boost/format.hpp> + +using namespace uhd::rfnoc; + +class null_block_ctrl_impl : public null_block_ctrl +{ +public: + UHD_RFNOC_BLOCK_CONSTRUCTOR(null_block_ctrl) + { + // Register hooks for line_rate: + _tree->access<int>(_root_path / "args" / 0 / "line_rate" / "value") + .add_coerced_subscriber([this](const int delay){ + this->set_line_delay_cycles(delay); + }) + .update() + ; + // Register hooks for bpp: + _tree->access<int>(_root_path / "args" / 0 / "bpp" / "value") + .add_coerced_subscriber([this](const int bpp){ + this->set_bytes_per_packet(bpp); + }) + .update() + ; + } + + void set_line_delay_cycles(int cycles) + { + sr_write(SR_LINE_RATE, uint32_t(cycles)); + } + + void set_bytes_per_packet(int bpp) + { + sr_write(SR_LINES_PER_PACKET, uint32_t(bpp / BYTES_PER_LINE)); + } + + double set_line_rate(double rate, double clock_rate) + { + int cycs_between_lines = clock_rate / rate - 1; + if (cycs_between_lines > 0xFFFF) { + cycs_between_lines = 0xFFFF; + UHD_LOGGER_WARNING(unique_id()) + << str(boost::format("Requested rate %f is larger than possible " + "with the current clock rate (%.2f MHz).") + % rate % (clock_rate / 1e6)) + << std::endl; + } + cycs_between_lines = std::max(0, cycs_between_lines); + set_arg<int>("line_rate", cycs_between_lines); + return _line_rate_from_reg_val(cycs_between_lines, clock_rate); + } + + double get_line_rate(double clock_rate) const + { + return _line_rate_from_reg_val(get_arg<int>("line_rate"), clock_rate); + } + + double _line_rate_from_reg_val(uint32_t reg_val, double clock_rate) const + { + return clock_rate / (reg_val + 1); + } + + void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t) + { + if (not stream_cmd.stream_now) { + throw uhd::not_implemented_error("null_block does not support timed commands."); + } + switch (stream_cmd.stream_mode) { + case uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS: + sr_write(SR_ENABLE_STREAM, true); + break; + + case uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: + sr_write(SR_ENABLE_STREAM, false); + break; + + case uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE: + case uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE: + throw uhd::not_implemented_error("null_block does not support streaming modes other than CONTINUOUS"); + + default: + UHD_THROW_INVALID_CODE_PATH(); + } + } + + void set_destination( + uint32_t next_address, + size_t output_block_port + ) { + uhd::sid_t sid(next_address); + if (sid.get_src() == 0) { + sid.set_src(get_address()); + } + sr_write(SR_NEXT_DST_SID, sid.get(), output_block_port); + } +}; + +UHD_RFNOC_BLOCK_REGISTER(null_block_ctrl, "NullSrcSink"); + diff --git a/host/lib/rfnoc/window_block_ctrl_impl.cpp b/host/lib/rfnoc/window_block_ctrl_impl.cpp new file mode 100644 index 000000000..74ebd146d --- /dev/null +++ b/host/lib/rfnoc/window_block_ctrl_impl.cpp @@ -0,0 +1,94 @@ +// +// Copyright 2014-2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/rfnoc/window_block_ctrl.hpp> +#include <uhd/convert.hpp> +#include <uhd/utils/log.hpp> + +using namespace uhd::rfnoc; + +class window_block_ctrl_impl : public window_block_ctrl +{ +public: + UHD_RFNOC_BLOCK_CONSTRUCTOR(window_block_ctrl), + _item_type("sc16"), // We only support sc16 in this block + _bpi(uhd::convert::get_bytes_per_item("sc16")) + { + _max_len = uint32_t(user_reg_read64(RB_MAX_WINDOW_LEN)); + UHD_LOGGER_DEBUG(unique_id()) + << "window_block::window_block() max_len ==" << _max_len << std::endl; + UHD_ASSERT_THROW(_max_len); + + // TODO we need a coercer to check that spp on the prop tree doesn't get set to anything invalid + _set_default_window(std::min<size_t>(get_arg<int>("spp"), _max_len)); + } + + //! Set window coefficients and length + void set_window(const std::vector<int> &coeffs) + { + UHD_LOGGER_TRACE(unique_id()) + << "window_block::set_window()" << std::endl; + if (coeffs.size() > _max_len) { + throw uhd::value_error(str( + boost::format("window_block::set_window(): Too many window " + "coefficients! Provided %d, window allows up to %d.\n") + % coeffs.size() % _max_len + )); + } + + size_t window_len = coeffs.size(); + + // Window block can take complex coefficients in sc16 format, but typical usage is + // to have real(coeffs) == imag(coeffs) + std::vector<uint32_t> coeffs_; + for (size_t i = 0; i < window_len - 1; i++) { + if (coeffs[i] > 32767 || coeffs[i] < -32768) { + throw uhd::value_error(str( + boost::format("window_block::set_window(): Coefficient %d " + "(index %d) outside coefficient range [-32768,32767].\n") + % coeffs[i] % i)); + } + coeffs_.push_back(coeffs[i]); + } + + // Write coefficients via the load bus + for (size_t i = 0; i < window_len - 1; i++) { + sr_write(AXIS_WINDOW_LOAD, coeffs_[i]); + } + // Assert tlast when sending the final coefficient (sorry, no joke here) + sr_write(AXIS_WINDOW_LOAD_TLAST, coeffs_.back()); + // Set the window length + sr_write(SR_WINDOW_LEN, window_len); + + // This block requires spp to match the window length: + set_arg<int>("spp", int(window_len)); + } + + //! Returns the maximum window length of this block. + size_t get_max_len() const + { + return _max_len; + } + + size_t get_window_len() const + { + return size_t(get_arg<int>("spp")); + } + + +private: + const std::string _item_type; + const size_t _bpi; + size_t _max_len; + + //! Default is a rectangular window + void _set_default_window(size_t window_len) { + std::vector<int> default_coeffs(window_len, (1 << 15)-1); + set_window(default_coeffs); + } +}; + +UHD_RFNOC_BLOCK_REGISTER(window_block_ctrl, "Window"); |