diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-06-03 22:33:52 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:23 -0800 |
commit | debe5189364b0684500b7ce4cd8f45894a3e54e7 (patch) | |
tree | 6a1d3d263e904afbe58d4dad77744ecf26ea37c8 /host/lib/rfnoc | |
parent | 6460e07f91bc468e7c094785093426ee07e26bcb (diff) | |
download | uhd-debe5189364b0684500b7ce4cd8f45894a3e54e7.tar.gz uhd-debe5189364b0684500b7ce4cd8f45894a3e54e7.tar.bz2 uhd-debe5189364b0684500b7ce4cd8f45894a3e54e7.zip |
rfnoc: Add null block controller
Diffstat (limited to 'host/lib/rfnoc')
-rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/rfnoc/null_block_control.cpp | 182 |
2 files changed, 183 insertions, 0 deletions
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index d62489484..1b627d304 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -57,6 +57,7 @@ LIBUHD_APPEND_SOURCES( ${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}/null_block_control.cpp ${CMAKE_CURRENT_SOURCE_DIR}/window_block_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_control_impl.cpp diff --git a/host/lib/rfnoc/null_block_control.cpp b/host/lib/rfnoc/null_block_control.cpp new file mode 100644 index 000000000..be0738b76 --- /dev/null +++ b/host/lib/rfnoc/null_block_control.cpp @@ -0,0 +1,182 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/rfnoc/null_block_control.hpp> +#include <uhd/rfnoc/registry.hpp> +#include <uhd/rfnoc/defaults.hpp> +#include <atomic> + +namespace { + +} // namespace + +using namespace uhd::rfnoc; +using uhd::stream_cmd_t; + + +const uint32_t null_block_control::REG_CTRL_STATUS = 0x00; +const uint32_t null_block_control::REG_SRC_LINES_PER_PKT = 0x04; +const uint32_t null_block_control::REG_SRC_BYTES_PER_PKT = 0x08; +const uint32_t null_block_control::REG_SRC_THROTTLE_CYC = 0x0C; +const uint32_t null_block_control::REG_SNK_LINE_CNT_LO = 0x10; +const uint32_t null_block_control::REG_SNK_LINE_CNT_HI = 0x14; +const uint32_t null_block_control::REG_SNK_PKT_CNT_LO = 0x18; +const uint32_t null_block_control::REG_SNK_PKT_CNT_HI = 0x1C; +const uint32_t null_block_control::REG_SRC_LINE_CNT_LO = 0x20; +const uint32_t null_block_control::REG_SRC_LINE_CNT_HI = 0x24; +const uint32_t null_block_control::REG_SRC_PKT_CNT_LO = 0x28; +const uint32_t null_block_control::REG_SRC_PKT_CNT_HI = 0x2C; +const uint32_t null_block_control::REG_LOOP_LINE_CNT_LO = 0x30; +const uint32_t null_block_control::REG_LOOP_LINE_CNT_HI = 0x34; +const uint32_t null_block_control::REG_LOOP_PKT_CNT_LO = 0x38; +const uint32_t null_block_control::REG_LOOP_PKT_CNT_HI = 0x3C; + + +class null_block_control_impl : public null_block_control +{ +public: + RFNOC_BLOCK_CONSTRUCTOR(null_block_control) + { + uint32_t initial_state = regs().peek32(REG_CTRL_STATUS); + _streaming = initial_state & 0x2; + _nipc = (initial_state >> 24) & 0xFF; + _item_width = (initial_state >> 16) & 0xFF; + reset_counters(); + register_issue_stream_cmd(); + } + + void issue_stream_cmd(const stream_cmd_t& stream_cmd) + { + if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS) { + RFNOC_LOG_TRACE("Received start stream request!"); + regs().poke32(REG_CTRL_STATUS, 0x2); + _streaming = true; + } else if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { + RFNOC_LOG_TRACE("Received stop stream request!"); + regs().poke32(REG_CTRL_STATUS, 0x0); + _streaming = false; + } else { + throw uhd::runtime_error("Null source can only do continuous streaming!"); + } + } + + void reset_counters() + { + const uint32_t streaming_flag = _streaming ? 0x2 : 0x0; + regs().poke32(REG_CTRL_STATUS, streaming_flag | 0x1); + regs().poke32(REG_CTRL_STATUS, streaming_flag | 0x0); + } + + void set_lines_per_packet(const uint32_t lpp) + { + if (lpp < 2) { + throw uhd::value_error("Null source lines per packet must be at " + "least one line in the payload!"); + } + if (lpp > 0xFFF) { + throw uhd::value_error("Null source lines per packet cannot exceed 12 bits!"); + } + // The register value is decreased by one line for the header, and one + // line for encoding (if we write a 0 here, the payload will still be at + // least one line long). + regs().poke32(REG_SRC_LINES_PER_PKT, lpp - 2); + } + + void set_bytes_per_packet(const uint32_t bpp) + { + if (bpp > 0xFFFF) { + throw uhd::value_error("Null source lines per packet cannot exceed 16 bits!"); + } + regs().poke32(REG_SRC_BYTES_PER_PKT, bpp); + const uint32_t bytes_per_line = (_item_width * _nipc) / 8; + // If bpp is not an integer multiple of bytes_per_line, then we add a + // full additional line! + const uint32_t lpp = bpp / bytes_per_line + (bpp % bytes_per_line ? 1 : 0); + set_lines_per_packet(lpp); + } + + void set_throttle_cycles(const uint32_t cycs) + { + if (cycs > 0x3FF) { + throw uhd::value_error("Null source throttle cycles cannot exceed 10 bits!"); + } + regs().poke32(REG_SRC_THROTTLE_CYC, cycs); + } + + uint32_t get_lines_per_packet() + { + return regs().peek32(REG_SRC_LINES_PER_PKT) + 2; + } + + uint32_t get_bytes_per_packet() + { + return regs().peek32(REG_SRC_BYTES_PER_PKT); + } + + uint32_t get_throttle_cycles() + { + return regs().peek32(REG_SRC_THROTTLE_CYC); + } + + uint64_t get_count( + const port_type_t port_type, const count_type_t count_type) + { + const uint32_t count_addr_lo = [&](){ + switch (port_type) { + case SOURCE: + return count_type == LINES ? REG_SRC_LINE_CNT_LO : REG_SRC_PKT_CNT_LO; + case SINK: + return count_type == LINES ? REG_SNK_LINE_CNT_LO : REG_SNK_PKT_CNT_LO; + case LOOP: + return count_type == LINES ? REG_LOOP_LINE_CNT_LO : REG_LOOP_PKT_CNT_LO; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + }(); + return regs().peek64(count_addr_lo); + } + +private: + + /*! Action API: Register a handler for stream commands + */ + void register_issue_stream_cmd() + { + register_action_handler(ACTION_KEY_STREAM_CMD, + [this](const res_source_info& src, action_info::sptr action) { + stream_cmd_action_info::sptr stream_cmd_action = + std::dynamic_pointer_cast<stream_cmd_action_info>(action); + if (!stream_cmd_action) { + throw uhd::runtime_error( + "Received stream_cmd of invalid action type!"); + } + if (src.instance != 0 || src.type != res_source_info::OUTPUT_EDGE) { + throw uhd::runtime_error( + "The null source can only stream from output port 0!"); + } + RFNOC_LOG_DEBUG("Received stream command action request!"); + issue_stream_cmd(stream_cmd_action->stream_cmd); + }); + } + + /************************************************************************** + * FPGA communication (register IO) + *************************************************************************/ + + /************************************************************************** + * Attributes + *************************************************************************/ + //! True if the source port 0 is producing data + std::atomic_bool _streaming{false}; + + //! Number of items per clock + uint32_t _nipc; + + //! Bits per item + uint32_t _item_width; +}; + +UHD_RFNOC_BLOCK_REGISTER_DIRECT(null_block_control, 0x00000001, "NullSrcSink") |