aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2019-06-03 22:33:52 -0700
committerMartin Braun <martin.braun@ettus.com>2019-11-26 11:49:23 -0800
commitdebe5189364b0684500b7ce4cd8f45894a3e54e7 (patch)
tree6a1d3d263e904afbe58d4dad77744ecf26ea37c8 /host/lib/rfnoc
parent6460e07f91bc468e7c094785093426ee07e26bcb (diff)
downloaduhd-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.txt1
-rw-r--r--host/lib/rfnoc/null_block_control.cpp182
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")