aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/rfnoc')
-rw-r--r--host/lib/rfnoc/CMakeLists.txt30
-rw-r--r--host/lib/rfnoc/async_msg_handler.cpp174
-rw-r--r--host/lib/rfnoc/block_ctrl_base.cpp678
-rw-r--r--host/lib/rfnoc/block_ctrl_base_factory.cpp87
-rw-r--r--host/lib/rfnoc/block_ctrl_impl.cpp23
-rw-r--r--host/lib/rfnoc/blockdef_xml_impl.cpp438
-rw-r--r--host/lib/rfnoc/ctrl_iface.cpp240
-rw-r--r--host/lib/rfnoc/ddc_block_ctrl_impl.cpp347
-rw-r--r--host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp106
-rw-r--r--host/lib/rfnoc/duc_block_ctrl_impl.cpp313
-rw-r--r--host/lib/rfnoc/fir_block_ctrl_impl.cpp78
-rw-r--r--host/lib/rfnoc/graph_impl.cpp219
-rw-r--r--host/lib/rfnoc/legacy_compat.cpp1179
-rw-r--r--host/lib/rfnoc/nocscript/CMakeLists.txt27
-rw-r--r--host/lib/rfnoc/nocscript/block_iface.cpp236
-rw-r--r--host/lib/rfnoc/nocscript/block_iface.hpp87
-rw-r--r--host/lib/rfnoc/nocscript/expression.cpp380
-rw-r--r--host/lib/rfnoc/nocscript/expression.hpp360
-rw-r--r--host/lib/rfnoc/nocscript/function_table.cpp100
-rw-r--r--host/lib/rfnoc/nocscript/function_table.hpp75
-rwxr-xr-xhost/lib/rfnoc/nocscript/gen_basic_funcs.py465
-rw-r--r--host/lib/rfnoc/nocscript/parser.cpp357
-rw-r--r--host/lib/rfnoc/nocscript/parser.hpp37
-rw-r--r--host/lib/rfnoc/node_ctrl_base.cpp138
-rw-r--r--host/lib/rfnoc/null_block_ctrl_impl.cpp120
-rw-r--r--host/lib/rfnoc/radio_ctrl_impl.cpp533
-rw-r--r--host/lib/rfnoc/rate_node_ctrl.cpp51
-rw-r--r--host/lib/rfnoc/rx_stream_terminator.cpp134
-rw-r--r--host/lib/rfnoc/scalar_node_ctrl.cpp50
-rw-r--r--host/lib/rfnoc/siggen_block_ctrl_impl.cpp48
-rw-r--r--host/lib/rfnoc/sink_block_ctrl_base.cpp105
-rw-r--r--host/lib/rfnoc/sink_node_ctrl.cpp80
-rw-r--r--host/lib/rfnoc/source_block_ctrl_base.cpp148
-rw-r--r--host/lib/rfnoc/source_node_ctrl.cpp80
-rw-r--r--host/lib/rfnoc/stream_sig.cpp66
-rw-r--r--host/lib/rfnoc/tick_node_ctrl.cpp65
-rw-r--r--host/lib/rfnoc/tx_stream_terminator.cpp53
-rw-r--r--host/lib/rfnoc/wb_iface_adapter.cpp44
-rw-r--r--host/lib/rfnoc/window_block_ctrl_impl.cpp95
39 files changed, 0 insertions, 7846 deletions
diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt
index 2892e0d6d..5f5838a29 100644
--- a/host/lib/rfnoc/CMakeLists.txt
+++ b/host/lib/rfnoc/CMakeLists.txt
@@ -13,12 +13,7 @@
LIBUHD_APPEND_SOURCES(
# Infrastructure:
${CMAKE_CURRENT_SOURCE_DIR}/actions.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/async_msg_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/block_container.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/block_ctrl_base.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/block_ctrl_base_factory.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/block_ctrl_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/blockdef_xml_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/block_id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/chdr_types.cpp
${CMAKE_CURRENT_SOURCE_DIR}/chdr_packet.cpp
@@ -26,35 +21,20 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/chdr_rx_data_xport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/chdr_tx_data_xport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/client_zero.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/ctrl_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/device_id.cpp
${CMAKE_CURRENT_SOURCE_DIR}/epid_allocator.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/graph_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/graph.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/legacy_compat.cpp
${CMAKE_CURRENT_SOURCE_DIR}/link_stream_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/graph_stream_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mb_controller.cpp
${CMAKE_CURRENT_SOURCE_DIR}/noc_block_base.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/node_ctrl_base.cpp
${CMAKE_CURRENT_SOURCE_DIR}/node.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/rate_node_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/register_iface_holder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ctrlport_endpoint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/chdr_ctrl_endpoint.cpp
${CMAKE_CURRENT_SOURCE_DIR}/registry_factory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rfnoc_graph.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/rx_stream_terminator.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/scalar_node_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/sink_block_ctrl_base.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/sink_node_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/source_block_ctrl_base.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/source_node_ctrl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mgmt_portal.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/stream_sig.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/tick_node_ctrl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/tx_stream_terminator.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface_adapter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rfnoc_rx_streamer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rfnoc_tx_streamer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tx_async_msg_queue.cpp
@@ -62,17 +42,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ddc_block_control.cpp
${CMAKE_CURRENT_SOURCE_DIR}/duc_block_control.cpp
- ${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}/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
- ${CMAKE_CURRENT_SOURCE_DIR}/siggen_block_ctrl_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/dma_fifo_block_ctrl_impl.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/replay_block_ctrl_impl.cpp
)
-INCLUDE_SUBDIRECTORY(nocscript)
diff --git a/host/lib/rfnoc/async_msg_handler.cpp b/host/lib/rfnoc/async_msg_handler.cpp
deleted file mode 100644
index 6b7d7d057..000000000
--- a/host/lib/rfnoc/async_msg_handler.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-//
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/exception.hpp>
-#include <uhd/transport/bounded_buffer.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/transport/zero_copy.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/tasks.hpp>
-#include <uhdlib/rfnoc/async_msg_handler.hpp>
-#include <boost/make_shared.hpp>
-#include <mutex>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-template <endianness_t _endianness>
-class async_msg_handler_impl : public async_msg_handler
-{
-public:
- /************************************************************************
- * Types
- ***********************************************************************/
- typedef uhd::transport::bounded_buffer<async_msg_t> async_md_type;
-
- /************************************************************************
- * Structors
- ***********************************************************************/
- async_msg_handler_impl(uhd::transport::zero_copy_if::sptr recv,
- uhd::transport::zero_copy_if::sptr send,
- uhd::sid_t sid)
- : _rx_xport(recv), _tx_xport(send), _sid(sid)
- {
- // Launch receive thread
- _recv_msg_task = task::make([=]() { this->handle_async_msgs(); });
- }
-
- ~async_msg_handler_impl() {}
-
- /************************************************************************
- * API calls
- ***********************************************************************/
- int register_event_handler(
- const async_msg_t::event_code_t event_code, async_handler_type handler)
- {
- _event_handlers.insert(std::pair<async_msg_t::event_code_t, async_handler_type>(
- event_code, handler));
- return _event_handlers.count(event_code);
- }
-
- void post_async_msg(const async_msg_t& metadata)
- {
- std::lock_guard<std::mutex> lock(_mutex);
-
- for (auto const event_handler : _event_handlers) {
- // If the event code in the message matches the event code used at
- // registration time, call the event handler
- if ((metadata.event_code & event_handler.first) == event_handler.first) {
- event_handler.second(metadata);
- }
- }
-
- // Print
- if (metadata.event_code & async_msg_t::EVENT_CODE_UNDERFLOW) {
- UHD_LOG_FASTPATH("U")
- } else if (metadata.event_code
- & (async_msg_t::EVENT_CODE_SEQ_ERROR
- | async_msg_t::EVENT_CODE_SEQ_ERROR_IN_BURST)) {
- UHD_LOG_FASTPATH("S")
- } else if (metadata.event_code
- & (async_msg_t::EVENT_CODE_LATE_CMD_ERROR
- | async_msg_t::EVENT_CODE_LATE_DATA_ERROR)) {
- UHD_LOG_FASTPATH("L")
- } else if (metadata.event_code & async_msg_t::EVENT_CODE_OVERRUN) {
- UHD_LOG_FASTPATH("O")
- }
- }
-
-private: // methods
- /************************************************************************
- * Internals
- ***********************************************************************/
- /*! Packet receiver thread call.
- */
- void handle_async_msgs()
- {
- using namespace uhd::transport;
- managed_recv_buffer::sptr buff = _rx_xport->get_recv_buff();
- if (not buff)
- return;
-
- // Get packet info
- vrt::if_packet_info_t if_packet_info;
- if_packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t);
- const uint32_t* packet_buff = buff->cast<const uint32_t*>();
-
- // unpacking can fail
- uint32_t (*endian_conv)(uint32_t) = uhd::ntohx;
- try {
- if (_endianness == ENDIANNESS_BIG) {
- vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info);
- endian_conv = uhd::ntohx;
- } else {
- vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info);
- endian_conv = uhd::wtohx;
- }
- } catch (const uhd::value_error& ex) {
- UHD_LOGGER_ERROR("RFNOC")
- << "[async message handler] Error parsing async message packet: "
- << ex.what() << std::endl;
- return;
- }
-
- // We discard anything that's not actually a command or response packet.
- if (not(if_packet_info.packet_type & vrt::if_packet_info_t::PACKET_TYPE_CMD)
- or if_packet_info.num_packet_words32 == 0) {
- return;
- }
-
- const uint32_t* payload = packet_buff + if_packet_info.num_header_words32;
- async_msg_t metadata(if_packet_info.num_payload_words32 - 1);
- metadata.has_time_spec = if_packet_info.has_tsf;
- // FIXME: not hardcoding tick rate
- metadata.time_spec = time_spec_t::from_ticks(if_packet_info.tsf, 1);
- metadata.event_code = async_msg_t::event_code_t(endian_conv(payload[0]) & 0xFFFF);
- metadata.sid = if_packet_info.sid;
-
- // load user payload
- for (size_t i = 1; i < if_packet_info.num_payload_words32; i++) {
- metadata.payload[i - 1] = endian_conv(payload[i]);
- }
-
- this->post_async_msg(metadata);
- }
-
- uint32_t get_local_addr() const
- {
- return _sid.get_src();
- }
-
-private: // members
- std::mutex _mutex;
- //! Store event handlers
- std::multimap<async_msg_t::event_code_t, async_handler_type> _event_handlers;
- //! port that receive messge
- uhd::transport::zero_copy_if::sptr _rx_xport;
-
- //! port that send out respond
- uhd::transport::zero_copy_if::sptr _tx_xport;
-
- //! The source part of \p _sid is the address of this async message handler.
- uhd::sid_t _sid;
-
- //! Stores the task that polls the Rx queue
- task::sptr _recv_msg_task;
-};
-
-async_msg_handler::sptr async_msg_handler::make(uhd::transport::zero_copy_if::sptr recv,
- uhd::transport::zero_copy_if::sptr send,
- uhd::sid_t sid,
- endianness_t endianness)
-{
- if (endianness == ENDIANNESS_BIG) {
- return boost::make_shared<async_msg_handler_impl<ENDIANNESS_BIG>>(
- recv, send, sid);
- } else {
- return boost::make_shared<async_msg_handler_impl<ENDIANNESS_LITTLE>>(
- recv, send, sid);
- }
-}
diff --git a/host/lib/rfnoc/block_ctrl_base.cpp b/host/lib/rfnoc/block_ctrl_base.cpp
deleted file mode 100644
index d186910b9..000000000
--- a/host/lib/rfnoc/block_ctrl_base.cpp
+++ /dev/null
@@ -1,678 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-// This file contains the block control functions for block controller classes.
-// See block_ctrl_base_factory.cpp for discovery and factory functions.
-
-#include "nocscript/block_iface.hpp"
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/block_ctrl_base.hpp>
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhdlib/rfnoc/ctrl_iface.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-#include <uhdlib/utils/compat_check.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <chrono>
-#include <thread>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-using std::string;
-
-/***********************************************************************
- * Structors
- **********************************************************************/
-block_ctrl_base::block_ctrl_base(const make_args_t& make_args)
- : _tree(make_args.tree)
- , _ctrl_ifaces(make_args.ctrl_ifaces)
- , _base_address(make_args.base_address & 0xFFF0)
- , _noc_id(sr_read64(SR_READBACK_REG_ID))
- , _compat_num(sr_read64(SR_READBACK_COMPAT))
-{
- /*** Identify this block (NoC-ID, block-ID, and block definition) *******/
- // Read NoC-ID (name is passed in through make_args):
- _block_def = blockdef::make_from_noc_id(_noc_id);
- if (not _block_def) {
- UHD_LOG_DEBUG("RFNOC",
- "No block definition found, using default block configuration "
- "for block with NOC ID: "
- + str(boost::format("0x%08X") % _noc_id));
- _block_def = blockdef::make_from_noc_id(DEFAULT_NOC_ID_64);
- }
- UHD_ASSERT_THROW(_block_def);
- // For the block ID, we start with block count 0 and increase until
- // we get a block ID that's not already registered:
- _block_id.set(make_args.device_index, make_args.block_name, 0);
- while (_tree->exists("xbar/" + _block_id.get_local())) {
- _block_id++;
- }
- UHD_LOG_INFO(unique_id(),
- str(boost::format("Initializing block control (NOC ID: 0x%016X)") % _noc_id));
-
- /*** Check compat number ************************************************/
- assert_fpga_compat(NOC_SHELL_COMPAT_MAJOR,
- NOC_SHELL_COMPAT_MINOR,
- _compat_num,
- "noc_shell",
- unique_id(),
- false /* fail_on_minor_behind */
- );
-
- /*** Initialize property tree *******************************************/
- _root_path = "xbar/" + _block_id.get_local();
- _tree->create<uint64_t>(_root_path / "noc_id").set(_noc_id);
-
- /*** Reset block state *******************************************/
- // We don't know the state of the data-path of this block before
- // we initialize. If everything tore down properly, the data-path
- // should be disconnected and thus idle. Reconfiguration of parameters
- // like SIDs is safe to do in that scenario.
- // However, if data is still streaming, block configuration
- // can potentially lock up noc_shell. So we flush the data-path here.
-
- // Flush is a block-level operation that can be triggered
- // from any block port.
- // Do it once before clearing...
- if (get_ctrl_ports().size() > 0) {
- _flush(get_ctrl_ports().front());
- }
- // Clear flow control and misc state
- clear();
-
- /*** Configure ports ****************************************************/
- size_t n_valid_input_buffers = 0;
- for (const size_t ctrl_port : get_ctrl_ports()) {
- // Set command times to sensible defaults
- set_command_tick_rate(1.0, ctrl_port);
- set_command_time(time_spec_t(0.0), ctrl_port);
- // Set source addresses:
- sr_write(SR_BLOCK_SID, get_address(ctrl_port), ctrl_port);
- // Set sink buffer sizes:
- const uint64_t fifo_size_reg = sr_read64(SR_READBACK_REG_FIFOSIZE, ctrl_port);
- const size_t buf_size_bytes = size_t(fifo_size_reg & 0xFFFFFFFF);
- if (buf_size_bytes > 0) {
- n_valid_input_buffers++;
- }
- _tree->create<size_t>(_root_path / "input_buffer_size" / ctrl_port)
- .set(buf_size_bytes);
- // Set MTU size and convert to bytes:
- settingsbus_reg_t reg_mtu = SR_READBACK_REG_MTU;
- size_t mtu = 8 * (1 << size_t(sr_read64(reg_mtu, ctrl_port)));
- _tree->create<size_t>(_root_path / "mtu" / ctrl_port).set(mtu);
- // Set command FIFO size
- const uint32_t cmd_fifo_size = (fifo_size_reg >> 32) & 0xFFFFFFFF;
- _ctrl_ifaces[ctrl_port]->set_cmd_fifo_size(cmd_fifo_size);
- // Set default destination SIDs
- // Otherwise, the default is someone else's SID, which we don't want
- sr_write(SR_RESP_IN_DST_SID, 0xFFFF, ctrl_port);
- sr_write(SR_RESP_OUT_DST_SID, 0xFFFF, ctrl_port);
- }
-
- /*** Register names *****************************************************/
- blockdef::registers_t sregs = _block_def->get_settings_registers();
- for (const std::string& reg_name : sregs.keys()) {
- if (DEFAULT_NAMED_SR.has_key(reg_name)) {
- throw uhd::runtime_error(
- str(boost::format("Register name %s is already defined!") % reg_name));
- }
- _tree->create<size_t>(_root_path / "registers" / "sr" / reg_name)
- .set(sregs.get(reg_name));
- }
- blockdef::registers_t rbacks = _block_def->get_readback_registers();
- for (const std::string& reg_name : rbacks.keys()) {
- _tree->create<size_t>(_root_path / "registers" / "rb" / reg_name)
- .set(rbacks.get(reg_name));
- }
-
- /*** Init I/O port definitions ******************************************/
- _init_port_defs("in", _block_def->get_input_ports());
- _init_port_defs("out", _block_def->get_output_ports());
- _num_input_ports = _block_def->get_input_ports().size();
- _num_output_ports = _block_def->get_output_ports().size();
- // FIXME this warning always fails until the input buffer code above is fixed
- // if (_tree->list(_root_path / "ports/in").size() != n_valid_input_buffers) {
- // UHD_LOGGER_WARNING(unique_id()) <<
- // boost::format("[%s] defines %d input buffer sizes, but %d input ports")
- // % get_block_id().get()
- // % n_valid_input_buffers
- // % _tree->list(_root_path / "ports/in").size()
- // ;
- //}
-
- /*** Init default block args ********************************************/
- _nocscript_iface = nocscript::block_iface::make(this);
- _init_block_args();
-}
-
-block_ctrl_base::~block_ctrl_base()
-{
- UHD_SAFE_CALL(if (get_ctrl_ports().size() > 0) {
- // Notify the data-path gatekeeper in noc_shell that we are done
- // with this block. This operation disconnects the noc_block
- // data-path from noc_shell which dumps all input and output
- // packets that are in flight, for now and until the setting is
- // disabled. This prevents long-running blocks without a tear-down
- // mechanism to gracefully flush.
- _start_drain(get_ctrl_ports().front());
- } _tree->remove(_root_path);)
-}
-
-void block_ctrl_base::_init_port_defs(
- const std::string& direction, blockdef::ports_t ports, const size_t first_port_index)
-{
- size_t port_index = first_port_index;
- for (const blockdef::port_t& port_def : ports) {
- fs_path port_path = _root_path / "ports" / direction / port_index;
- if (not _tree->exists(port_path)) {
- _tree->create<blockdef::port_t>(port_path);
- }
- UHD_LOGGER_TRACE(unique_id())
- << "Adding port definition at " << port_path
- << boost::format(": type = '%s' pkt_size = '%s' vlen = '%s'")
- % port_def["type"] % port_def["pkt_size"] % port_def["vlen"];
- _tree->access<blockdef::port_t>(port_path).set(port_def);
- port_index++;
- }
-}
-
-void block_ctrl_base::_init_block_args()
-{
- blockdef::args_t args = _block_def->get_args();
- fs_path arg_path = _root_path / "args";
- for (const size_t port : get_ctrl_ports()) {
- _tree->create<std::string>(arg_path / port);
- }
-
- // First, create all nodes.
- for (const auto& arg : args) {
- fs_path arg_type_path = arg_path / arg["port"] / arg["name"] / "type";
- _tree->create<std::string>(arg_type_path).set(arg["type"]);
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else if (arg["type"] == "int") {
- _tree->create<int>(arg_val_path);
- } else if (arg["type"] == "double") {
- _tree->create<double>(arg_val_path);
- } else if (arg["type"] == "string") {
- _tree->create<string>(arg_val_path);
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- // Next: Create all the subscribers and coercers.
- // TODO: Add coercer
-#define _SUBSCRIBE_CHECK_AND_RUN(type, arg_tag, error_message) \
- _tree->access<type>(arg_val_path) \
- .add_coerced_subscriber(boost::bind((&nocscript::block_iface::run_and_check), \
- _nocscript_iface, \
- arg[#arg_tag], \
- error_message))
- for (const auto& arg : args) {
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (not arg["check"].empty()) {
- if (arg["type"] == "string") {
- _SUBSCRIBE_CHECK_AND_RUN(string, check, arg["check_message"]);
- } else if (arg["type"] == "int") {
- _SUBSCRIBE_CHECK_AND_RUN(int, check, arg["check_message"]);
- } else if (arg["type"] == "double") {
- _SUBSCRIBE_CHECK_AND_RUN(double, check, arg["check_message"]);
- } else if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- if (not arg["action"].empty()) {
- if (arg["type"] == "string") {
- _SUBSCRIBE_CHECK_AND_RUN(string, action, "");
- } else if (arg["type"] == "int") {
- _SUBSCRIBE_CHECK_AND_RUN(int, action, "");
- } else if (arg["type"] == "double") {
- _SUBSCRIBE_CHECK_AND_RUN(double, action, "");
- } else if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- }
-
- // Finally: Set the values. This will call subscribers, if we have any.
- for (const auto& arg : args) {
- fs_path arg_val_path = arg_path / arg["port"] / arg["name"] / "value";
- if (not arg["value"].empty()) {
- if (arg["type"] == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- } else if (arg["type"] == "int") {
- _tree->access<int>(arg_val_path).set(std::stoi(arg["value"]));
- } else if (arg["type"] == "double") {
- _tree->access<double>(arg_val_path).set(std::stod(arg["value"]));
- } else if (arg["type"] == "string") {
- _tree->access<string>(arg_val_path).set(arg["value"]);
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
- }
-}
-
-/***********************************************************************
- * FPGA control & communication
- **********************************************************************/
-timed_wb_iface::sptr block_ctrl_base::get_ctrl_iface(const size_t block_port)
-{
- return boost::make_shared<wb_iface_adapter>(_ctrl_ifaces[block_port],
- boost::bind(&block_ctrl_base::get_command_tick_rate, this, block_port),
- boost::bind(&block_ctrl_base::set_command_time, this, _1, block_port),
- boost::bind(&block_ctrl_base::get_command_time, this, block_port));
-}
-
-std::vector<size_t> block_ctrl_base::get_ctrl_ports() const
-{
- std::vector<size_t> ctrl_ports;
- ctrl_ports.reserve(_ctrl_ifaces.size());
- std::pair<size_t, ctrl_iface::sptr> it;
- for (auto it : _ctrl_ifaces) {
- ctrl_ports.push_back(it.first);
- }
- return ctrl_ports;
-}
-
-void block_ctrl_base::sr_write(const uint32_t reg, const uint32_t data, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_write(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- _ctrl_ifaces[port]->send_cmd_pkt(
- reg, data, false, _cmd_timespecs[port].to_ticks(_cmd_tickrates[port]));
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("[%s] sr_write() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-void block_ctrl_base::sr_write(
- const std::string& reg, const uint32_t data, const size_t port)
-{
- uint32_t reg_addr = 255;
- if (DEFAULT_NAMED_SR.has_key(reg)) {
- reg_addr = DEFAULT_NAMED_SR[reg];
- } else {
- if (not _tree->exists(_root_path / "registers" / "sr" / reg)) {
- throw uhd::key_error(
- str(boost::format("Unknown settings register name: %s") % reg));
- }
- reg_addr =
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "sr" / reg).get());
- }
- return sr_write(reg_addr, data, port);
-}
-
-uint64_t block_ctrl_base::sr_read64(const settingsbus_reg_t reg, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_read64(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- return _ctrl_ifaces[port]->send_cmd_pkt(
- SR_READBACK, reg, true, _cmd_timespecs[port].to_ticks(_cmd_tickrates[port]));
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("[%s] sr_read64() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint32_t block_ctrl_base::sr_read32(const settingsbus_reg_t reg, const size_t port)
-{
- if (not _ctrl_ifaces.count(port)) {
- throw uhd::key_error(str(boost::format("[%s] sr_read32(): No such port: %d")
- % get_block_id().get() % port));
- }
- try {
- return uint32_t(_ctrl_ifaces[port]->send_cmd_pkt(
- SR_READBACK, reg, true, _cmd_timespecs[port].to_ticks(_cmd_tickrates[port])));
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("[%s] sr_read32() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint64_t block_ctrl_base::user_reg_read64(const uint32_t addr, const size_t port)
-{
- try {
- // TODO: When timed readbacks are used, time the second, but not the first
- // Set readback register address
- sr_write(SR_READBACK_ADDR, addr, port);
- // Read readback register via RFNoC
- return sr_read64(SR_READBACK_REG_USER, port);
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("%s user_reg_read64() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint64_t block_ctrl_base::user_reg_read64(const std::string& reg, const size_t port)
-{
- if (not _tree->exists(_root_path / "registers" / "rb" / reg)) {
- throw uhd::key_error(
- str(boost::format("Invalid readback register name: %s") % reg));
- }
- return user_reg_read64(
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "rb" / reg).get()),
- port);
-}
-
-uint32_t block_ctrl_base::user_reg_read32(const uint32_t addr, const size_t port)
-{
- try {
- // Set readback register address
- sr_write(SR_READBACK_ADDR, addr, port);
- // Read readback register via RFNoC
- return sr_read32(SR_READBACK_REG_USER, port);
- } catch (const std::exception& ex) {
- throw uhd::io_error(str(boost::format("[%s] user_reg_read32() failed: %s")
- % get_block_id().get() % ex.what()));
- }
-}
-
-uint32_t block_ctrl_base::user_reg_read32(const std::string& reg, const size_t port)
-{
- if (not _tree->exists(_root_path / "registers" / "rb" / reg)) {
- throw uhd::key_error(
- str(boost::format("Invalid readback register name: %s") % reg));
- }
- return user_reg_read32(
- uint32_t(_tree->access<size_t>(_root_path / "registers" / "rb" / reg).get()),
- port);
-}
-
-void block_ctrl_base::set_command_time(const time_spec_t& time_spec, const size_t port)
-{
- if (port == ANY_PORT) {
- for (const size_t specific_port : get_ctrl_ports()) {
- set_command_time(time_spec, specific_port);
- }
- return;
- }
-
- _cmd_timespecs[port] = time_spec;
- _set_command_time(time_spec, port);
-}
-
-time_spec_t block_ctrl_base::get_command_time(const size_t port)
-{
- return _cmd_timespecs[port];
-}
-
-void block_ctrl_base::set_command_tick_rate(const double tick_rate, const size_t port)
-{
- if (port == ANY_PORT) {
- for (const size_t specific_port : get_ctrl_ports()) {
- set_command_tick_rate(tick_rate, specific_port);
- }
- return;
- }
-
- _cmd_tickrates[port] = tick_rate;
-}
-
-double block_ctrl_base::get_command_tick_rate(const size_t port)
-{
- return _cmd_tickrates[port];
-}
-
-void block_ctrl_base::clear_command_time(const size_t port)
-{
- _cmd_timespecs[port] = time_spec_t(0.0);
-}
-
-void block_ctrl_base::clear()
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::clear()");
- // Call parent...
- node_ctrl_base::clear();
- // ...then child
- for (const size_t port_index : get_ctrl_ports()) {
- _clear(port_index);
- }
-}
-
-uint32_t block_ctrl_base::get_address(size_t block_port)
-{
- UHD_ASSERT_THROW(block_port < 16);
- return (_base_address & 0xFFF0) | (block_port & 0xF);
-}
-
-/***********************************************************************
- * Argument handling
- **********************************************************************/
-void block_ctrl_base::set_args(const uhd::device_addr_t& args, const size_t port)
-{
- for (const std::string& key : args.keys()) {
- if (_tree->exists(get_arg_path(key, port))) {
- set_arg(key, args.get(key), port);
- }
- }
-}
-
-void block_ctrl_base::set_arg(
- const std::string& key, const std::string& val, const size_t port)
-{
- fs_path arg_path = get_arg_path(key, port);
- if (not _tree->exists(arg_path / "value")) {
- throw uhd::runtime_error(str(
- boost::format("Attempting to set uninitialized argument '%s' on block '%s'")
- % key % unique_id()));
- }
-
- std::string type = _tree->access<std::string>(arg_path / "type").get();
- fs_path arg_val_path = arg_path / "value";
- try {
- if (type == "string") {
- _tree->access<std::string>(arg_val_path).set(val);
- } else if (type == "int") {
- _tree->access<int>(arg_val_path).set(std::stoi(val));
- } else if (type == "double") {
- _tree->access<double>(arg_val_path).set(std::stod(val));
- } else if (type == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- }
- } catch (const boost::bad_lexical_cast&) {
- throw uhd::value_error(
- str(boost::format("Error trying to cast value %s == '%s' to type '%s'") % key
- % val % type));
- }
-}
-
-device_addr_t block_ctrl_base::get_args(const size_t port) const
-{
- device_addr_t args;
- for (const std::string& key : _tree->list(_root_path / "args" / port)) {
- args[key] = get_arg(key);
- }
- return args;
-}
-
-std::string block_ctrl_base::get_arg(const std::string& key, const size_t port) const
-{
- fs_path arg_path = get_arg_path(key, port);
- if (not _tree->exists(arg_path / "value")) {
- throw uhd::runtime_error(str(
- boost::format("Attempting to get uninitialized argument '%s' on block '%s'")
- % key % unique_id()));
- }
-
- std::string type = _tree->access<std::string>(arg_path / "type").get();
- fs_path arg_val_path = arg_path / "value";
- if (type == "string") {
- return _tree->access<std::string>(arg_val_path).get();
- } else if (type == "int") {
- return std::to_string(_tree->access<int>(arg_val_path).get());
- } else if (type == "double") {
- return std::to_string(_tree->access<double>(arg_val_path).get());
- } else if (type == "int_vector") {
- throw uhd::runtime_error("not yet implemented: int_vector");
- }
-
- UHD_THROW_INVALID_CODE_PATH();
-}
-
-std::string block_ctrl_base::get_arg_type(const std::string& key, const size_t port) const
-{
- fs_path arg_type_path = _root_path / "args" / port / key / "type";
- return _tree->access<std::string>(arg_type_path).get();
-}
-
-stream_sig_t block_ctrl_base::_resolve_port_def(const blockdef::port_t& port_def) const
-{
- if (not port_def.is_valid()) {
- throw uhd::runtime_error(
- str(boost::format("Invalid port definition: %s") % port_def.to_string()));
- }
-
- // TODO this entire section is pretty dumb at this point. Needs better
- // checks.
- stream_sig_t stream_sig;
- // Item Type
- if (port_def.is_variable("type")) {
- std::string var_name = port_def["type"].substr(1);
- // TODO check this is even a string
- stream_sig.item_type = get_arg(var_name);
- } else if (port_def.is_keyword("type")) {
- throw uhd::runtime_error("keywords resolution for type not yet implemented");
- } else {
- stream_sig.item_type = port_def["type"];
- }
-
- // Vector length
- if (port_def.is_variable("vlen")) {
- std::string var_name = port_def["vlen"].substr(1);
- stream_sig.vlen = boost::lexical_cast<size_t>(get_arg(var_name));
- } else if (port_def.is_keyword("vlen")) {
- throw uhd::runtime_error("keywords resolution for vlen not yet implemented");
- } else {
- stream_sig.vlen = boost::lexical_cast<size_t>(port_def["vlen"]);
- }
-
- // Packet size
- if (port_def.is_variable("pkt_size")) {
- std::string var_name = port_def["pkt_size"].substr(1);
- stream_sig.packet_size = boost::lexical_cast<size_t>(get_arg(var_name));
- } else if (port_def.is_keyword("pkt_size")) {
- if (port_def["pkt_size"] != "%vlen") {
- throw uhd::runtime_error(
- "generic keywords resolution for pkt_size not yet implemented");
- }
- if (stream_sig.vlen == 0) {
- stream_sig.packet_size = 0;
- } else {
- if (stream_sig.item_type.empty()) {
- throw uhd::runtime_error(
- "cannot resolve pkt_size if item type is not given");
- }
- size_t bpi = uhd::convert::get_bytes_per_item(stream_sig.item_type);
- stream_sig.packet_size = stream_sig.vlen * bpi;
- }
- } else {
- stream_sig.packet_size = boost::lexical_cast<size_t>(port_def["pkt_size"]);
- }
-
- return stream_sig;
-}
-
-void block_ctrl_base::_start_drain(const size_t port)
-{
- // Begin flushing data out of the block by writing to the flushing
- // registers, then disabling flow control. We do this because we don't know
- // what state the flow-control module was left in in the previous run
- sr_write(SR_CLEAR_TX_FC, 0x2, port);
- sr_write(SR_CLEAR_RX_FC, 0x2, port);
- sr_write(SR_FLOW_CTRL_EN, 0, port);
-}
-
-bool block_ctrl_base::_flush(const size_t port)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_flush (port=" << port << ")");
-
- auto is_data_streaming = [this](int time_ms) -> bool {
- // noc_shell has 2 16-bit counters (one for TX and one for RX) in the top
- // 32 bits of the SR_READBACK_REG_GLOBAL_PARAMS. For all the checks below
- // we want to make sure that the counts are not changing i.e. no data is
- // streaming. So we just look at the two counters together as a single
- // 32-bit quantity.
- auto old_cnts =
- static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
- std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
- auto new_cnts =
- static_cast<uint32_t>(this->sr_read64(SR_READBACK_REG_GLOBAL_PARAMS) >> 32);
- return (new_cnts != old_cnts);
- };
-
- // We always want to try flushing out data. This is done by starting to
- // drain the data out of the block, then checking if counts have changed.
- // If a change is detected, this is most likely because the last
- // session terminated abnormally or if logic in a noc_block is
- // misbehaving. This is a situation that we may not be able to
- // recover from because we are in a partially initialized state.
- // We will try to at least not lock up the FPGA.
-
- // Disconnect the RX and TX data paths and let them flush.
- // A timeout of 2s is chosen to be conservative. It needs to account for:
- // - Upstream blocks that weren't terminated to run out of FC credits
- // - This block which might be finishing up with its data output
- constexpr int FLUSH_TIMEOUT_MS = 2000; // This is approximate
- bool success = false;
- _start_drain(port);
- for (int i = 0; i < FLUSH_TIMEOUT_MS / 10; i++) {
- if (not is_data_streaming(10)) {
- success = true;
- break;
- }
- }
- // Stop flushing
- sr_write(SR_CLEAR_TX_FC, 0x0, port); // Enable TX data-path
- sr_write(SR_CLEAR_RX_FC, 0x0, port); // Enable RX data-path
-
- if (not success) {
- // Print a warning only if data was still flushing
- // after the timeout elapsed
- UHD_LOGGER_WARNING(unique_id())
- << "This block seems to be busy most likely due to the abnormal termination "
- "of a previous "
- "session. Attempted recovery but it may not have worked depending on the "
- "behavior of "
- "other blocks in the design. Please restart the application.";
- }
- return success;
-}
-
-
-/***********************************************************************
- * Hooks & Derivables
- **********************************************************************/
-void block_ctrl_base::_clear(const size_t port)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_clear()");
- sr_write(SR_CLEAR_TX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
- sr_write(SR_CLEAR_TX_FC, 0x0, port); // Write 0 to reset the clear flag
- sr_write(SR_CLEAR_RX_FC, 0x1, port); // Write 1 to trigger a single cycle clear event
- sr_write(SR_CLEAR_RX_FC, 0x0, port); // Write 0 to reset the clear flag
-}
-
-void block_ctrl_base::_set_command_time(
- const time_spec_t& /*time_spec*/, const size_t /*port*/)
-{
- UHD_LOG_TRACE(unique_id(), "block_ctrl_base::_set_command_time()");
-}
-// vim: sw=4 et:
diff --git a/host/lib/rfnoc/block_ctrl_base_factory.cpp b/host/lib/rfnoc/block_ctrl_base_factory.cpp
deleted file mode 100644
index 6f3e9d9f7..000000000
--- a/host/lib/rfnoc/block_ctrl_base_factory.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/block_ctrl_base.hpp>
-#include <uhd/rfnoc/blockdef.hpp>
-#include <uhd/utils/log.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-typedef uhd::dict<std::string, block_ctrl_base::make_t> block_fcn_reg_t;
-// Instantiate the block function registry container
-UHD_SINGLETON_FCN(block_fcn_reg_t, get_block_fcn_regs);
-
-void block_ctrl_base::register_block(const make_t& make, const std::string& key)
-{
- if (get_block_fcn_regs().has_key(key)) {
- throw uhd::runtime_error(str(
- boost::format(
- "Attempting to register an RFNoC block with key %s for the second time.")
- % key));
- }
-
- get_block_fcn_regs().set(key, make);
-}
-
-/*! Look up names for blocks in XML files using NoC ID.
- */
-static void lookup_block_key(uint64_t noc_id, make_args_t& make_args)
-{
- try {
- blockdef::sptr bd = blockdef::make_from_noc_id(noc_id);
- if (not bd) {
- make_args.block_key = DEFAULT_BLOCK_NAME;
- make_args.block_name = DEFAULT_BLOCK_NAME;
- return;
- }
- UHD_ASSERT_THROW(bd->is_block());
- make_args.block_key = bd->get_key();
- make_args.block_name = bd->get_name();
- return;
- } catch (std::exception& e) {
- UHD_LOGGER_WARNING("RFNOC")
- << str(boost::format("Error while looking up name for NoC-ID %016X.\n%s")
- % noc_id % e.what());
- }
-
- make_args.block_key = DEFAULT_BLOCK_NAME;
- make_args.block_name = DEFAULT_BLOCK_NAME;
-}
-
-
-block_ctrl_base::sptr block_ctrl_base::make(
- const make_args_t& make_args_, uint64_t noc_id)
-{
- UHD_LOGGER_TRACE("RFNOC") << "[RFNoC Factory] block_ctrl_base::make()";
- make_args_t make_args = make_args_;
-
- // Check if a block key was specified, in this case, we *must* either
- // create a specialized block controller class or throw
- if (make_args.block_key.empty()) {
- lookup_block_key(noc_id, make_args);
- } else if (not get_block_fcn_regs().has_key(make_args.block_key)) {
- throw uhd::runtime_error(
- str(boost::format("No block controller class registered for key '%s'.")
- % make_args.block_key));
- }
- if (not get_block_fcn_regs().has_key(make_args.block_key)) {
- UHD_LOG_WARNING("RFNOC",
- "Can't find a block controller for key "
- << make_args.block_key << ", using default block controller!");
- make_args.block_key = DEFAULT_BLOCK_NAME;
- }
- if (make_args.block_name.empty()) {
- make_args.block_name = make_args.block_key;
- }
-
- UHD_LOGGER_TRACE("RFNOC") << "[RFNoC Factory] Using controller key '"
- << make_args.block_key << "' and block name '"
- << make_args.block_name << "'";
- return get_block_fcn_regs()[make_args.block_key](make_args);
-}
diff --git a/host/lib/rfnoc/block_ctrl_impl.cpp b/host/lib/rfnoc/block_ctrl_impl.cpp
deleted file mode 100644
index 030cd77de..000000000
--- a/host/lib/rfnoc/block_ctrl_impl.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/block_ctrl.hpp>
-
-using namespace uhd::rfnoc;
-
-class block_ctrl_impl : public block_ctrl
-{
-public:
- UHD_RFNOC_BLOCK_CONSTRUCTOR(block_ctrl)
- {
- // nop
- }
-
- // Very empty class, this one
-};
-
-UHD_RFNOC_BLOCK_REGISTER(block_ctrl, DEFAULT_BLOCK_NAME);
diff --git a/host/lib/rfnoc/blockdef_xml_impl.cpp b/host/lib/rfnoc/blockdef_xml_impl.cpp
deleted file mode 100644
index 2326043ca..000000000
--- a/host/lib/rfnoc/blockdef_xml_impl.cpp
+++ /dev/null
@@ -1,438 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/exception.hpp>
-#include <uhd/rfnoc/blockdef.hpp>
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhd/utils/paths.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/filesystem/operations.hpp>
-#include <boost/format.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/xml_parser.hpp>
-#include <cstdlib>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-namespace fs = boost::filesystem;
-namespace pt = boost::property_tree;
-
-static const fs::path XML_BLOCKS_SUBDIR("blocks");
-static const fs::path XML_COMPONENTS_SUBDIR("components");
-static const fs::path XML_EXTENSION(".xml");
-
-
-/****************************************************************************
- * port_t stuff
- ****************************************************************************/
-const device_addr_t blockdef::port_t::PORT_ARGS("name,"
- "type,"
- "vlen=0,"
- "pkt_size=0,"
- "optional=0,"
- "bursty=0,"
- "port,");
-
-blockdef::port_t::port_t()
-{
- // This guarantees that we can access these keys
- // even if they were never initialized:
- for (const std::string& key : PORT_ARGS.keys()) {
- set(key, PORT_ARGS[key]);
- }
-}
-
-bool blockdef::port_t::is_variable(const std::string& key) const
-{
- const std::string& val = get(key);
- return (val[0] == '$');
-}
-
-bool blockdef::port_t::is_keyword(const std::string& key) const
-{
- const std::string& val = get(key);
- return (val[0] == '%');
-}
-
-bool blockdef::port_t::is_valid() const
-{
- // Check we have all the keys:
- for (const std::string& key : PORT_ARGS.keys()) {
- if (not has_key(key)) {
- return false;
- }
- }
-
- // Twelve of the clock, all seems well
- return true;
-}
-
-std::string blockdef::port_t::to_string() const
-{
- std::string result;
- for (const std::string& key : PORT_ARGS.keys()) {
- if (has_key(key)) {
- result += str(boost::format("%s=%s,") % key % get(key));
- }
- }
-
- return result;
-}
-
-/****************************************************************************
- * arg_t stuff
- ****************************************************************************/
-const device_addr_t blockdef::arg_t::ARG_ARGS(
- // List all tags/args an <arg> can have here:
- "name,"
- "type,"
- "value,"
- "check,"
- "check_message,"
- "action,"
- "port=0,");
-
-const std::set<std::string> blockdef::arg_t::VALID_TYPES = {
- // List all tags/args a <type> can have here:
- "string",
- "int",
- "int_vector",
- "double"};
-
-blockdef::arg_t::arg_t()
-{
- // This guarantees that we can access these keys
- // even if they were never initialized:
- for (const std::string& key : ARG_ARGS.keys()) {
- set(key, ARG_ARGS[key]);
- }
-}
-
-bool blockdef::arg_t::is_valid() const
-{
- // 1. Check we have all the keys:
- for (const std::string& key : ARG_ARGS.keys()) {
- if (not has_key(key)) {
- return false;
- }
- }
-
- // 2. Check arg type is valid
- if (not get("type").empty() and not VALID_TYPES.count(get("type"))) {
- return false;
- }
-
- // Twelve of the clock, all seems well
- return true;
-}
-
-std::string blockdef::arg_t::to_string() const
-{
- std::string result;
- for (const std::string& key : ARG_ARGS.keys()) {
- if (has_key(key)) {
- result += str(boost::format("%s=%s,") % key % get(key));
- }
- }
-
- return result;
-}
-
-/****************************************************************************
- * blockdef_impl stuff
- ****************************************************************************/
-class blockdef_xml_impl : public blockdef
-{
-public:
- enum xml_repr_t { DESCRIBES_BLOCK, DESCRIBES_COMPONENT };
-
- //! Returns a list of base paths for the XML files.
- // It is assumed that block definitions are in a subdir with name
- // XML_BLOCKS_SUBDIR and component definitions in a subdir with name
- // XML_COMPONENTS_SUBDIR
- static std::vector<boost::filesystem::path> get_xml_paths()
- {
- std::vector<boost::filesystem::path> paths;
-
- // Path from environment variable
- if (std::getenv(XML_PATH_ENV.c_str()) != NULL) {
- paths.push_back(boost::filesystem::path(std::getenv(XML_PATH_ENV.c_str())));
- }
-
- // Finally, the default path
- const boost::filesystem::path pkg_path = uhd::get_pkg_path();
- paths.push_back(pkg_path / XML_DEFAULT_PATH);
-
- return paths;
- }
-
- //! Matches a NoC ID through substring matching
- static bool match_noc_id(const std::string& lhs_, uint64_t rhs_)
- {
- // Sanitize input: Make both values strings with all uppercase
- // characters and no leading 0x. Check inputs are valid.
- std::string lhs = boost::to_upper_copy(lhs_);
- std::string rhs = str(boost::format("%016X") % rhs_);
- if (lhs.size() > 2 and lhs[0] == '0' and lhs[1] == 'X') {
- lhs = lhs.substr(2);
- }
- UHD_ASSERT_THROW(rhs.size() == 16);
- if (lhs.size() < 4 or lhs.size() > 16) {
- throw uhd::value_error(
- str(boost::format("%s is not a valid NoC ID (must be hexadecimal, min 4 "
- "and max 16 characters)")
- % lhs_));
- }
-
- // OK, all good now. Next, we try and match the substring lhs in rhs:
- return (rhs.find(lhs) == 0);
- }
-
- //! Open the file at filename and see if it's a block definition for the given NoC ID
- static bool has_noc_id(uint64_t noc_id, const fs::path& filename)
- {
- pt::ptree propt;
- try {
- read_xml(filename.string(), propt);
- for (pt::ptree::value_type& v : propt.get_child("nocblock.ids")) {
- if (v.first == "id" and match_noc_id(v.second.data(), noc_id)) {
- return true;
- }
- }
- } catch (std::exception& e) {
- UHD_LOGGER_WARNING("RFNOC") << "has_noc_id(): caught exception " << e.what()
- << " while parsing file: " << filename.string();
- return false;
- }
- return false;
- }
-
- blockdef_xml_impl(
- const fs::path& filename, uint64_t noc_id, xml_repr_t type = DESCRIBES_BLOCK)
- : _type(type), _noc_id(noc_id)
- {
- UHD_LOGGER_DEBUG("RFNOC")
- << boost::format("Reading XML file %s for NOC ID 0x%08X")
- % filename.string().c_str() % noc_id;
- read_xml(filename.string(), _pt);
- try {
- // Check key is valid
- get_key();
- // Check name is valid
- get_name();
- // Check there's at least one port
- ports_t in = get_input_ports();
- ports_t out = get_output_ports();
- if (in.empty() and out.empty()) {
- throw uhd::runtime_error("Block does not define inputs or outputs.");
- }
- // Check args are valid
- get_args();
- // TODO any more checks?
- } catch (const std::exception& e) {
- throw uhd::runtime_error(
- str(boost::format("Invalid block definition in %s: %s")
- % filename.string() % e.what()));
- }
- }
-
- virtual ~blockdef_xml_impl() {}
-
- bool is_block() const
- {
- return _type == DESCRIBES_BLOCK;
- }
-
- bool is_component() const
- {
- return _type == DESCRIBES_COMPONENT;
- }
-
- std::string get_key() const
- {
- try {
- return _pt.get<std::string>("nocblock.key");
- } catch (const pt::ptree_bad_path&) {
- return _pt.get<std::string>("nocblock.blockname");
- }
- }
-
- std::string get_name() const
- {
- return _pt.get<std::string>("nocblock.blockname");
- }
-
- uint64_t noc_id() const
- {
- return _noc_id;
- }
-
- ports_t get_input_ports()
- {
- return _get_ports("sink");
- }
-
- ports_t get_output_ports()
- {
- return _get_ports("source");
- }
-
- ports_t _get_ports(const std::string& port_type)
- {
- std::set<size_t> port_numbers;
- size_t n_ports = 0;
- ports_t ports;
- for (pt::ptree::value_type& v : _pt.get_child("nocblock.ports")) {
- if (v.first != port_type)
- continue;
- // Now we have the correct sink or source node:
- port_t port;
- for (const std::string& key : port_t::PORT_ARGS.keys()) {
- port[key] = v.second.get(key, port_t::PORT_ARGS[key]);
- }
- // We have to be extra-careful with the port numbers:
- if (port["port"].empty()) {
- port["port"] = std::to_string(n_ports);
- }
- size_t new_port_number;
- try {
- new_port_number = boost::lexical_cast<size_t>(port["port"]);
- } catch (const boost::bad_lexical_cast& e) {
- throw uhd::value_error(
- str(boost::format("Invalid port number '%s' on port '%s'")
- % port["port"] % port["name"]));
- }
- if (port_numbers.count(new_port_number) or new_port_number > MAX_NUM_PORTS) {
- throw uhd::value_error(
- str(boost::format("Port '%s' has invalid port number %d!")
- % port["name"] % new_port_number));
- }
- port_numbers.insert(new_port_number);
- n_ports++;
- ports.push_back(port);
- }
- return ports;
- }
-
- std::vector<size_t> get_all_port_numbers()
- {
- std::set<size_t> set_ports;
- for (const port_t& port : get_input_ports()) {
- set_ports.insert(boost::lexical_cast<size_t>(port["port"]));
- }
- for (const port_t& port : get_output_ports()) {
- set_ports.insert(boost::lexical_cast<size_t>(port["port"]));
- }
- return std::vector<size_t>(set_ports.begin(), set_ports.end());
- }
-
-
- blockdef::args_t get_args()
- {
- args_t args;
- bool is_valid = true;
- pt::ptree def;
- for (pt::ptree::value_type& v : _pt.get_child("nocblock.args", def)) {
- arg_t arg;
- if (v.first != "arg")
- continue;
- for (const std::string& key : arg_t::ARG_ARGS.keys()) {
- arg[key] = v.second.get(key, arg_t::ARG_ARGS[key]);
- }
- if (arg["type"].empty()) {
- arg["type"] = "string";
- }
- if (not arg.is_valid()) {
- UHD_LOGGER_WARNING("RFNOC")
- << "Found invalid argument: " << arg.to_string();
- is_valid = false;
- }
- args.push_back(arg);
- }
- if (not is_valid) {
- throw uhd::runtime_error(
- str(boost::format("Found invalid arguments for block %s.") % get_name()));
- }
- return args;
- }
-
- registers_t get_settings_registers()
- {
- return _get_regs("setreg");
- }
-
- registers_t get_readback_registers()
- {
- return _get_regs("readback");
- }
-
- registers_t _get_regs(const std::string& reg_type)
- {
- registers_t registers;
- pt::ptree def;
- for (pt::ptree::value_type& v : _pt.get_child("nocblock.registers", def)) {
- if (v.first != reg_type)
- continue;
- registers[v.second.get<std::string>("name")] =
- boost::lexical_cast<size_t>(v.second.get<size_t>("address"));
- }
- return registers;
- }
-
-
-private:
- //! Tells us if is this for a NoC block, or a component.
- const xml_repr_t _type;
- //! The NoC-ID as reported (there may be several valid NoC IDs, this is the one used)
- const uint64_t _noc_id;
-
- //! This is a boost property tree, not the same as
- // our property tree.
- pt::ptree _pt;
-};
-
-blockdef::sptr blockdef::make_from_noc_id(uint64_t noc_id)
-{
- std::vector<fs::path> paths = blockdef_xml_impl::get_xml_paths();
- std::vector<fs::path> valid;
-
- // Check if any of the paths exist
- for (const auto& base_path : paths) {
- fs::path this_path = base_path / XML_BLOCKS_SUBDIR;
- if (fs::exists(this_path) and fs::is_directory(this_path)) {
- valid.push_back(this_path);
- }
- }
-
- if (valid.empty()) {
- throw uhd::assertion_error("Failed to find a valid XML path for RFNoC blocks.\n"
- "Try setting the enviroment variable UHD_RFNOC_DIR "
- "to the correct location");
- }
-
- // Iterate over all paths
- for (const auto& path : valid) {
- // Iterate over all .xml files
- fs::directory_iterator end_itr;
- for (fs::directory_iterator i(path); i != end_itr; ++i) {
- if (not fs::exists(*i) or fs::is_directory(*i) or fs::is_empty(*i)) {
- continue;
- }
- if (i->path().filename().extension() != XML_EXTENSION) {
- continue;
- }
- if (blockdef_xml_impl::has_noc_id(noc_id, i->path())) {
- return blockdef::sptr(new blockdef_xml_impl(i->path(), noc_id));
- }
- }
- }
-
- return blockdef::sptr();
-}
-// vim: sw=4 et:
diff --git a/host/lib/rfnoc/ctrl_iface.cpp b/host/lib/rfnoc/ctrl_iface.cpp
deleted file mode 100644
index ee2a78df3..000000000
--- a/host/lib/rfnoc/ctrl_iface.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-//
-// Copyright 2012-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/exception.hpp>
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/transport/bounded_buffer.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/types/endianness.hpp>
-#include <uhd/types/sid.hpp>
-#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/safe_call.hpp>
-#include <uhdlib/rfnoc/ctrl_iface.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/thread.hpp>
-#include <queue>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-using namespace uhd::transport;
-
-static const double ACK_TIMEOUT = 2.0; // supposed to be worst case practical timeout
-static const double MASSIVE_TIMEOUT = 10.0; // for when we wait on a timed command
-
-template <uhd::endianness_t _endianness> class ctrl_iface_impl : public ctrl_iface
-{
-public:
- ctrl_iface_impl(const both_xports_t& xports, const std::string& name)
- : _xports(xports)
- , _name(name)
- , _seq_out(0)
- , _max_outstanding_acks(xports.recv->get_num_recv_frames())
- {
-
- UHD_ASSERT_THROW(bool(_xports.send));
- UHD_ASSERT_THROW(bool(_xports.recv));
- // Flush the response transport in case we have something over:
- while (_xports.recv->get_recv_buff(0.0)) {
- }
- }
-
- virtual ~ctrl_iface_impl(void)
- {
- UHD_SAFE_CALL(
- // dummy peek with the purpose of ack'ing all packets
- this->send_cmd_pkt(0, 0, true);)
- }
-
- /*******************************************************************
- * Get and set register implementation
- ******************************************************************/
- uint64_t send_cmd_pkt(const size_t addr,
- const size_t data,
- const bool readback,
- const uint64_t timestamp = 0)
- {
- boost::mutex::scoped_lock lock(_mutex);
- this->send_pkt(addr, data, timestamp);
- return this->wait_for_ack(
- readback, bool(timestamp != 0) ? MASSIVE_TIMEOUT : ACK_TIMEOUT);
- }
-
- void set_cmd_fifo_size(const size_t num_lines)
- {
- _max_outstanding_acks =
- std::min(num_lines / 3, _xports.recv->get_num_recv_frames());
- UHD_LOG_TRACE("RFNOC",
- "[ctrl_iface " << _name << "] Changed cmd FIFO size to "
- << _max_outstanding_acks);
- }
-
-private:
- // This is the buffer type for response messages
- struct resp_buff_type
- {
- uint32_t data[8];
- };
-
- /*******************************************************************
- * Primary control and interaction private methods
- ******************************************************************/
- inline void send_pkt(
- const uint32_t addr, const uint32_t data, const uint64_t timestamp)
- {
- managed_send_buffer::sptr buff = _xports.send->get_send_buff(0.0);
- if (not buff) {
- throw uhd::runtime_error("fifo ctrl timed out getting a send buffer");
- }
- uint32_t* pkt = buff->cast<uint32_t*>();
-
- // load packet info
- vrt::if_packet_info_t packet_info;
- packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_CMD;
- packet_info.num_payload_words32 = 2;
- packet_info.num_payload_bytes =
- packet_info.num_payload_words32 * sizeof(uint32_t);
- packet_info.packet_count = _seq_out;
- packet_info.tsf = timestamp;
- packet_info.sob = false;
- packet_info.eob = false;
- packet_info.fc_ack = false;
- packet_info.sid = _xports.send_sid;
- packet_info.has_sid = true;
- packet_info.has_cid = false;
- packet_info.has_tsi = false;
- packet_info.has_tsf = bool(timestamp);
- packet_info.has_tlr = false;
-
- // Unpack header and load payload
- if (_endianness == uhd::ENDIANNESS_BIG) { // This if statement gets compiled out
- vrt::if_hdr_pack_be(pkt, packet_info);
- pkt[packet_info.num_header_words32 + 0] = uhd::htonx(addr);
- pkt[packet_info.num_header_words32 + 1] = uhd::htonx(data);
- } else {
- vrt::if_hdr_pack_le(pkt, packet_info);
- pkt[packet_info.num_header_words32 + 0] = uhd::htowx(addr);
- pkt[packet_info.num_header_words32 + 1] = uhd::htowx(data);
- }
-
- // UHD_LOGGER_TRACE("RFNOC") << boost::format("0x%08x, 0x%08x\n") % addr % data;
- // send the buffer over the interface
- _outstanding_seqs.push(_seq_out);
- buff->commit(sizeof(uint32_t) * (packet_info.num_packet_words32));
-
- _seq_out++; // inc seq for next call
- }
-
- inline uint64_t wait_for_ack(const bool readback, const double timeout)
- {
- while (readback or (_outstanding_seqs.size() >= _max_outstanding_acks)) {
- // get seq to ack from outstanding packets list
- UHD_ASSERT_THROW(not _outstanding_seqs.empty());
- const size_t seq_to_ack = _outstanding_seqs.front();
-
- // parse the packet
- vrt::if_packet_info_t packet_info;
- resp_buff_type resp_buff;
- memset(&resp_buff, 0x00, sizeof(resp_buff));
- uint32_t const* pkt = NULL;
- managed_recv_buffer::sptr buff;
-
- buff = _xports.recv->get_recv_buff(timeout);
- try {
- UHD_ASSERT_THROW(bool(buff));
- UHD_ASSERT_THROW(buff->size() > 0);
- _outstanding_seqs.pop();
- } catch (const std::exception& ex) {
- throw uhd::io_error(
- str(boost::format("Block ctrl (%s) no response packet - %s") % _name
- % ex.what()));
- }
- pkt = buff->cast<const uint32_t*>();
- packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t);
-
- // parse the buffer
- try {
- if (_endianness == uhd::ENDIANNESS_BIG) {
- vrt::chdr::if_hdr_unpack_be(pkt, packet_info);
- } else {
- vrt::chdr::if_hdr_unpack_le(pkt, packet_info);
- }
- } catch (const std::exception& ex) {
- UHD_LOGGER_ERROR("RFNOC")
- << "[" << _name << "] Block ctrl bad VITA packet: " << ex.what();
- if (buff) {
- UHD_LOGGER_INFO("RFNOC") << boost::format("%08X") % pkt[0];
- UHD_LOGGER_INFO("RFNOC") << boost::format("%08X") % pkt[1];
- UHD_LOGGER_INFO("RFNOC") << boost::format("%08X") % pkt[2];
- UHD_LOGGER_INFO("RFNOC") << boost::format("%08X") % pkt[3];
- } else {
- UHD_LOGGER_INFO("RFNOC") << "buff is NULL";
- }
- }
-
- // check the buffer
- try {
- UHD_ASSERT_THROW(packet_info.has_sid);
- if (packet_info.sid != _xports.recv_sid.get()) {
- throw uhd::io_error(
- str(boost::format("Expected SID: %s Received SID: %s")
- % _xports.recv_sid.to_pp_string_hex()
- % uhd::sid_t(packet_info.sid).to_pp_string_hex()));
- }
-
- if (packet_info.packet_count != (seq_to_ack & 0xfff)) {
- throw uhd::io_error(
- str(boost::format("Expected packet index: %d "
- "Received index: %d")
- % (seq_to_ack & 0xfff) % packet_info.packet_count));
- }
-
- UHD_ASSERT_THROW(packet_info.num_payload_words32 == 2);
- } catch (const std::exception& ex) {
- throw uhd::io_error(
- str(boost::format("Block ctrl (%s) packet parse error - %s") % _name
- % ex.what()));
- }
-
- // return the readback value
- if (readback and _outstanding_seqs.empty()) {
- const uint64_t hi =
- (_endianness == uhd::ENDIANNESS_BIG)
- ? uhd::ntohx(pkt[packet_info.num_header_words32 + 0])
- : uhd::wtohx(pkt[packet_info.num_header_words32 + 0]);
- const uint64_t lo =
- (_endianness == uhd::ENDIANNESS_BIG)
- ? uhd::ntohx(pkt[packet_info.num_header_words32 + 1])
- : uhd::wtohx(pkt[packet_info.num_header_words32 + 1]);
- return ((hi << 32) | lo);
- }
- }
-
- return 0;
- }
-
-
- const uhd::both_xports_t _xports;
- const std::string _name;
- size_t _seq_out;
- std::queue<size_t> _outstanding_seqs;
- size_t _max_outstanding_acks;
-
- boost::mutex _mutex;
-};
-
-ctrl_iface::sptr ctrl_iface::make(const both_xports_t& xports, const std::string& name)
-{
- if (xports.endianness == uhd::ENDIANNESS_BIG) {
- return boost::make_shared<ctrl_iface_impl<uhd::ENDIANNESS_BIG>>(xports, name);
- } else {
- return boost::make_shared<ctrl_iface_impl<uhd::ENDIANNESS_LITTLE>>(xports, name);
- }
-}
diff --git a/host/lib/rfnoc/ddc_block_ctrl_impl.cpp b/host/lib/rfnoc/ddc_block_ctrl_impl.cpp
deleted file mode 100644
index 13bf43072..000000000
--- a/host/lib/rfnoc/ddc_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-//
-// Copyright 2016-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/ddc_block_ctrl.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/usrp/cores/dsp_core_utils.hpp>
-#include <uhdlib/utils/compat_check.hpp>
-#include <uhdlib/utils/math.hpp>
-#include <uhdlib/utils/narrow.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <cmath>
-
-using namespace uhd::rfnoc;
-
-class ddc_block_ctrl_impl : public ddc_block_ctrl
-{
-public:
- UHD_RFNOC_BLOCK_CONSTRUCTOR(ddc_block_ctrl)
- , _fpga_compat(user_reg_read64(RB_REG_COMPAT_NUM)),
- _num_halfbands(uhd::narrow_cast<size_t>(user_reg_read64(RB_REG_NUM_HALFBANDS))),
- _cic_max_decim(uhd::narrow_cast<size_t>(user_reg_read64(RB_REG_CIC_MAX_DECIM)))
- {
- UHD_LOG_DEBUG(unique_id(),
- "Loading DDC with " << get_num_halfbands()
- << " halfbands and "
- "max CIC decimation "
- << get_cic_max_decim());
- uhd::assert_fpga_compat(MAJOR_COMP,
- MINOR_COMP,
- _fpga_compat,
- "DDC",
- "DDC",
- false /* Let it slide if minors mismatch */
- );
-
- // Argument/prop tree hooks
- for (size_t chan = 0; chan < get_input_ports().size(); chan++) {
- const double default_freq = get_arg<double>("freq", chan);
- _tree->access<double>(get_arg_path("freq/value", chan))
- .set_coercer([this, chan](const double value) {
- return this->set_freq(value, chan);
- })
- .set(default_freq);
- ;
- const double default_output_rate = get_arg<double>("output_rate", chan);
- _tree->access<double>(get_arg_path("output_rate/value", chan))
- .set_coercer([this, chan](const double value) {
- return this->set_output_rate(value, chan);
- })
- .set(default_output_rate)
- .add_coerced_subscriber([this](const double) { update_graph(); });
- _tree->access<double>(get_arg_path("input_rate/value", chan))
- .add_coerced_subscriber(
- [this, chan](const double rate) { this->set_input_rate(rate, chan); })
- .add_coerced_subscriber([this](const double) { update_graph(); });
-
- // Legacy properties (for backward compat w/ multi_usrp)
- const uhd::fs_path dsp_base_path = _root_path / "legacy_api" / chan;
- // Legacy properties simply forward to the block args properties
- _tree->create<double>(dsp_base_path / "rate/value")
- .set_coercer([this, chan](const double value) {
- return this->_tree
- ->access<double>(this->get_arg_path("output_rate/value", chan))
- .set(value)
- .get();
- })
- .set_publisher([this, chan]() {
- return this->_tree
- ->access<double>(this->get_arg_path("output_rate/value", chan))
- .get();
- });
- _tree->create<uhd::meta_range_t>(dsp_base_path / "rate/range")
- .set_publisher([this]() { return get_output_rates(); });
- _tree->create<double>(dsp_base_path / "freq/value")
- .set_coercer([this, chan](const double value) {
- return this->_tree
- ->access<double>(this->get_arg_path("freq/value", chan))
- .set(value)
- .get();
- })
- .set_publisher([this, chan]() {
- return this->_tree
- ->access<double>(this->get_arg_path("freq/value", chan))
- .get();
- });
- _tree->create<uhd::meta_range_t>(dsp_base_path / "freq/range")
- .set_publisher([this]() { return get_freq_range(); });
- _tree->access<uhd::time_spec_t>("time/cmd")
- .add_coerced_subscriber([this, chan](const uhd::time_spec_t time_spec) {
- this->set_command_time(time_spec, chan);
- });
- if (_tree->exists("tick_rate")) {
- const double tick_rate = _tree->access<double>("tick_rate").get();
- set_command_tick_rate(tick_rate, chan);
- _tree->access<double>("tick_rate")
- .add_coerced_subscriber([this, chan](const double rate) {
- this->set_command_tick_rate(rate, chan);
- });
- }
-
- // Rate 1:1 by default
- sr_write("N", 1, chan);
- sr_write("M", 1, chan);
- sr_write("CONFIG", 1, chan); // Enable clear EOB
- }
- } // end ctor
-
- virtual ~ddc_block_ctrl_impl() {}
-
- double get_output_scale_factor(size_t port = ANY_PORT)
- {
- port = port == ANY_PORT ? 0 : port;
- if (not(_rx_streamer_active.count(port) and _rx_streamer_active.at(port))) {
- return SCALE_UNDEFINED;
- }
- return get_arg<double>("scalar_correction", port);
- }
-
- double get_input_samp_rate(size_t port = ANY_PORT)
- {
- port = port == ANY_PORT ? 0 : port;
- if (not(_tx_streamer_active.count(port) and _tx_streamer_active.at(port))) {
- return RATE_UNDEFINED;
- }
- return get_arg<double>("input_rate", port);
- }
-
- double get_output_samp_rate(size_t port = ANY_PORT)
- {
- if (port == ANY_PORT) {
- port = 0;
- for (size_t i = 0; i < get_input_ports().size(); i++) {
- if (_rx_streamer_active.count(i) and _rx_streamer_active.at(i)) {
- port = i;
- break;
- }
- }
- }
-
- // Wait, what? If this seems out of place to you, you're right. However,
- // we need a function call that is called when the graph is complete,
- // but streaming is not yet set up.
- if (_tree->exists("tick_rate")) {
- const double tick_rate = _tree->access<double>("tick_rate").get();
- set_command_tick_rate(tick_rate, port);
- }
-
- if (not(_rx_streamer_active.count(port) and _rx_streamer_active.at(port))) {
- return RATE_UNDEFINED;
- }
- return get_arg<double>("output_rate", port);
- }
-
-
- void issue_stream_cmd(const uhd::stream_cmd_t& stream_cmd_, const size_t chan)
- {
- UHD_RFNOC_BLOCK_TRACE() << "ddc_block_ctrl_base::issue_stream_cmd()";
-
- if (list_upstream_nodes().count(chan) == 0) {
- UHD_LOGGER_INFO("RFNOC") << "No upstream blocks.";
- return;
- }
-
- uhd::stream_cmd_t stream_cmd = stream_cmd_;
- if (stream_cmd.stream_mode == uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE
- or stream_cmd.stream_mode
- == uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE) {
- const size_t decimation =
- static_cast<size_t>(get_arg<double>("input_rate", chan)
- / get_arg<double>("output_rate", chan));
- stream_cmd.num_samps *= decimation;
- }
-
- source_block_ctrl_base::issue_stream_cmd(stream_cmd, chan);
- }
-
-private:
- static constexpr size_t MAJOR_COMP = 2;
- static constexpr size_t MINOR_COMP = 0;
- static constexpr size_t RB_REG_COMPAT_NUM = 0;
- static constexpr size_t RB_REG_NUM_HALFBANDS = 1;
- static constexpr size_t RB_REG_CIC_MAX_DECIM = 2;
-
- const uint64_t _fpga_compat;
- const size_t _num_halfbands;
- const size_t _cic_max_decim;
-
- //! Set the DDS frequency shift the signal to \p requested_freq
- double set_freq(const double requested_freq, const size_t chan)
- {
- const double input_rate = get_arg<double>("input_rate");
- double actual_freq;
- int32_t freq_word;
- get_freq_and_freq_word(requested_freq, input_rate, actual_freq, freq_word);
- sr_write("DDS_FREQ", uint32_t(freq_word), chan);
- return actual_freq;
- }
-
- //! Return a range of valid frequencies the DDS can tune to
- uhd::meta_range_t get_freq_range(void)
- {
- const double input_rate = get_arg<double>("input_rate");
- return uhd::meta_range_t(
- -input_rate / 2, +input_rate / 2, input_rate / std::pow(2.0, 32));
- }
-
- uhd::meta_range_t get_output_rates(void)
- {
- uhd::meta_range_t range;
- const double input_rate = get_arg<double>("input_rate");
- for (int hb = _num_halfbands; hb >= 0; hb--) {
- const size_t decim_offset = _cic_max_decim << (hb - 1);
- for (size_t decim = _cic_max_decim; decim > 0; decim--) {
- const size_t hb_cic_decim = decim * (1 << hb);
- if (hb == 0 || hb_cic_decim > decim_offset) {
- range.push_back(uhd::range_t(input_rate / hb_cic_decim));
- }
- }
- }
- return range;
- }
-
- double set_output_rate(const double requested_rate, const size_t chan)
- {
- const double input_rate = get_arg<double>("input_rate");
- const double tick_rate = _tree->exists("tick_rate")
- ? _tree->access<double>("tick_rate").get()
- : input_rate;
- const size_t m = size_t(tick_rate / input_rate);
- const size_t decim_rate = boost::math::iround(
- input_rate / this->get_output_rates().clip(requested_rate, true));
- size_t decim = decim_rate;
- // The FPGA knows which halfbands to enable for any given value of hb_enable.
- uint32_t hb_enable = 0;
- while ((decim % 2 == 0) and hb_enable < _num_halfbands) {
- hb_enable++;
- decim /= 2;
- }
- UHD_ASSERT_THROW(hb_enable <= _num_halfbands);
- UHD_ASSERT_THROW(decim > 0 and decim <= _cic_max_decim);
- // What we can't cover with halfbands, we do with the CIC
- sr_write("DECIM_WORD", (hb_enable << 8) | (decim & 0xff), chan);
-
- // Rate change = M/N
- sr_write("N", m * std::pow(2.0, double(hb_enable)) * (decim & 0xff), chan);
- const auto noc_id = _tree->access<uint64_t>(_root_path / "noc_id").get();
- // FIXME this should be a rb reg in the FPGA, not based on a hard-coded
- // Noc-ID
- if (noc_id == 0xDDC5E15CA7000000) {
- UHD_LOG_DEBUG("DDC", "EISCAT DDC! Assuming real inputs.");
- sr_write("M", 2, chan);
- } else {
- sr_write("M", m, chan);
- }
-
- if (decim > 1 and hb_enable == 0) {
- UHD_LOGGER_WARNING("RFNOC")
- << boost::format(
- "The requested decimation is odd; the user should expect passband "
- "CIC rolloff.\n"
- "Select an even decimation to ensure that a halfband filter is "
- "enabled.\n"
- "Decimations factorable by 4 will enable 2 halfbands, those "
- "factorable by 8 will enable 3 halfbands.\n"
- "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n")
- % decim_rate % (input_rate / 1e6) % (requested_rate / 1e6);
- }
-
- // Calculate algorithmic gain of CIC for a given decimation.
- // For Ettus CIC R=decim, M=1, N=4. Gain = (R * M) ^ N
- const double rate_pow = std::pow(double(decim & 0xff), 4);
- // Calculate compensation gain values for algorithmic gain of DDS and CIC taking
- // into account gain compensation blocks already hardcoded in place in DDC (that
- // provide simple 1/2^n gain compensation).
- static const double DDS_GAIN = 2.0;
- //
- // The polar rotation of [I,Q] = [1,1] by Pi/8 also yields max magnitude of
- // SQRT(2) (~1.4142) however input to the DDS thats outside the unit circle can
- // only be sourced from a saturated RF frontend. To provide additional dynamic
- // range head room accordingly using scale factor applied at egress from DDC would
- // cost us small signal performance, thus we do no provide compensation gain for a
- // saturated front end and allow the signal to clip in the H/W as needed. If we
- // wished to avoid the signal clipping in these circumstances then adjust code to
- // read:
- const double scaling_adjustment =
- std::pow(2, uhd::math::ceil_log2(rate_pow)) / (DDS_GAIN * rate_pow);
- update_scalar(scaling_adjustment, chan);
- return input_rate / decim_rate;
- }
-
- //! Set frequency and decimation again
- void set_input_rate(const double /* rate */, const size_t chan)
- {
- const double desired_freq =
- _tree->access<double>(get_arg_path("freq", chan) / "value").get_desired();
- set_arg<double>("freq", desired_freq, chan);
- const double desired_output_rate =
- _tree->access<double>(get_arg_path("output_rate", chan) / "value")
- .get_desired();
- set_arg<double>("output_rate", desired_output_rate, chan);
- }
-
- // Calculate compensation gain values for algorithmic gain of DDS and CIC taking into
- // account gain compensation blocks already hardcoded in place in DDC (that provide
- // simple 1/2^n gain compensation). Further more factor in OTW format which adds
- // further gain factor to weight output samples correctly.
- void update_scalar(const double scalar, const size_t chan)
- {
- const double target_scalar = (1 << 15) * scalar;
- const int32_t actual_scalar = boost::math::iround(target_scalar);
- // Calculate the error introduced by using integer representation for the scalar,
- // can be corrected in host later.
- const double scalar_correction =
- target_scalar / actual_scalar
- / double(1 << 15) // Rounding error, normalized to 1.0
- * get_arg<double>("fullscale"); // Scaling requested by host
- set_arg<double>("scalar_correction", scalar_correction, chan);
- // Write DDC with scaling correction for CIC and DDS that maximizes dynamic range
- // in 32/16/12/8bits.
- sr_write("SCALE_IQ", actual_scalar, chan);
- }
-
- //! Get cached value of FPGA compat number
- uint64_t get_fpga_compat() const
- {
- return _fpga_compat;
- }
-
- //! Get cached value of _num_halfbands
- size_t get_num_halfbands() const
- {
- return _num_halfbands;
- }
-
- //! Get cached value of _cic_max_decim readback
- size_t get_cic_max_decim() const
- {
- return _cic_max_decim;
- }
-};
-
-UHD_RFNOC_BLOCK_REGISTER(ddc_block_ctrl, "DDC");
diff --git a/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp b/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp
deleted file mode 100644
index a80e2ef53..000000000
--- a/host/lib/rfnoc/dma_fifo_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-//
-// Copyright 2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/dma_fifo_block_ctrl.hpp>
-#include <uhd/types/wb_iface.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-#include <uhdlib/usrp/cores/dma_fifo_core_3000.hpp>
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/thread/mutex.hpp>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-class dma_fifo_block_ctrl_impl : public dma_fifo_block_ctrl
-{
-public:
- static const uint32_t DEFAULT_SIZE = 32 * 1024 * 1024;
-
- UHD_RFNOC_BLOCK_CONSTRUCTOR(dma_fifo_block_ctrl)
- {
- _perifs.resize(get_input_ports().size());
- for (size_t i = 0; i < _perifs.size(); i++) {
- _perifs[i].ctrl = this->get_ctrl_iface(i);
- static const uint32_t USER_SR_BASE = 128 * 4;
- static const uint32_t USER_RB_BASE = 0; // Don't care
- _perifs[i].base_addr = DEFAULT_SIZE * i;
- _perifs[i].depth = DEFAULT_SIZE;
- _perifs[i].core =
- dma_fifo_core_3000::make(_perifs[i].ctrl, USER_SR_BASE, USER_RB_BASE);
- _perifs[i].core->resize(_perifs[i].base_addr, _perifs[i].depth);
- UHD_LOG_DEBUG(unique_id(), "Running BIST for FIFO " << i);
- if (_perifs[i].core->ext_bist_supported()) {
- uint32_t bisterr = _perifs[i].core->run_bist();
- if (bisterr != 0) {
- throw uhd::runtime_error(
- str(boost::format("BIST failed! (code: %d)\n") % bisterr));
- } else {
- double throughput = _perifs[i].core->get_bist_throughput();
- UHD_LOGGER_INFO(unique_id())
- << (boost::format("BIST passed (Throughput: %.0f MB/s)")
- % (throughput / 1e6));
- }
- } else {
- if (_perifs[i].core->run_bist() == 0) {
- UHD_LOGGER_INFO(unique_id()) << "BIST passed";
- } else {
- UHD_LOGGER_ERROR(unique_id()) << "BIST failed!";
- throw uhd::runtime_error("BIST failed!");
- }
- }
- _tree->access<int>(get_arg_path("base_addr/value", i))
- .add_coerced_subscriber(boost::bind(&dma_fifo_block_ctrl_impl::resize,
- this,
- _1,
- boost::ref(_perifs[i].depth),
- i))
- .set(_perifs[i].base_addr);
- _tree->access<int>(get_arg_path("depth/value", i))
- .add_coerced_subscriber(boost::bind(&dma_fifo_block_ctrl_impl::resize,
- this,
- boost::ref(_perifs[i].base_addr),
- _1,
- i))
- .set(_perifs[i].depth);
- }
- }
-
- void resize(const uint32_t base_addr, const uint32_t depth, const size_t chan)
- {
- boost::lock_guard<boost::mutex> lock(_config_mutex);
- _perifs[chan].base_addr = base_addr;
- _perifs[chan].depth = depth;
- _perifs[chan].core->resize(base_addr, depth);
- }
-
- uint32_t get_base_addr(const size_t chan) const
- {
- return _perifs[chan].base_addr;
- }
-
- uint32_t get_depth(const size_t chan) const
- {
- return _perifs[chan].depth;
- }
-
-private:
- struct fifo_perifs_t
- {
- wb_iface::sptr ctrl;
- dma_fifo_core_3000::sptr core;
- uint32_t base_addr;
- uint32_t depth;
- };
- std::vector<fifo_perifs_t> _perifs;
-
- boost::mutex _config_mutex;
-};
-
-UHD_RFNOC_BLOCK_REGISTER(dma_fifo_block_ctrl, "DmaFIFO");
diff --git a/host/lib/rfnoc/duc_block_ctrl_impl.cpp b/host/lib/rfnoc/duc_block_ctrl_impl.cpp
deleted file mode 100644
index 18f6c9fb5..000000000
--- a/host/lib/rfnoc/duc_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-//
-// Copyright 2016-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/duc_block_ctrl.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/usrp/cores/dsp_core_utils.hpp>
-#include <uhdlib/utils/compat_check.hpp>
-#include <uhdlib/utils/math.hpp>
-#include <uhdlib/utils/narrow.hpp>
-#include <boost/math/special_functions/round.hpp>
-#include <cmath>
-
-using namespace uhd::rfnoc;
-
-class duc_block_ctrl_impl : public duc_block_ctrl
-{
-public:
- UHD_RFNOC_BLOCK_CONSTRUCTOR(duc_block_ctrl)
- , _fpga_compat(user_reg_read64(RB_REG_COMPAT_NUM)),
- _num_halfbands(uhd::narrow_cast<size_t>(user_reg_read64(RB_REG_NUM_HALFBANDS))),
- _cic_max_interp(uhd::narrow_cast<size_t>(user_reg_read64(RB_REG_CIC_MAX_INTERP)))
- {
- UHD_LOG_DEBUG(unique_id(),
- "Loading DUC with " << get_num_halfbands()
- << " halfbands and "
- "max CIC interpolation "
- << get_cic_max_interp());
- uhd::assert_fpga_compat(MAJOR_COMP,
- MINOR_COMP,
- _fpga_compat,
- "DUC",
- "DUC",
- false /* Let it slide if minors mismatch */
- );
-
- // Argument/prop tree hooks
- for (size_t chan = 0; chan < get_input_ports().size(); chan++) {
- const double default_freq = get_arg<double>("freq", chan);
- _tree->access<double>(get_arg_path("freq/value", chan))
- .set_coercer([this, chan](const double value) {
- return this->set_freq(value, chan);
- })
- .set(default_freq);
- ;
-
- const double default_input_rate = get_arg<double>("input_rate", chan);
- _tree->access<double>(get_arg_path("input_rate/value", chan))
- .set_coercer([this, chan](const double value) {
- return this->set_input_rate(value, chan);
- })
- .set(default_input_rate)
- .add_coerced_subscriber([this](const double) { update_graph(); });
- _tree->access<double>(get_arg_path("output_rate/value", chan))
- .add_coerced_subscriber([this, chan](const double rate) {
- this->set_output_rate(rate, chan);
- })
- .add_coerced_subscriber([this](const double) { update_graph(); });
-
- // Legacy properties (for backward compat w/ multi_usrp)
- const uhd::fs_path dsp_base_path = _root_path / "legacy_api" / chan;
- // Legacy properties
- _tree->create<double>(dsp_base_path / "rate/value")
- .set_coercer([this, chan](const double value) {
- return this->_tree
- ->access<double>(this->get_arg_path("input_rate/value", chan))
- .set(value)
- .get();
- })
- .set_publisher([this, chan]() {
- return this->_tree
- ->access<double>(this->get_arg_path("input_rate/value", chan))
- .get();
- });
- _tree->create<uhd::meta_range_t>(dsp_base_path / "rate/range")
- .set_publisher([this]() { return get_input_rates(); });
- _tree->create<double>(dsp_base_path / "freq/value")
- .set_coercer([this, chan](const double value) {
- return this->_tree
- ->access<double>(this->get_arg_path("freq/value", chan))
- .set(value)
- .get();
- })
- .set_publisher([this, chan]() {
- return this->_tree
- ->access<double>(this->get_arg_path("freq/value", chan))
- .get();
- });
- _tree->create<uhd::meta_range_t>(dsp_base_path / "freq/range")
- .set_publisher([this]() { return get_freq_range(); });
- _tree->access<uhd::time_spec_t>("time/cmd")
- .add_coerced_subscriber([this, chan](const uhd::time_spec_t time_spec) {
- this->set_command_time(time_spec, chan);
- });
- if (_tree->exists("tick_rate")) {
- const double tick_rate = _tree->access<double>("tick_rate").get();
- set_command_tick_rate(tick_rate, chan);
- _tree->access<double>("tick_rate")
- .add_coerced_subscriber([this, chan](const double rate) {
- this->set_command_tick_rate(rate, chan);
- });
- }
-
- // Rate 1:1 by default
- sr_write("N", 1, chan);
- sr_write("M", 1, chan);
- sr_write("CONFIG", 1, chan); // Enable clear EOB
- }
- } // end ctor
-
- virtual ~duc_block_ctrl_impl() {}
-
- double get_input_scale_factor(size_t port = ANY_PORT)
- {
- port = (port == ANY_PORT) ? 0 : port;
- if (not(_tx_streamer_active.count(port) and _tx_streamer_active.at(port))) {
- return SCALE_UNDEFINED;
- }
- return get_arg<double>("scalar_correction", port);
- }
-
- double get_input_samp_rate(size_t port = ANY_PORT)
- {
- port = (port == ANY_PORT) ? 0 : port;
-
- // Wait, what? If this seems out of place to you, you're right. However,
- // we need a function call that is called when the graph is complete,
- // but streaming is not yet set up.
- if (_tree->exists("tick_rate")) {
- const double tick_rate = _tree->access<double>("tick_rate").get();
- set_command_tick_rate(tick_rate, port);
- }
-
- if (not(_tx_streamer_active.count(port) and _tx_streamer_active.at(port))) {
- return RATE_UNDEFINED;
- }
- return get_arg<double>("input_rate", port);
- }
-
- double get_output_samp_rate(size_t port = ANY_PORT)
- {
- port = (port == ANY_PORT) ? 0 : port;
- if (not(_tx_streamer_active.count(port) and _tx_streamer_active.at(port))) {
- return RATE_UNDEFINED;
- }
- return get_arg<double>("output_rate", port == ANY_PORT ? 0 : port);
- }
-
- void issue_stream_cmd(const uhd::stream_cmd_t& stream_cmd_, const size_t chan)
- {
- UHD_RFNOC_BLOCK_TRACE() << "duc_block_ctrl_base::issue_stream_cmd()";
-
- uhd::stream_cmd_t stream_cmd = stream_cmd_;
- if (stream_cmd.stream_mode == uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE
- or stream_cmd.stream_mode
- == uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE) {
- size_t interpolation = get_arg<double>("output_rate", chan)
- / get_arg<double>("input_rate", chan);
- stream_cmd.num_samps *= interpolation;
- }
-
- source_block_ctrl_base::issue_stream_cmd(stream_cmd, chan);
- }
-
-private:
- static constexpr size_t MAJOR_COMP = 2;
- static constexpr size_t MINOR_COMP = 0;
- static constexpr size_t RB_REG_COMPAT_NUM = 0;
- static constexpr size_t RB_REG_NUM_HALFBANDS = 1;
- static constexpr size_t RB_REG_CIC_MAX_INTERP = 2;
-
- const uint64_t _fpga_compat;
- const size_t _num_halfbands;
- const size_t _cic_max_interp;
-
- //! Set the DDS frequency shift the signal to \p requested_freq
- double set_freq(const double requested_freq, const size_t chan)
- {
- const double output_rate = get_arg<double>("output_rate");
- double actual_freq;
- int32_t freq_word;
- get_freq_and_freq_word(requested_freq, output_rate, actual_freq, freq_word);
- sr_write("DDS_FREQ", uint32_t(freq_word), chan);
- return actual_freq;
- }
-
- //! Return a range of valid frequencies the DDS can tune to
- uhd::meta_range_t get_freq_range(void)
- {
- const double output_rate = get_arg<double>("output_rate");
- return uhd::meta_range_t(
- -output_rate / 2, +output_rate / 2, output_rate / std::pow(2.0, 32));
- }
-
- uhd::meta_range_t get_input_rates(void)
- {
- uhd::meta_range_t range;
- const double output_rate = get_arg<double>("output_rate");
- for (int hb = _num_halfbands; hb >= 0; hb--) {
- const size_t interp_offset = _cic_max_interp << (hb - 1);
- for (size_t interp = _cic_max_interp; interp > 0; interp--) {
- const size_t hb_cic_interp = interp * (1 << hb);
- if (hb == 0 || hb_cic_interp > interp_offset) {
- range.push_back(uhd::range_t(output_rate / hb_cic_interp));
- }
- }
- }
- return range;
- }
-
- double set_input_rate(const double requested_rate, const size_t chan)
- {
- const double output_rate = get_arg<double>("output_rate", chan);
- const double tick_rate = _tree->exists("tick_rate")
- ? _tree->access<double>("tick_rate").get()
- : output_rate;
- const size_t n = size_t(tick_rate / output_rate);
- const size_t interp_rate = boost::math::iround(
- output_rate / get_input_rates().clip(requested_rate, true));
- size_t interp = interp_rate;
-
- uint32_t hb_enable = 0;
- while ((interp % 2 == 0) and hb_enable < _num_halfbands) {
- hb_enable++;
- interp /= 2;
- }
- UHD_ASSERT_THROW(hb_enable <= _num_halfbands);
- UHD_ASSERT_THROW(interp > 0 and interp <= _cic_max_interp);
- // What we can't cover with halfbands, we do with the CIC
- sr_write("INTERP_WORD", (hb_enable << 8) | (interp & 0xff), chan);
-
- // Rate change = M/N
- sr_write("N", n, chan);
- sr_write("M", n * std::pow(2.0, double(hb_enable)) * (interp & 0xff), chan);
-
- if (interp > 1 and hb_enable == 0) {
- UHD_LOGGER_WARNING("RFNOC")
- << boost::format(
- "The requested interpolation is odd; the user should expect "
- "passband CIC rolloff.\n"
- "Select an even interpolation to ensure that a halfband filter is "
- "enabled.\n"
- "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n")
- % interp_rate % (output_rate / 1e6) % (requested_rate / 1e6);
- }
-
- // Calculate algorithmic gain of CIC for a given interpolation
- // For Ettus CIC R=interp, M=1, N=4. Gain = (R * M) ^ (N - 1)
- const int CIC_N = 4;
- const double rate_pow = std::pow(double(interp & 0xff), CIC_N - 1);
- const double CONSTANT_GAIN = 1.0;
-
- const double scaling_adjustment =
- std::pow(2, uhd::math::ceil_log2(rate_pow)) / (CONSTANT_GAIN * rate_pow);
- update_scalar(scaling_adjustment, chan);
- return output_rate / interp_rate;
- }
-
- //! Set frequency and interpolation again
- void set_output_rate(const double /* rate */, const size_t chan)
- {
- const double desired_freq =
- _tree->access<double>(get_arg_path("freq", chan) / "value").get_desired();
- set_arg<double>("freq", desired_freq, chan);
- const double desired_input_rate =
- _tree->access<double>(get_arg_path("input_rate", chan) / "value")
- .get_desired();
- set_arg<double>("input_rate", desired_input_rate, chan);
- }
-
- // Calculate compensation gain values for algorithmic gain of DDS and CIC taking into
- // account gain compensation blocks already hardcoded in place in DUC (that provide
- // simple 1/2^n gain compensation). Further more factor in OTW format which adds
- // further gain factor to weight output samples correctly.
- void update_scalar(const double scalar, const size_t chan)
- {
- const double target_scalar = (1 << 15) * scalar;
- const int32_t actual_scalar = boost::math::iround(target_scalar);
- // Calculate the error introduced by using integer representation for the scalar
- const double scalar_correction =
- actual_scalar / target_scalar
- * (double(1 << 15) - 1.0) // Rounding error, normalized to 1.0
- * get_arg<double>("fullscale"); // Scaling requested by host
- set_arg<double>("scalar_correction", scalar_correction, chan);
- // Write DUC with scaling correction for CIC and CORDIC that maximizes dynamic
- // range in 32/16/12/8bits.
- sr_write("SCALE_IQ", actual_scalar, chan);
- }
-
- //! Get cached value of FPGA compat number
- uint64_t get_fpga_compat() const
- {
- return _fpga_compat;
- }
-
- // Get cached value of _num_halfbands
- size_t get_num_halfbands() const
- {
- return _num_halfbands;
- }
-
- // Get cached value of _cic_max_decim readback
- size_t get_cic_max_interp() const
- {
- return _cic_max_interp;
- }
-};
-
-UHD_RFNOC_BLOCK_REGISTER(duc_block_ctrl, "DUC");
diff --git a/host/lib/rfnoc/fir_block_ctrl_impl.cpp b/host/lib/rfnoc/fir_block_ctrl_impl.cpp
deleted file mode 100644
index a4106111e..000000000
--- a/host/lib/rfnoc/fir_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// Copyright 2014-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/fir_block_ctrl.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/graph_impl.cpp b/host/lib/rfnoc/graph_impl.cpp
deleted file mode 100644
index 4c04a0c1e..000000000
--- a/host/lib/rfnoc/graph_impl.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-//
-// Copyright 2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
-#include <uhd/rfnoc/source_block_ctrl_base.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/graph_impl.hpp>
-
-using namespace uhd::rfnoc;
-
-/****************************************************************************
- * Structors
- ***************************************************************************/
-graph_impl::graph_impl(const std::string& name,
- boost::weak_ptr<uhd::device3> device_ptr,
- async_msg_handler::sptr msg_handler)
- : _name(name), _device_ptr(device_ptr), _msg_handler(msg_handler)
-{
- UHD_LOG_TRACE("RFNOC", "Instantiating RFNoC graph " << _name);
-}
-
-/****************************************************************************
- * Connection API
- ***************************************************************************/
-void graph_impl::connect(const block_id_t& src_block,
- size_t src_block_port,
- const block_id_t& dst_block,
- size_t dst_block_port,
- const size_t pkt_size_)
-{
- device3::sptr device_ptr = _device_ptr.lock();
- if (not device_ptr) {
- throw uhd::runtime_error("Invalid device");
- }
-
- uhd::rfnoc::source_block_ctrl_base::sptr src =
- device_ptr->get_block_ctrl<rfnoc::source_block_ctrl_base>(src_block);
- uhd::rfnoc::sink_block_ctrl_base::sptr dst =
- device_ptr->get_block_ctrl<rfnoc::sink_block_ctrl_base>(dst_block);
- UHD_LOGGER_TRACE("RFNOC") << "[" << _name << "] Attempting to connect " << src_block
- << ":" << src_block_port << " --> " << dst_block << ":"
- << dst_block_port;
-
- /********************************************************************
- * 1. Draw the edges (logically connect the nodes)
- ********************************************************************/
- size_t actual_src_block_port = src->connect_downstream(
- boost::dynamic_pointer_cast<uhd::rfnoc::node_ctrl_base>(dst), src_block_port);
- if (src_block_port == uhd::rfnoc::ANY_PORT) {
- src_block_port = actual_src_block_port;
- } else if (src_block_port != actual_src_block_port) {
- throw uhd::runtime_error(
- str(boost::format("Can't connect to port %d on block %s.") % src_block_port
- % src->unique_id()));
- }
- size_t actual_dst_block_port = dst->connect_upstream(
- boost::dynamic_pointer_cast<uhd::rfnoc::node_ctrl_base>(src), dst_block_port);
- if (dst_block_port == uhd::rfnoc::ANY_PORT) {
- dst_block_port = actual_dst_block_port;
- } else if (dst_block_port != actual_dst_block_port) {
- throw uhd::runtime_error(
- str(boost::format("Can't connect to port %d on block %s.") % dst_block_port
- % dst->unique_id()));
- }
- src->set_downstream_port(actual_src_block_port, actual_dst_block_port);
- dst->set_upstream_port(actual_dst_block_port, actual_src_block_port);
- // At this point, ports are locked and no one else can simply connect
- // into them.
- UHD_LOGGER_TRACE("RFNOC") << "[" << _name << "] Connecting " << src_block << ":"
- << actual_src_block_port << " --> " << dst_block << ":"
- << actual_dst_block_port;
-
- /********************************************************************
- * 2. Check IO signatures match
- ********************************************************************/
- if (not rfnoc::stream_sig_t::is_compatible(
- src->get_output_signature(actual_src_block_port),
- dst->get_input_signature(actual_dst_block_port))) {
- throw uhd::runtime_error(
- str(boost::format("Can't connect block %s to %s: IO signature mismatch\n(%s "
- "is incompatible with %s).")
- % src->get_block_id().get() % dst->get_block_id().get()
- % src->get_output_signature(actual_src_block_port)
- % dst->get_input_signature(actual_dst_block_port)));
- }
- UHD_LOG_TRACE("RFNOC", "IO signatures match.");
-
- /********************************************************************
- * 3. Configure the source block's destination
- ********************************************************************/
- // Calculate SID
- sid_t sid = dst->get_address(dst_block_port);
- sid.set_src(src->get_address(src_block_port));
-
- // Set SID on source block
- src->set_destination(sid.get(), src_block_port);
-
- /********************************************************************
- * 4. Configure flow control
- ********************************************************************/
- size_t pkt_size = (pkt_size_ != 0)
- ? pkt_size_
- : src->get_output_signature(src_block_port).packet_size;
- if (pkt_size == 0) { // Unspecified packet rate. Assume max packet size.
- UHD_LOGGER_WARNING("RFNOC")
- << "Assuming max packet size for " << src->get_block_id();
- pkt_size = uhd::rfnoc::MAX_PACKET_SIZE;
- }
- // FC window (in bytes) depends on FIFO size.
- size_t buf_size_bytes = dst->get_fifo_size(dst_block_port);
- if (buf_size_bytes < pkt_size) {
- throw uhd::runtime_error(
- str(boost::format("Input FIFO for block %s is too small (%d kiB) for packets "
- "of size %d kiB\n"
- "coming from block %s.")
- % dst->get_block_id().get() % (dst->get_fifo_size(dst_block_port) / 1024)
- % (pkt_size / 1024) % src->get_block_id().get()));
- }
- const bool same_xbar = sid.get_src_addr() == sid.get_dst_addr();
- src->configure_flow_control_out(true, /* enable output */
- false, // Keep packets from jamming the crossbar
- buf_size_bytes,
- 0, /* no packet limit. We need to revisit this at some point. */
- src_block_port);
- // On the same crossbar, use lots of FC packets
- // Over the network, use less or we'd flood the transport
- const size_t bytes_per_response =
- same_xbar ? buf_size_bytes / uhd::rfnoc::DEFAULT_FC_XBAR_RESPONSE_FREQ
- : buf_size_bytes / uhd::rfnoc::DEFAULT_FC_TX_RESPONSE_FREQ;
- UHD_ASSERT_THROW(bytes_per_response != 0);
- dst->configure_flow_control_in(bytes_per_response, dst_block_port);
-
- /********************************************************************
- * 5. Configure error policy
- ********************************************************************/
- dst->set_error_policy("next_burst");
-
- /********************************************************************
- * 6. Set async message handling
- ********************************************************************/
- src->sr_write(
- uhd::rfnoc::SR_RESP_OUT_DST_SID, _msg_handler->get_local_addr(), src_block_port);
- dst->sr_write(
- uhd::rfnoc::SR_RESP_IN_DST_SID, _msg_handler->get_local_addr(), dst_block_port);
-}
-
-void graph_impl::connect(const block_id_t& src_block, const block_id_t& dst_block)
-{
- connect(src_block, ANY_PORT, dst_block, ANY_PORT);
-}
-
-void graph_impl::connect_src(const block_id_t& src_block,
- const size_t src_block_port,
- const uhd::sid_t dst_sid,
- const size_t buf_size_dst_bytes,
- const size_t pkt_size_)
-{
- device3::sptr device_ptr = _device_ptr.lock();
- if (not device_ptr) {
- throw uhd::runtime_error("Invalid device");
- }
-
- UHD_LOGGER_DEBUG("RFNOC") << "[" << _name << "] Connecting " << src_block << ":"
- << src_block_port << " --> " << dst_sid.to_pp_string_hex();
-
- uhd::rfnoc::source_block_ctrl_base::sptr src =
- device_ptr->get_block_ctrl<rfnoc::source_block_ctrl_base>(src_block);
-
- src->set_destination(dst_sid.get(), src_block_port);
-
- size_t pkt_size = (pkt_size_ != 0)
- ? pkt_size_
- : src->get_output_signature(src_block_port).packet_size;
- if (pkt_size == 0) { // Unspecified packet rate. Assume max packet size.
- UHD_LOGGER_WARNING("RFNOC")
- << "Assuming max packet size for " << src->get_block_id();
- pkt_size = uhd::rfnoc::MAX_PACKET_SIZE;
- }
- size_t buf_size_pkts = buf_size_dst_bytes / pkt_size;
- if (buf_size_pkts == 0) {
- throw uhd::runtime_error(
- str(boost::format("Input FIFO for unknown destination is too small "
- "(%d kiB) for packets of size %d kiB\n coming from "
- "block %s.")
- % (buf_size_dst_bytes / 1024) % (pkt_size / 1024)
- % src->get_block_id().get()));
- }
-
- src->configure_flow_control_out(true, /* enable output */
- (dst_sid.get_src_addr() == dst_sid.get_dst_addr()),
- buf_size_dst_bytes,
- 0, /* no packet limit. We need to revisit this at some point. */
- src_block_port);
-}
-
-void graph_impl::connect_sink(
- const block_id_t& sink_block, const size_t dst_block_port, const size_t bytes_per_ack)
-{
- device3::sptr device_ptr = _device_ptr.lock();
- if (not device_ptr) {
- throw uhd::runtime_error("Invalid device");
- }
-
- UHD_LOGGER_DEBUG("RFNOC") << "[" << _name << "] Connecting unknown source to"
- << sink_block << ":" << dst_block_port;
-
- uhd::rfnoc::sink_block_ctrl_base::sptr dst =
- device_ptr->get_block_ctrl<rfnoc::sink_block_ctrl_base>(sink_block);
- dst->configure_flow_control_in(bytes_per_ack, dst_block_port);
-
- /********************************************************************
- * 5. Configure error policy
- ********************************************************************/
- dst->set_error_policy("next_burst");
-}
diff --git a/host/lib/rfnoc/legacy_compat.cpp b/host/lib/rfnoc/legacy_compat.cpp
deleted file mode 100644
index 91de361df..000000000
--- a/host/lib/rfnoc/legacy_compat.cpp
+++ /dev/null
@@ -1,1179 +0,0 @@
-//
-// Copyright 2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "../usrp/device3/device3_impl.hpp"
-#include <uhd/property_tree.hpp>
-#include <uhd/rfnoc/ddc_block_ctrl.hpp>
-#include <uhd/rfnoc/graph.hpp>
-#include <uhd/rfnoc/radio_ctrl.hpp>
-#include <uhd/stream.hpp>
-#include <uhd/transport/chdr.hpp>
-#include <uhd/types/direction.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/types/stream_cmd.hpp>
-#include <uhd/usrp/multi_usrp.hpp>
-#include <uhd/usrp/subdev_spec.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/legacy_compat.hpp>
-#include <boost/make_shared.hpp>
-#include <set>
-
-#define UHD_LEGACY_LOG() UHD_LOGGER_TRACE("RFNOC")
-
-using namespace uhd::rfnoc;
-using uhd::stream_cmd_t;
-using uhd::usrp::subdev_spec_pair_t;
-using uhd::usrp::subdev_spec_t;
-
-/************************************************************************
- * Constants and globals
- ***********************************************************************/
-static const std::string RADIO_BLOCK_NAME = "Radio";
-static const std::string DFIFO_BLOCK_NAME = "DmaFIFO";
-static const std::string SFIFO_BLOCK_NAME = "FIFO";
-static const std::string DDC_BLOCK_NAME = "DDC";
-static const std::string DUC_BLOCK_NAME = "DUC";
-static const size_t MAX_BYTES_PER_HEADER =
- uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t);
-static const size_t BYTES_PER_SAMPLE = 4; // We currently only support sc16
-static boost::mutex _make_mutex;
-static const std::vector<std::string> LEGACY_BLOCKS_LIST = {
- RADIO_BLOCK_NAME, DFIFO_BLOCK_NAME, SFIFO_BLOCK_NAME, DDC_BLOCK_NAME, DUC_BLOCK_NAME};
-typedef std::vector<source_block_ctrl_base::sptr> source_block_list_t;
-typedef std::vector<sink_block_ctrl_base::sptr> sink_block_list_t;
-typedef std::map<std::string, std::pair<source_block_list_t, sink_block_list_t>>
- block_name_to_block_map_t;
-typedef std::pair<source_block_ctrl_base::sptr, size_t> source_port_t;
-typedef std::pair<sink_block_ctrl_base::sptr, size_t> sink_port_t;
-/************************************************************************
- * Static helpers
- ***********************************************************************/
-static uhd::fs_path mb_root(const size_t mboard)
-{
- return uhd::fs_path("/mboards") / mboard;
-}
-
-size_t num_ports(const uhd::property_tree::sptr& tree,
- const std::string& block_name,
- const std::string& in_out)
-{
- return tree
- ->list(uhd::fs_path("/mboards/0/xbar") / str(boost::format("%s_0") % block_name)
- / "ports" / in_out)
- .size();
-}
-
-size_t calc_num_tx_chans_per_radio(const uhd::property_tree::sptr& tree,
- const size_t num_radios_per_board,
- const bool has_ducs,
- const bool has_dmafifo)
-{
- const size_t num_radio_ports = num_ports(tree, RADIO_BLOCK_NAME, "in");
- if (has_ducs) {
- return std::min(num_radio_ports, num_ports(tree, DUC_BLOCK_NAME, "in"));
- }
-
- if (not has_dmafifo) {
- return num_radio_ports;
- }
-
- const size_t num_dmafifo_ports_per_radio =
- num_ports(tree, DFIFO_BLOCK_NAME, "in") / num_radios_per_board;
- UHD_ASSERT_THROW(num_dmafifo_ports_per_radio);
-
- return std::min(num_radio_ports, num_dmafifo_ports_per_radio);
-}
-
-/*! Recreate passed property without bound subscribers. Maintains current property value.
- */
-template <typename T>
-static void recreate_property(const uhd::fs_path& path, uhd::property_tree::sptr& tree)
-{
- T temp = tree->access<T>(path).get();
- tree->remove(path);
- tree->create<T>(path).set(temp);
-}
-
-/************************************************************************
- * Class Definition
- ***********************************************************************/
-class legacy_compat_impl : public legacy_compat
-{
-public:
- /************************************************************************
- * Structors and Initialization
- ***********************************************************************/
- legacy_compat_impl(uhd::device3::sptr device, const uhd::device_addr_t& args)
- : _device(device)
- , _tree(device->get_tree())
- , _has_ducs(not args.has_key("skip_duc")
- and not device->find_blocks(DUC_BLOCK_NAME).empty())
- , _has_ddcs(not args.has_key("skip_ddc")
- and not device->find_blocks(DDC_BLOCK_NAME).empty())
- , _has_dmafifo(not args.has_key("skip_dram")
- and not device->find_blocks(DFIFO_BLOCK_NAME).empty())
- , _has_sramfifo(not args.has_key("skip_sram")
- and not device->find_blocks(SFIFO_BLOCK_NAME).empty())
- , _num_mboards(_tree->list("/mboards").size())
- , _num_radios_per_board(device->find_blocks<radio_ctrl>("0/Radio").size())
- , // These might throw, maybe we catch that and provide a nicer error message.
- _num_tx_chans_per_radio(calc_num_tx_chans_per_radio(
- _tree, _num_radios_per_board, _has_ducs, _has_dmafifo))
- , _num_rx_chans_per_radio(
- _has_ddcs ? std::min(num_ports(_tree, RADIO_BLOCK_NAME, "out"),
- num_ports(_tree, DDC_BLOCK_NAME, "out"))
- : num_ports(_tree, RADIO_BLOCK_NAME, "out"))
- , _rx_spp(get_block_ctrl<radio_ctrl>(0, RADIO_BLOCK_NAME, 0)->get_arg<int>("spp"))
- , _tx_spp(_rx_spp)
- , _rx_channel_map(_num_mboards, std::vector<radio_port_pair_t>())
- , _tx_channel_map(_num_mboards, std::vector<radio_port_pair_t>())
- {
- _device->clear();
- check_available_periphs(); // Throws if invalid configuration.
- setup_prop_tree();
- if (_tree->exists("/mboards/0/mtu/send")) {
- _tx_spp = (_tree->access<size_t>("/mboards/0/mtu/send").get()
- - MAX_BYTES_PER_HEADER)
- / BYTES_PER_SAMPLE;
- }
- connect_blocks();
- if (args.has_key("skip_ddc")) {
- UHD_LEGACY_LOG() << "[legacy_compat] Skipping DDCs by user request.";
- } else if (not _has_ddcs) {
- UHD_LOGGER_WARNING("RFNOC")
- << "[legacy_compat] No DDCs detected. You will only be able to receive "
- "at the radio frontend rate.";
- }
- if (args.has_key("skip_duc")) {
- UHD_LEGACY_LOG() << "[legacy_compat] Skipping DUCs by user request.";
- } else if (not _has_ducs) {
- UHD_LOGGER_WARNING("RFNOC")
- << "[legacy_compat] No DUCs detected. You will only be able to transmit "
- "at the radio frontend rate.";
- }
- if (args.has_key("skip_dram")) {
- UHD_LEGACY_LOG() << "[legacy_compat] Skipping DRAM by user request.";
- }
- if (args.has_key("skip_sram")) {
- UHD_LEGACY_LOG() << "[legacy_compat] Skipping SRAM by user request.";
- }
- if (not _has_dmafifo and not _has_sramfifo) {
- UHD_LOGGER_WARNING("RFNOC") << "[legacy_compat] No FIFO detected. Higher "
- "transmit rates may encounter errors.";
- }
- for (size_t mboard = 0; mboard < _num_mboards; mboard++) {
- for (size_t radio = 0; radio < _num_radios_per_board; radio++) {
- auto radio_block_ctrl =
- get_block_ctrl<radio_ctrl>(mboard, "Radio", radio);
- for (size_t port = 0; port < _num_rx_chans_per_radio; port++) {
- if (!radio_block_ctrl->get_dboard_fe_from_chan(
- port, uhd::RX_DIRECTION)
- .empty()) {
- _rx_channel_map[mboard].push_back({radio, port});
- }
- }
- for (size_t port = 0; port < _num_tx_chans_per_radio; port++) {
- if (!radio_block_ctrl->get_dboard_fe_from_chan(
- port, uhd::TX_DIRECTION)
- .empty()) {
- _tx_channel_map[mboard].push_back({radio, port});
- }
- }
- }
-
- update_sample_rate_on_blocks(mboard);
- }
- }
-
- ~legacy_compat_impl()
- {
- remove_prop_subscribers();
- }
-
- /************************************************************************
- * API Calls
- ***********************************************************************/
- inline uhd::fs_path rx_dsp_root(
- const size_t mboard_idx, const size_t dsp_index, const size_t port_index)
- {
- return mb_root(mboard_idx) / "xbar"
- / str(boost::format("%s_%d") % DDC_BLOCK_NAME % dsp_index) / "legacy_api"
- / port_index;
- }
-
- uhd::fs_path rx_dsp_root(const size_t mboard_idx, const size_t chan)
- {
- // The DSP index is the same as the radio index
- size_t dsp_index = _rx_channel_map[mboard_idx][chan].radio_index;
- size_t port_index = _rx_channel_map[mboard_idx][chan].port_index;
-
- if (not _has_ddcs) {
- return mb_root(mboard_idx) / "rx_dsps" / dsp_index / port_index;
- }
-
- return rx_dsp_root(mboard_idx, dsp_index, port_index);
- }
-
- inline uhd::fs_path tx_dsp_root(
- const size_t mboard_idx, const size_t dsp_index, const size_t port_index)
- {
- return mb_root(mboard_idx) / "xbar"
- / str(boost::format("%s_%d") % DUC_BLOCK_NAME % dsp_index) / "legacy_api"
- / port_index;
- }
-
- uhd::fs_path tx_dsp_root(const size_t mboard_idx, const size_t chan)
- {
- // The DSP index is the same as the radio index
- size_t dsp_index = _tx_channel_map[mboard_idx][chan].radio_index;
- size_t port_index = _tx_channel_map[mboard_idx][chan].port_index;
-
- if (not _has_ducs) {
- return mb_root(mboard_idx) / "tx_dsps" / dsp_index / port_index;
- }
-
- return tx_dsp_root(mboard_idx, dsp_index, port_index);
- }
-
- uhd::fs_path rx_fe_root(const size_t mboard_idx, const size_t chan)
- {
- size_t radio_index = _rx_channel_map[mboard_idx][chan].radio_index;
- size_t port_index = _rx_channel_map[mboard_idx][chan].port_index;
- return uhd::fs_path(
- str(boost::format("/mboards/%d/xbar/%s_%d/rx_fe_corrections/%d/") % mboard_idx
- % RADIO_BLOCK_NAME % radio_index % port_index));
- }
-
- uhd::fs_path tx_fe_root(const size_t mboard_idx, const size_t chan)
- {
- size_t radio_index = _tx_channel_map[mboard_idx][chan].radio_index;
- size_t port_index = _tx_channel_map[mboard_idx][chan].port_index;
- return uhd::fs_path(
- str(boost::format("/mboards/%d/xbar/%s_%d/tx_fe_corrections/%d/") % mboard_idx
- % RADIO_BLOCK_NAME % radio_index % port_index));
- }
- //! Get all legacy blocks from the LEGACY_BLOCK_LIST return in a form of
- // {BLOCK_NAME: <{source_block_pointer},{sink_block_pointer}>}
- block_name_to_block_map_t get_legacy_blocks(uhd::device3::sptr _device)
- {
- block_name_to_block_map_t result;
- for (auto each_block_name : LEGACY_BLOCKS_LIST) {
- std::vector<block_id_t> block_list = _device->find_blocks(each_block_name);
- std::pair<source_block_list_t, sink_block_list_t> ss_pair;
- source_block_list_t src_list;
- sink_block_list_t snk_list;
- for (auto each_block : block_list) {
- uhd::rfnoc::source_block_ctrl_base::sptr src =
- _device->get_block_ctrl<source_block_ctrl_base>(each_block);
- src_list.push_back(src);
- uhd::rfnoc::sink_block_ctrl_base::sptr snk =
- _device->get_block_ctrl<sink_block_ctrl_base>(each_block);
- snk_list.push_back(snk);
- }
- ss_pair = std::make_pair(src_list, snk_list);
- result[each_block_name] = ss_pair;
- }
- return result;
- }
-
- void issue_stream_cmd(const stream_cmd_t& stream_cmd, size_t mboard, size_t chan)
- {
- UHD_LEGACY_LOG() << "[legacy_compat] issue_stream_cmd() ";
- const size_t& radio_index = _rx_channel_map[mboard][chan].radio_index;
- const size_t& port_index = _rx_channel_map[mboard][chan].port_index;
- if (_has_ddcs) {
- get_block_ctrl<ddc_block_ctrl>(mboard, DDC_BLOCK_NAME, radio_index)
- ->issue_stream_cmd(stream_cmd, port_index);
- } else {
- get_block_ctrl<radio_ctrl>(mboard, RADIO_BLOCK_NAME, radio_index)
- ->issue_stream_cmd(stream_cmd, port_index);
- }
- }
-
- //! Sets block_id<N> and block_port<N> in the streamer args, otherwise forwards the
- //! call
- uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t& args_)
- {
- uhd::stream_args_t args(args_);
- if (args.otw_format.empty()) {
- args.otw_format = "sc16";
- }
- _update_stream_args_for_streaming<uhd::RX_DIRECTION>(args, _rx_channel_map);
- UHD_LEGACY_LOG() << "[legacy_compat] rx stream args: " << args.args.to_string();
- uhd::rx_streamer::sptr streamer = _device->get_rx_stream(args);
- for (const size_t chan : args.channels) {
- _rx_stream_cache[chan] = streamer;
- }
- return streamer;
- }
-
- //! Sets block_id<N> and block_port<N> in the streamer args, otherwise forwards the
- //! call.
- // If spp is in the args, update the radios. If it's not set, copy the value from the
- // radios.
- uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t& args_)
- {
- uhd::stream_args_t args(args_);
- if (args.otw_format.empty()) {
- args.otw_format = "sc16";
- }
- _update_stream_args_for_streaming<uhd::TX_DIRECTION>(args, _tx_channel_map);
- UHD_LEGACY_LOG() << "[legacy_compat] tx stream args: " << args.args.to_string();
- uhd::tx_streamer::sptr streamer = _device->get_tx_stream(args);
- for (const size_t chan : args.channels) {
- _tx_stream_cache[chan] = streamer;
- }
- return streamer;
- }
-
- double get_tick_rate(const size_t mboard_idx = 0)
- {
- return _tree->access<double>(mb_root(mboard_idx) / "tick_rate").get();
- }
-
- uhd::meta_range_t lambda_get_samp_rate_range(const size_t mboard_idx,
- const size_t radio_idx,
- const size_t chan,
- uhd::direction_t dir)
- {
- radio_ctrl::sptr radio_sptr =
- get_block_ctrl<radio_ctrl>(mboard_idx, RADIO_BLOCK_NAME, radio_idx);
- const double samp_rate = (dir == uhd::TX_DIRECTION)
- ? radio_sptr->get_input_samp_rate(chan)
- : radio_sptr->get_output_samp_rate(chan);
-
- return uhd::meta_range_t(samp_rate, samp_rate, 0.0);
- }
-
- void set_tick_rate(const double tick_rate, const size_t mboard_idx = 0)
- {
- _tree->access<double>(mb_root(mboard_idx) / "tick_rate").set(tick_rate);
- for (size_t radio = 0; radio < _num_radios_per_board; radio++) {
- auto radio_block_ctrl =
- get_block_ctrl<radio_ctrl>(mboard_idx, "Radio", radio);
- radio_block_ctrl->set_rate(tick_rate);
- }
- update_sample_rate_on_blocks(mboard_idx);
- }
-
- void set_rx_rate(const double rate, const size_t chan)
- {
- if (not _has_ddcs) {
- return;
- }
-
- // Set DDC values:
- if (chan == uhd::usrp::multi_usrp::ALL_CHANS) {
- for (size_t mboard_idx = 0; mboard_idx < _rx_channel_map.size();
- mboard_idx++) {
- for (size_t chan_idx = 0; chan_idx < _rx_channel_map[mboard_idx].size();
- chan_idx++) {
- const size_t dsp_index =
- _rx_channel_map[mboard_idx][chan_idx].radio_index;
- const size_t port_index =
- _rx_channel_map[mboard_idx][chan_idx].port_index;
- _tree
- ->access<double>(
- rx_dsp_root(mboard_idx, dsp_index, port_index) / "rate/value")
- .set(rate);
- }
- }
- } else {
- std::set<size_t> chans_to_change{chan};
- if (_rx_stream_cache.count(chan)) {
- uhd::rx_streamer::sptr str_ptr = _rx_stream_cache[chan].lock();
- if (str_ptr) {
- for (const rx_stream_map_type::value_type& chan_streamer_pair :
- _rx_stream_cache) {
- if (chan_streamer_pair.second.lock() == str_ptr) {
- chans_to_change.insert(chan_streamer_pair.first);
- }
- }
- }
- }
- for (const size_t this_chan : chans_to_change) {
- size_t mboard, mb_chan;
- chan_to_mcp<uhd::RX_DIRECTION>(
- this_chan, _rx_channel_map, mboard, mb_chan);
- const size_t dsp_index = _rx_channel_map[mboard][mb_chan].radio_index;
- const size_t port_index = _rx_channel_map[mboard][mb_chan].port_index;
- _tree
- ->access<double>(
- rx_dsp_root(mboard, dsp_index, port_index) / "rate/value")
- .set(rate);
- }
- }
- }
-
- void set_tx_rate(const double rate, const size_t chan)
- {
- if (not _has_ducs) {
- return;
- }
-
- // Set DUC values:
- if (chan == uhd::usrp::multi_usrp::ALL_CHANS) {
- for (size_t mboard_idx = 0; mboard_idx < _tx_channel_map.size();
- mboard_idx++) {
- for (size_t chan_idx = 0; chan_idx < _tx_channel_map[mboard_idx].size();
- chan_idx++) {
- const size_t dsp_index =
- _tx_channel_map[mboard_idx][chan_idx].radio_index;
- const size_t port_index =
- _tx_channel_map[mboard_idx][chan_idx].port_index;
- _tree
- ->access<double>(
- tx_dsp_root(mboard_idx, dsp_index, port_index) / "rate/value")
- .set(rate);
- }
- }
- } else {
- std::set<size_t> chans_to_change{chan};
- if (_tx_stream_cache.count(chan)) {
- uhd::tx_streamer::sptr str_ptr = _tx_stream_cache[chan].lock();
- if (str_ptr) {
- for (const tx_stream_map_type::value_type& chan_streamer_pair :
- _tx_stream_cache) {
- if (chan_streamer_pair.second.lock() == str_ptr) {
- chans_to_change.insert(chan_streamer_pair.first);
- }
- }
- }
- }
- for (const size_t this_chan : chans_to_change) {
- size_t mboard, mb_chan;
- chan_to_mcp<uhd::TX_DIRECTION>(
- this_chan, _tx_channel_map, mboard, mb_chan);
- const size_t dsp_index = _tx_channel_map[mboard][mb_chan].radio_index;
- const size_t port_index = _tx_channel_map[mboard][mb_chan].port_index;
- _tree
- ->access<double>(
- tx_dsp_root(mboard, dsp_index, port_index) / "rate/value")
- .set(rate);
- }
- }
- }
-
-private: // types
- struct radio_port_pair_t
- {
- radio_port_pair_t(const size_t radio = 0, const size_t port = 0)
- : radio_index(radio), port_index(port)
- {
- }
- size_t radio_index;
- size_t port_index;
- };
- //! Map: _rx_channel_map[mboard_idx][chan_idx] => (Radio, Port)
- // Container is not a std::map because we need to guarantee contiguous
- // ports and correct order anyway.
- typedef std::vector<std::vector<radio_port_pair_t>> chan_map_t;
-
-private: // methods
- /************************************************************************
- * Private helpers
- ***********************************************************************/
- std::string get_slot_name(const size_t radio_index)
- {
- if (radio_index == 0) {
- return "A";
- } else if (radio_index == 1) {
- return "B";
- } else if (radio_index == 2) {
- return "C";
- } else if (radio_index == 3) {
- return "D";
- } else {
- throw uhd::index_error(str(
- boost::format("[legacy_compat]: radio index %u out of supported range.")
- % radio_index));
- }
- }
-
- size_t get_radio_index(const std::string slot_name)
- {
- if (slot_name == "A") {
- return 0;
- } else if (slot_name == "B") {
- return 1;
- } else if (slot_name == "C") {
- return 2;
- } else if (slot_name == "D") {
- return 3;
- } else {
- throw uhd::key_error(
- str(boost::format(
- "[legacy_compat]: radio slot name %s out of supported range.")
- % slot_name));
- }
- }
-
- template <typename block_type>
- inline typename block_type::sptr get_block_ctrl(
- const size_t mboard_idx, const std::string& name, const size_t block_count)
- {
- block_id_t block_id(mboard_idx, name, block_count);
- return _device->get_block_ctrl<block_type>(block_id);
- }
-
- template <uhd::direction_t dir>
- inline void chan_to_mcp(const size_t chan,
- const chan_map_t& chan_map,
- size_t& mboard_idx,
- size_t& mb_chan_idx)
- {
- mboard_idx = 0;
- mb_chan_idx = chan;
- while (mb_chan_idx >= chan_map[mboard_idx].size()) {
- mb_chan_idx -= chan_map[mboard_idx++].size();
- }
- if (mboard_idx >= chan_map.size()) {
- throw uhd::index_error(
- str(boost::format("[legacy_compat]: %s channel %u out of range for given "
- "frontend configuration.")
- % (dir == uhd::TX_DIRECTION ? "TX" : "RX") % chan));
- }
- }
-
- template <uhd::direction_t dir>
- void _update_stream_args_for_streaming(
- uhd::stream_args_t& args, const chan_map_t& chan_map)
- {
- // If the user provides spp, that value is always applied. If it's
- // different from what we thought it was, we need to update the blocks.
- // If it's not provided, we provide our own spp value.
- const size_t args_spp = args.args.cast<size_t>("spp", 0);
- if (dir == uhd::RX_DIRECTION) {
- size_t target_spp = _rx_spp;
- if (args.args.has_key("spp") and args_spp != _rx_spp) {
- target_spp = args_spp;
- // TODO: Update flow control on the blocks
- } else {
- for (size_t mboard = 0; mboard < _num_mboards; mboard++) {
- for (size_t radio = 0; radio < _num_radios_per_board; radio++) {
- const size_t this_spp =
- get_block_ctrl<radio_ctrl>(mboard, RADIO_BLOCK_NAME, radio)
- ->get_arg<int>("spp");
- target_spp = std::min(this_spp, target_spp);
- }
- }
- }
- for (size_t mboard = 0; mboard < _num_mboards; mboard++) {
- for (size_t radio = 0; radio < _num_radios_per_board; radio++) {
- get_block_ctrl<radio_ctrl>(mboard, RADIO_BLOCK_NAME, radio)
- ->set_arg<int>("spp", target_spp);
- }
- }
- _rx_spp = target_spp;
- args.args["spp"] = str(boost::format("%d") % _rx_spp);
- } else {
- if (args.args.has_key("spp") and args_spp != _tx_spp) {
- _tx_spp = args_spp;
- // TODO: Update flow control on the blocks
- } else {
- args.args["spp"] = str(boost::format("%d") % _tx_spp);
- }
- }
-
- if (args.channels.empty()) {
- args.channels = std::vector<size_t>(1, 0);
- }
- for (size_t i = 0; i < args.channels.size(); i++) {
- const size_t stream_arg_chan_idx = args.channels[i];
- // Determine which mboard, and on that mboard, which channel this is:
- size_t mboard_idx, this_mboard_chan_idx;
- chan_to_mcp<dir>(
- stream_arg_chan_idx, chan_map, mboard_idx, this_mboard_chan_idx);
- // Map that mboard and channel to a block:
- const size_t radio_index =
- chan_map[mboard_idx][this_mboard_chan_idx].radio_index;
- size_t port_index = chan_map[mboard_idx][this_mboard_chan_idx].port_index;
- auto block_and_port =
- _get_streamer_block_id_and_port<dir>(mboard_idx, radio_index, port_index);
- auto block_name = block_and_port.first.to_string();
- port_index = block_and_port.second;
- args.args[str(boost::format("block_id%d") % stream_arg_chan_idx)] =
- block_name;
- args.args[str(boost::format("block_port%d") % stream_arg_chan_idx)] =
- str(boost::format("%d") % port_index);
- // Map radio to channel (for in-band response)
- args.args[str(boost::format("radio_id%d") % stream_arg_chan_idx)] =
- block_id_t(mboard_idx, RADIO_BLOCK_NAME, radio_index).to_string();
- args.args[str(boost::format("radio_port%d") % stream_arg_chan_idx)] =
- str(boost::format("%d")
- % chan_map[mboard_idx][this_mboard_chan_idx].port_index);
- }
- }
-
- //! Given mboard_index(m), radio_index(r), and port_index(p),
- // this function returns the index of a block on the input block list that match
- // m,r,p
- template <typename T>
- size_t find_block(const std::vector<T>& port_list,
- const size_t& m,
- const size_t& r,
- const size_t& p)
- {
- size_t index = 0;
- for (auto port : port_list) {
- auto block_id = (port.first)->get_block_id();
- if (p == port.second && r == block_id.get_block_count()
- && m == block_id.get_device_no()) {
- return index;
- }
- index++;
- }
- throw uhd::runtime_error(
- (boost::format(
- "Could not find block in list for device %d, radio %d, and port %d")
- % m % r % p)
- .str());
- }
-
- template <uhd::direction_t dir>
- std::pair<block_id_t, size_t> _get_streamer_block_id_and_port(
- const size_t& mboard_idx, const size_t& radio_index, const size_t& port_index)
- {
- block_name_to_block_map_t legacy_block_map = get_legacy_blocks(_device);
- if (dir == uhd::TX_DIRECTION) {
- auto radio_snk_flat =
- _flatten_blocks_by_n_ports(legacy_block_map[RADIO_BLOCK_NAME].second);
- size_t index_snk = find_block<sink_port_t>(
- radio_snk_flat, mboard_idx, radio_index, port_index);
- if (_has_sramfifo) {
- auto sfifo_snk_flat =
- _flatten_blocks_by_n_ports(legacy_block_map[SFIFO_BLOCK_NAME].second);
- UHD_ASSERT_THROW(index_snk < sfifo_snk_flat.size());
- auto sfifo_block = sfifo_snk_flat[index_snk].first->get_block_id();
- return std::make_pair(sfifo_block, sfifo_snk_flat[index_snk].second);
- } else if (_has_dmafifo) {
- auto dfifo_snk_flat =
- _flatten_blocks_by_n_ports(legacy_block_map[DFIFO_BLOCK_NAME].second);
- UHD_ASSERT_THROW(index_snk < dfifo_snk_flat.size());
- auto dfifo_block = dfifo_snk_flat[index_snk].first->get_block_id();
- return std::make_pair(dfifo_block, dfifo_snk_flat[index_snk].second);
- } else {
- if (_has_ducs) {
- return std::make_pair(
- block_id_t(mboard_idx, DUC_BLOCK_NAME, radio_index).to_string(),
- port_index);
- auto duc_snk_flat = _flatten_blocks_by_n_ports(
- legacy_block_map[DUC_BLOCK_NAME].second);
- UHD_ASSERT_THROW(index_snk < duc_snk_flat.size());
- auto duc_block = duc_snk_flat[index_snk].first->get_block_id();
- return std::make_pair(duc_block, duc_snk_flat[index_snk].second);
- } else {
- return std::make_pair(
- block_id_t(mboard_idx, RADIO_BLOCK_NAME, radio_index).to_string(),
- port_index);
- }
- }
- } else {
- auto radio_src_flat =
- _flatten_blocks_by_n_ports(legacy_block_map[RADIO_BLOCK_NAME].first);
- size_t index_src = find_block<source_port_t>(
- radio_src_flat, mboard_idx, radio_index, port_index);
- if (_has_ddcs) {
- auto ddc_src_flat =
- _flatten_blocks_by_n_ports(legacy_block_map[DDC_BLOCK_NAME].first);
- UHD_ASSERT_THROW(index_src < ddc_src_flat.size());
- auto ddc_block = ddc_src_flat[index_src].first->get_block_id();
- return std::make_pair(ddc_block, ddc_src_flat[index_src].second);
- } else {
- return std::make_pair(
- block_id_t(mboard_idx, RADIO_BLOCK_NAME, radio_index).to_string(),
- port_index);
- }
- }
- }
- /************************************************************************
- * Initialization
- ***********************************************************************/
- /*! Check this device has all the required peripherals.
- *
- * Check rules:
- * - Every mboard needs the same number of radios.
- * - For every radio block, there must be DDC and a DUC block,
- * with matching number of ports.
- *
- * \throw uhd::runtime_error if any of these checks fail.
- */
- void check_available_periphs()
- {
- if (_num_radios_per_board == 0) {
- throw uhd::runtime_error(
- "For legacy APIs, all devices require at least one radio.");
- }
- block_id_t radio_block_id(0, RADIO_BLOCK_NAME);
- block_id_t duc_block_id(0, DUC_BLOCK_NAME);
- block_id_t ddc_block_id(0, DDC_BLOCK_NAME);
- block_id_t fifo_block_id(0, DFIFO_BLOCK_NAME, 0);
- for (size_t i = 0; i < _num_mboards; i++) {
- radio_block_id.set_device_no(i);
- duc_block_id.set_device_no(i);
- ddc_block_id.set_device_no(i);
- fifo_block_id.set_device_no(i);
- for (size_t k = 0; k < _num_radios_per_board; k++) {
- radio_block_id.set_block_count(k);
- duc_block_id.set_block_count(k);
- ddc_block_id.set_block_count(k);
- // Only one FIFO per crossbar, so don't set block count for that block
- if (not _device->has_block(radio_block_id)
- or (_has_ducs and not _device->has_block(duc_block_id))
- or (_has_ddcs and not _device->has_block(ddc_block_id))
- or (_has_dmafifo and not _device->has_block(fifo_block_id))) {
- throw uhd::runtime_error("For legacy APIs, all devices require the "
- "same number of radios, DDCs and DUCs.");
- }
-
- const size_t this_spp = get_block_ctrl<radio_ctrl>(i, RADIO_BLOCK_NAME, k)
- ->get_arg<int>("spp");
- if (this_spp != _rx_spp) {
- UHD_LOGGER_WARNING("RFNOC") << str(
- boost::format(
- "[legacy compat] Radios have differing spp values: %s has "
- "%d, others have %d. UHD will use smaller spp value for all "
- "connections. Performance might be not optimal.")
- % radio_block_id.to_string() % this_spp % _rx_spp);
- }
- }
- }
- }
-
- /*! Initialize properties in property tree to match legacy mode
- */
- void setup_prop_tree()
- {
- for (size_t mboard_idx = 0; mboard_idx < _num_mboards; mboard_idx++) {
- uhd::fs_path root = mb_root(mboard_idx);
- // Subdev specs
- if (_tree->exists(root / "tx_subdev_spec")) {
- _tree->access<subdev_spec_t>(root / "tx_subdev_spec")
- .add_coerced_subscriber(
- boost::bind(&legacy_compat_impl::set_subdev_spec,
- this,
- _1,
- mboard_idx,
- uhd::TX_DIRECTION))
- .update()
- .set_publisher(boost::bind(&legacy_compat_impl::get_subdev_spec,
- this,
- mboard_idx,
- uhd::TX_DIRECTION));
- } else {
- _tree->create<subdev_spec_t>(root / "tx_subdev_spec")
- .add_coerced_subscriber(
- boost::bind(&legacy_compat_impl::set_subdev_spec,
- this,
- _1,
- mboard_idx,
- uhd::TX_DIRECTION))
- .set_publisher(boost::bind(&legacy_compat_impl::get_subdev_spec,
- this,
- mboard_idx,
- uhd::TX_DIRECTION));
- }
-
- if (_tree->exists(root / "rx_subdev_spec")) {
- _tree->access<subdev_spec_t>(root / "rx_subdev_spec")
- .add_coerced_subscriber(
- boost::bind(&legacy_compat_impl::set_subdev_spec,
- this,
- _1,
- mboard_idx,
- uhd::RX_DIRECTION))
- .update()
- .set_publisher(boost::bind(&legacy_compat_impl::get_subdev_spec,
- this,
- mboard_idx,
- uhd::RX_DIRECTION));
- } else {
- _tree->create<subdev_spec_t>(root / "rx_subdev_spec")
- .add_coerced_subscriber(
- boost::bind(&legacy_compat_impl::set_subdev_spec,
- this,
- _1,
- mboard_idx,
- uhd::RX_DIRECTION))
- .set_publisher(boost::bind(&legacy_compat_impl::get_subdev_spec,
- this,
- mboard_idx,
- uhd::RX_DIRECTION));
- }
-
- if (not _has_ddcs) {
- for (size_t radio_idx = 0; radio_idx < _num_radios_per_board;
- radio_idx++) {
- for (size_t chan = 0; chan < _num_rx_chans_per_radio; chan++) {
- const uhd::fs_path rx_dsp_base_path(
- mb_root(mboard_idx) / "rx_dsps" / radio_idx / chan);
- _tree->create<double>(rx_dsp_base_path / "rate/value")
- .set(0.0)
- .set_publisher(boost::bind(&radio_ctrl::get_output_samp_rate,
- get_block_ctrl<radio_ctrl>(
- mboard_idx, RADIO_BLOCK_NAME, radio_idx),
- chan));
- _tree->create<uhd::meta_range_t>(rx_dsp_base_path / "rate/range")
- .set_publisher(boost::bind(
- &legacy_compat_impl::lambda_get_samp_rate_range,
- this,
- mboard_idx,
- radio_idx,
- chan,
- uhd::RX_DIRECTION));
- _tree->create<double>(rx_dsp_base_path / "freq/value")
- .set_publisher([]() { return 0.0; });
- _tree->create<uhd::meta_range_t>(rx_dsp_base_path / "freq/range")
- .set_publisher(
- []() { return uhd::meta_range_t(0.0, 0.0, 0.0); });
- }
- }
- } /* if not _has_ddcs */
- if (not _has_ducs) {
- for (size_t radio_idx = 0; radio_idx < _num_radios_per_board;
- radio_idx++) {
- for (size_t chan = 0; chan < _num_tx_chans_per_radio; chan++) {
- const uhd::fs_path tx_dsp_base_path(
- mb_root(mboard_idx) / "tx_dsps" / radio_idx / chan);
- _tree->create<double>(tx_dsp_base_path / "rate/value")
- .set(0.0)
- .set_publisher(boost::bind(&radio_ctrl::get_input_samp_rate,
- get_block_ctrl<radio_ctrl>(
- mboard_idx, RADIO_BLOCK_NAME, radio_idx),
- chan));
- _tree->create<uhd::meta_range_t>(tx_dsp_base_path / "rate/range")
- .set_publisher(boost::bind(
- &legacy_compat_impl::lambda_get_samp_rate_range,
- this,
- mboard_idx,
- radio_idx,
- chan,
- uhd::TX_DIRECTION));
- _tree->create<double>(tx_dsp_base_path / "freq/value")
- .set_publisher([]() { return 0.0; });
- _tree->create<uhd::meta_range_t>(tx_dsp_base_path / "freq/range")
- .set_publisher(
- []() { return uhd::meta_range_t(0.0, 0.0, 0.0); });
- }
- }
- } /* if not _has_ducs */
- }
- }
-
-
- /*! Remove properties with bound functions in property tree and recreate
- */
- void remove_prop_subscribers()
- {
- for (size_t mboard_idx = 0; mboard_idx < _num_mboards; mboard_idx++) {
- uhd::fs_path root = mb_root(mboard_idx);
- // Subdev specs
- if (_tree->exists(root / "tx_subdev_spec")) {
- recreate_property<subdev_spec_t>(root / "tx_subdev_spec", _tree);
- }
-
- if (_tree->exists(root / "rx_subdev_spec")) {
- recreate_property<subdev_spec_t>(root / "rx_subdev_spec", _tree);
- }
- }
- }
-
- //! Flatten and sort a block list into a list of <block, port_index>
- // For a block list {b0 ,b1} where each block has ports {p0, p1}, this will
- // return {<b0,p0> <b0,p1> <b1,p0> <b1,p1>}
- std::vector<source_port_t> _flatten_blocks_by_n_ports(source_block_list_t block_list)
- {
- std::vector<source_port_t> result;
- for (auto block : block_list) {
- for (auto port : block->get_output_ports()) {
- result.push_back(std::make_pair(block, port));
- }
- }
- return result;
- }
-
- //! Flatten and sort a block list into a list of <block, port_index>
- // For a block list {b0 ,b1} where each block has ports {p0, p1}, this will
- // return {<b0,p0> <b0,p1> <b1,p0> <b1,p1>}
- std::vector<sink_port_t> _flatten_blocks_by_n_ports(sink_block_list_t block_list)
- {
- std::vector<sink_port_t> result;
- for (auto block : block_list) {
- for (auto port : block->get_input_ports()) {
- result.push_back(std::make_pair(block, port));
- }
- }
- return result;
- }
-
- template <typename T>
- std::vector<std::pair<T, size_t>> _filter_flattened_blocks(
- const std::vector<std::pair<T, size_t>>& blocks, size_t device_number)
- {
- const auto pred = [&device_number](const std::pair<T, size_t>& block) {
- return (block.first->get_block_id().get_device_no() == device_number);
- };
-
- std::vector<std::pair<T, size_t>> result;
- std::copy_if(blocks.begin(), blocks.end(), std::back_inserter(result), pred);
- return result;
- }
-
- /*! Default block connections.
- *
- * Tx connections:
- *
- * [Host] => DMA FIFO => DUC => Radio
- *
- * Note: There is only one DMA FIFO per crossbar, with twice the number of ports.
- *
- * Rx connections:
- *
- * Radio => DDC => [Host]
- *
- * Streamers are *not* generated here.
- */
- void connect_blocks()
- {
- const size_t rx_bpp = _rx_spp * BYTES_PER_SAMPLE + MAX_BYTES_PER_HEADER;
- const size_t tx_bpp = _tx_spp * BYTES_PER_SAMPLE + MAX_BYTES_PER_HEADER;
- _graph = _device->create_graph("legacy");
-
- block_name_to_block_map_t legacy_block_map = get_legacy_blocks(_device);
- // create a list of all devices in the legacy block map
- std::set<size_t> device_numbers;
- for (const auto& block_list : legacy_block_map) {
- for (const auto& block : block_list.second.first) {
- device_numbers.insert(block->get_block_id().get_device_no());
- }
- for (const auto& block : block_list.second.second) {
- device_numbers.insert(block->get_block_id().get_device_no());
- }
- }
-
- // Generate lists of all available ports in the graph
- // RX connections:
- // Radio => DDC
- auto radio_sources =
- _flatten_blocks_by_n_ports(legacy_block_map[RADIO_BLOCK_NAME].first);
- auto ddc_sinks =
- _flatten_blocks_by_n_ports(legacy_block_map[DDC_BLOCK_NAME].second);
-
- // TX connections:
- // DUC => Radio
- auto duc_sources =
- _flatten_blocks_by_n_ports(legacy_block_map[DUC_BLOCK_NAME].first);
- auto radio_sinks =
- _flatten_blocks_by_n_ports(legacy_block_map[RADIO_BLOCK_NAME].second);
-
- // FIFO (SRAM or DMA) => DUC
- auto duc_sinks =
- _flatten_blocks_by_n_ports(legacy_block_map[DUC_BLOCK_NAME].second);
- auto sfifo_sources =
- _flatten_blocks_by_n_ports(legacy_block_map[SFIFO_BLOCK_NAME].first);
- auto dfifo_sources =
- _flatten_blocks_by_n_ports(legacy_block_map[DFIFO_BLOCK_NAME].first);
-
- for (const auto& device_number : device_numbers) {
- // for RX, if there are DDCs, connect them to the radios
- if (_has_ddcs) {
- auto filtered_radio_sources =
- _filter_flattened_blocks(radio_sources, device_number);
- auto filtered_ddc_sinks =
- _filter_flattened_blocks(ddc_sinks, device_number);
- UHD_ASSERT_THROW(
- filtered_radio_sources.size() <= filtered_ddc_sinks.size());
-
- for (size_t i = 0; i < filtered_radio_sources.size(); ++i) {
- _graph->connect(filtered_radio_sources[i].first->get_block_id(),
- filtered_radio_sources[i].second,
- filtered_ddc_sinks[i].first->get_block_id(),
- filtered_ddc_sinks[i].second,
- rx_bpp);
- }
- }
-
- // for TX, if there are DUCs, connect them to the radios
- if (_has_ducs) {
- auto filtered_duc_sources =
- _filter_flattened_blocks(duc_sources, device_number);
- auto filtered_radio_sinks =
- _filter_flattened_blocks(radio_sinks, device_number);
-
- UHD_ASSERT_THROW(
- filtered_duc_sources.size() <= filtered_radio_sinks.size());
-
- for (size_t i = 0; i < filtered_duc_sources.size(); ++i) {
- _graph->connect(filtered_duc_sources[i].first->get_block_id(),
- filtered_duc_sources[i].second,
- filtered_radio_sinks[i].first->get_block_id(),
- filtered_radio_sinks[i].second,
- tx_bpp);
- }
- }
-
- // for TX, if there are SRAM or DMA fifos, connect them to the DUCs
- // (or radios, if there are no DUCs)
- if (_has_sramfifo or _has_dmafifo) {
- auto filtered_sources =
- (_has_sramfifo)
- ? _filter_flattened_blocks(sfifo_sources, device_number)
- : _filter_flattened_blocks(dfifo_sources, device_number);
- auto filtered_sinks =
- (_has_ducs) ? _filter_flattened_blocks(duc_sinks, device_number)
- : _filter_flattened_blocks(radio_sinks, device_number);
-
- if (filtered_sources.size() < filtered_sinks.size()) {
- UHD_LOG_WARNING("RFNOC",
- "[legacy compat] Not enough FIFO ports to connect, not all TX "
- "sinks will be connected");
- }
-
- for (size_t i = 0; i < filtered_sources.size(); ++i) {
- _graph->connect(filtered_sources[i].first->get_block_id(),
- filtered_sources[i].second,
- filtered_sinks[i].first->get_block_id(),
- filtered_sinks[i].second,
- tx_bpp);
- }
- }
- }
- }
-
-
- /************************************************************************
- * Subdev translation
- ***********************************************************************/
- /*! Subdev -> (Radio, Port)
- *
- * Example: Device is X300, subdev spec is 'A:0 B:0', we have 2 radios.
- * Then we map to ((0, 0), (1, 0)). I.e., zero-th port on radio 0 and
- * radio 1, respectively.
- */
- void set_subdev_spec(
- const subdev_spec_t& spec, const size_t mboard, const uhd::direction_t dir)
- {
- UHD_ASSERT_THROW(mboard < _num_mboards);
- chan_map_t& chan_map = (dir == uhd::TX_DIRECTION) ? _tx_channel_map
- : _rx_channel_map;
-
- std::vector<radio_port_pair_t> new_mapping(spec.size());
- for (size_t i = 0; i < spec.size(); i++) {
- const size_t new_radio_index = get_radio_index(spec[i].db_name);
- radio_ctrl::sptr radio =
- get_block_ctrl<radio_ctrl>(mboard, "Radio", new_radio_index);
- size_t new_port_index = radio->get_chan_from_dboard_fe(spec[i].sd_name, dir);
- auto port_size = (dir == uhd::TX_DIRECTION)
- ? radio->get_input_ports().size()
- : radio->get_output_ports().size();
- auto default_index = (dir == uhd::TX_DIRECTION)
- ? radio->get_input_ports().at(0)
- : radio->get_output_ports().at(0);
- if (new_port_index >= port_size) {
- new_port_index = default_index;
- }
-
- radio_port_pair_t new_radio_port_pair(new_radio_index, new_port_index);
- new_mapping[i] = new_radio_port_pair;
- }
- chan_map[mboard] = new_mapping;
- }
-
- subdev_spec_t get_subdev_spec(const size_t mboard, const uhd::direction_t dir)
- {
- UHD_ASSERT_THROW(mboard < _num_mboards);
- subdev_spec_t subdev_spec;
- chan_map_t& chan_map = (dir == uhd::TX_DIRECTION) ? _tx_channel_map
- : _rx_channel_map;
- for (size_t chan_idx = 0; chan_idx < chan_map[mboard].size(); chan_idx++) {
- const size_t radio_index = chan_map[mboard][chan_idx].radio_index;
- const size_t port_index = chan_map[mboard][chan_idx].port_index;
- const std::string new_db_name = get_slot_name(radio_index);
- const std::string new_sd_name =
- get_block_ctrl<radio_ctrl>(mboard, "Radio", radio_index)
- ->get_dboard_fe_from_chan(port_index, dir);
- subdev_spec_pair_t new_pair(new_db_name, new_sd_name);
- subdev_spec.push_back(new_pair);
- }
-
- return subdev_spec;
- }
-
- void update_sample_rate_on_blocks(const size_t mboard_idx)
- {
- block_id_t radio_block_id(mboard_idx, RADIO_BLOCK_NAME);
- block_id_t duc_block_id(mboard_idx, DUC_BLOCK_NAME);
- block_id_t ddc_block_id(mboard_idx, DDC_BLOCK_NAME);
-
- for (size_t radio = 0; radio < _num_radios_per_board; radio++) {
- radio_block_id.set_block_count(radio);
- duc_block_id.set_block_count(radio);
- ddc_block_id.set_block_count(radio);
- radio_ctrl::sptr radio_sptr =
- _device->get_block_ctrl<radio_ctrl>(radio_block_id);
- for (size_t chan = 0; chan < _num_rx_chans_per_radio and _has_ddcs; chan++) {
- const double radio_output_rate = radio_sptr->get_output_samp_rate(chan);
- _device->get_block_ctrl(ddc_block_id)
- ->set_arg<double>("input_rate", radio_output_rate, chan);
- }
- for (size_t chan = 0; chan < _num_tx_chans_per_radio and _has_ducs; chan++) {
- const double radio_input_rate = radio_sptr->get_input_samp_rate(chan);
- _device->get_block_ctrl(duc_block_id)
- ->set_arg<double>("output_rate", radio_input_rate, chan);
- }
- }
- }
-
-private: // attributes
- uhd::device3::sptr _device;
- uhd::property_tree::sptr _tree;
-
- const bool _has_ducs;
- const bool _has_ddcs;
- const bool _has_dmafifo;
- const bool _has_sramfifo;
- const size_t _num_mboards;
- const size_t _num_radios_per_board;
- const size_t _num_tx_chans_per_radio;
- const size_t _num_rx_chans_per_radio;
- size_t _rx_spp;
- size_t _tx_spp;
-
- chan_map_t _rx_channel_map;
- chan_map_t _tx_channel_map;
-
- //! Stores a weak pointer for every streamer that's generated through this API.
- // Key is the channel number (same format as e.g. the set_rx_rate() call).
- typedef std::map<size_t, boost::weak_ptr<uhd::rx_streamer>> rx_stream_map_type;
- rx_stream_map_type _rx_stream_cache;
- typedef std::map<size_t, boost::weak_ptr<uhd::tx_streamer>> tx_stream_map_type;
- tx_stream_map_type _tx_stream_cache;
-
- graph::sptr _graph;
-};
-
-legacy_compat::sptr legacy_compat::make(
- uhd::device3::sptr device, const uhd::device_addr_t& args)
-{
- boost::lock_guard<boost::mutex> lock(_make_mutex);
- UHD_ASSERT_THROW(bool(device));
- static std::map<void*, boost::weak_ptr<legacy_compat>> legacy_cache;
-
- if (legacy_cache.count(device.get())
- and not legacy_cache.at(device.get()).expired()) {
- legacy_compat::sptr legacy_compat_copy = legacy_cache.at(device.get()).lock();
- UHD_ASSERT_THROW(bool(legacy_compat_copy));
- UHD_LEGACY_LOG()
- << "[legacy_compat] Using existing legacy compat object for this device.";
- return legacy_compat_copy;
- }
-
- legacy_compat::sptr new_legacy_compat =
- boost::make_shared<legacy_compat_impl>(device, args);
- legacy_cache[device.get()] = new_legacy_compat;
- return new_legacy_compat;
-}
diff --git a/host/lib/rfnoc/nocscript/CMakeLists.txt b/host/lib/rfnoc/nocscript/CMakeLists.txt
deleted file mode 100644
index 2eeb984bf..000000000
--- a/host/lib/rfnoc/nocscript/CMakeLists.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Copyright 2015 Ettus Research LLC
-# Copyright 2018 Ettus Research, a National Instruments Company
-#
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR})
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-LIBUHD_PYTHON_GEN_SOURCE(
- ${CMAKE_CURRENT_SOURCE_DIR}/gen_basic_funcs.py
- ${CMAKE_CURRENT_BINARY_DIR}/basic_functions.hpp
-)
-
-if(ENABLE_MANUAL)
- LIBUHD_PYTHON_GEN_SOURCE(
- ${CMAKE_CURRENT_SOURCE_DIR}/gen_basic_funcs.py
- ${CMAKE_BINARY_DIR}/docs/nocscript_functions.dox
- )
-endif(ENABLE_MANUAL)
-
-LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/expression.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/function_table.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/parser.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/block_iface.cpp
-)
diff --git a/host/lib/rfnoc/nocscript/block_iface.cpp b/host/lib/rfnoc/nocscript/block_iface.cpp
deleted file mode 100644
index f029c3324..000000000
--- a/host/lib/rfnoc/nocscript/block_iface.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "block_iface.hpp"
-#include "function_table.hpp"
-#include <uhd/exception.hpp>
-#include <uhd/utils/log.hpp>
-#include <boost/assign.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-
-#define UHD_NOCSCRIPT_LOG() UHD_LOGGER_TRACE("RFNOC")
-
-using namespace uhd::rfnoc;
-using namespace uhd::rfnoc::nocscript;
-
-block_iface::block_iface(block_ctrl_base* block_ptr) : _block_ptr(block_ptr)
-{
- function_table::sptr ft = function_table::make();
-
- // Add the SR_WRITE() function
- expression_function::argtype_list_type sr_write_args_wo_port =
- boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT);
- expression_function::argtype_list_type sr_write_args_w_port = boost::assign::list_of(
- expression::TYPE_STRING)(expression::TYPE_INT)(expression::TYPE_INT);
- ft->register_function("SR_WRITE",
- boost::bind(&block_iface::_nocscript__sr_write, this, _1),
- expression::TYPE_BOOL,
- sr_write_args_wo_port);
- ft->register_function("SR_WRITE",
- boost::bind(&block_iface::_nocscript__sr_write, this, _1),
- expression::TYPE_BOOL,
- sr_write_args_w_port);
-
- // Add read access to arguments ($foo)
- expression_function::argtype_list_type arg_set_args_wo_port =
- boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT);
- expression_function::argtype_list_type arg_set_args_w_port = boost::assign::list_of(
- expression::TYPE_STRING)(expression::TYPE_INT)(expression::TYPE_INT);
-#define REGISTER_ARG_SETTER(noctype, setter_func) \
- arg_set_args_wo_port[1] = expression::noctype; \
- arg_set_args_w_port[1] = expression::noctype; \
- ft->register_function("SET_ARG", \
- boost::bind(&block_iface::setter_func, this, _1), \
- expression::TYPE_BOOL, \
- arg_set_args_wo_port); \
- ft->register_function("SET_ARG", \
- boost::bind(&block_iface::setter_func, this, _1), \
- expression::TYPE_BOOL, \
- arg_set_args_w_port);
- REGISTER_ARG_SETTER(TYPE_INT, _nocscript__arg_set_int);
- REGISTER_ARG_SETTER(TYPE_STRING, _nocscript__arg_set_string);
- REGISTER_ARG_SETTER(TYPE_DOUBLE, _nocscript__arg_set_double);
- REGISTER_ARG_SETTER(TYPE_INT_VECTOR, _nocscript__arg_set_intvec);
-
-
- // Add read/write access to local variables
- expression_function::argtype_list_type set_var_args =
- boost::assign::list_of(expression::TYPE_STRING)(expression::TYPE_INT);
- const expression_function::argtype_list_type get_var_args =
- boost::assign::list_of(expression::TYPE_STRING);
-#define REGISTER_VAR_ACCESS(noctype, typestr) \
- set_var_args[1] = expression::noctype; \
- ft->register_function("SET_VAR", \
- boost::bind(&block_iface::_nocscript__var_set, this, _1), \
- expression::TYPE_BOOL, \
- set_var_args); \
- ft->register_function("GET_" #typestr, \
- boost::bind(&block_iface::_nocscript__var_get, this, _1), \
- expression::noctype, \
- get_var_args);
- REGISTER_VAR_ACCESS(TYPE_INT, INT);
- REGISTER_VAR_ACCESS(TYPE_STRING, STRING);
- REGISTER_VAR_ACCESS(TYPE_DOUBLE, DOUBLE);
- REGISTER_VAR_ACCESS(TYPE_INT_VECTOR, INT_VECTOR);
-
- // Create the parser
- _parser = parser::make(ft,
- boost::bind(&block_iface::_nocscript__arg_get_type, this, _1),
- boost::bind(&block_iface::_nocscript__arg_get_val, this, _1));
-}
-
-
-void block_iface::run_and_check(const std::string& code, const std::string& error_message)
-{
- boost::mutex::scoped_lock local_interpreter_lock(_lil_mutex);
-
- UHD_NOCSCRIPT_LOG() << "[NocScript] Executing and asserting code: " << code;
- expression::sptr e = _parser->create_expr_tree(code);
- expression_literal result = e->eval();
- if (not result.to_bool()) {
- if (error_message.empty()) {
- throw uhd::runtime_error(
- str(boost::format("[NocScript] Code returned false: %s") % code));
- } else {
- throw uhd::runtime_error(
- str(boost::format("[NocScript] Error: %s") % error_message));
- }
- }
-
- _vars.clear(); // We go out of scope, and so do NocScript variables
-}
-
-
-expression_literal block_iface::_nocscript__sr_write(
- expression_container::expr_list_type args)
-{
- const std::string reg_name = args[0]->eval().get_string();
- const uint32_t reg_val = uint32_t(args[1]->eval().get_int());
- size_t port = 0;
- if (args.size() == 3) {
- port = size_t(args[2]->eval().get_int());
- }
-
- bool result = true;
- try {
- UHD_NOCSCRIPT_LOG() << "[NocScript] Executing SR_WRITE() ";
- _block_ptr->sr_write(reg_name, reg_val, port);
- } catch (const uhd::exception& e) {
- UHD_LOGGER_ERROR("RFNOC")
- << boost::format("[NocScript] Error while executing SR_WRITE(%s, 0x%X):\n%s")
- % reg_name % reg_val % e.what();
- result = false;
- }
-
- return expression_literal(result);
-}
-
-expression::type_t block_iface::_nocscript__arg_get_type(const std::string& varname)
-{
- const std::string var_type = _block_ptr->get_arg_type(varname);
- if (var_type == "int") {
- return expression::TYPE_INT;
- } else if (var_type == "string") {
- return expression::TYPE_STRING;
- } else if (var_type == "double") {
- return expression::TYPE_DOUBLE;
- } else if (var_type == "int_vector") {
- UHD_THROW_INVALID_CODE_PATH(); // TODO
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-expression_literal block_iface::_nocscript__arg_get_val(const std::string& varname)
-{
- const std::string var_type = _block_ptr->get_arg_type(varname);
- if (var_type == "int") {
- return expression_literal(_block_ptr->get_arg<int>(varname));
- } else if (var_type == "string") {
- return expression_literal(_block_ptr->get_arg<std::string>(varname));
- } else if (var_type == "double") {
- return expression_literal(_block_ptr->get_arg<double>(varname));
- } else if (var_type == "int_vector") {
- UHD_THROW_INVALID_CODE_PATH(); // TODO
- } else {
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-expression_literal block_iface::_nocscript__arg_set_int(
- const expression_container::expr_list_type& args)
-{
- const std::string var_name = args[0]->eval().get_string();
- const int val = args[1]->eval().get_int();
- size_t port = 0;
- if (args.size() == 3) {
- port = size_t(args[2]->eval().get_int());
- }
- UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name;
- _block_ptr->set_arg<int>(var_name, val, port);
- return expression_literal(true);
-}
-
-expression_literal block_iface::_nocscript__arg_set_string(
- const expression_container::expr_list_type& args)
-{
- const std::string var_name = args[0]->eval().get_string();
- const std::string val = args[1]->eval().get_string();
- size_t port = 0;
- if (args.size() == 3) {
- port = size_t(args[2]->eval().get_int());
- }
- UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name;
- _block_ptr->set_arg<std::string>(var_name, val, port);
- return expression_literal(true);
-}
-
-expression_literal block_iface::_nocscript__arg_set_double(
- const expression_container::expr_list_type& args)
-{
- const std::string var_name = args[0]->eval().get_string();
- const double val = args[1]->eval().get_double();
- size_t port = 0;
- if (args.size() == 3) {
- port = size_t(args[2]->eval().get_int());
- }
- UHD_NOCSCRIPT_LOG() << "[NocScript] Setting $" << var_name;
- _block_ptr->set_arg<double>(var_name, val, port);
- return expression_literal(true);
-}
-
-expression_literal block_iface::_nocscript__arg_set_intvec(
- const expression_container::expr_list_type&)
-{
- UHD_THROW_INVALID_CODE_PATH();
-}
-
-block_iface::sptr block_iface::make(uhd::rfnoc::block_ctrl_base* block_ptr)
-{
- return sptr(new block_iface(block_ptr));
-}
-
-expression_literal block_iface::_nocscript__var_get(
- const expression_container::expr_list_type& args)
-{
- expression_literal expr = _vars[args[0]->eval().get_string()];
- // std::cout << "[NocScript] Getting var " << args[0]->eval().get_string() << " == "
- // << expr ; std::cout << "[NocScript] Type " << expr.infer_type() ; return
- // _vars[args[0]->eval().get_string()];
- return expr;
-}
-
-expression_literal block_iface::_nocscript__var_set(
- const expression_container::expr_list_type& args)
-{
- _vars[args[0]->eval().get_string()] = args[1]->eval();
- // std::cout << "[NocScript] Set var " << args[0]->eval().get_string() << " to " <<
- // _vars[args[0]->eval().get_string()] ; std::cout << "[NocScript] Type " <<
- // _vars[args[0]->eval().get_string()].infer_type() ;
- return expression_literal(true);
-}
diff --git a/host/lib/rfnoc/nocscript/block_iface.hpp b/host/lib/rfnoc/nocscript/block_iface.hpp
deleted file mode 100644
index 9d13fd4ab..000000000
--- a/host/lib/rfnoc/nocscript/block_iface.hpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "expression.hpp"
-#include "parser.hpp"
-#include <uhd/rfnoc/block_ctrl_base.hpp>
-#include <boost/thread/mutex.hpp>
-
-#ifndef INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP
-# define INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP
-
-namespace uhd { namespace rfnoc { namespace nocscript {
-
-/*! NocScript / Block interface class.
- *
- * This class only exists as a member of an rfnoc::block_ctrl_base class.
- * It should never be instantiated anywhere else. It is used to execute
- * NocScript function calls that require access to the original block
- * controller class.
- */
-class block_iface
-{
-public:
- typedef boost::shared_ptr<block_iface> sptr;
-
- static sptr make(uhd::rfnoc::block_ctrl_base* block_ptr);
-
- block_iface(uhd::rfnoc::block_ctrl_base* block_ptr);
-
- /*! Execute \p code and make sure it returns 'true'.
- *
- * \param code Must be a valid NocScript expression that returns a boolean value.
- * If it returns false, this is interpreted as failure.
- * \param error_message If the expression fails, this error message is printed.
- * \throws uhd::runtime_error if the expression returns false.
- * \throws uhd::syntax_error if the expression is invalid.
- */
- void run_and_check(const std::string& code, const std::string& error_message = "");
-
-private:
- //! For the local interpreter lock (lil)
- boost::mutex _lil_mutex;
-
- //! Wrapper for block_ctrl_base::sr_write, so we can call it from within NocScript
- expression_literal _nocscript__sr_write(expression_container::expr_list_type);
-
- //! Argument type getter that can be used within NocScript
- expression::type_t _nocscript__arg_get_type(const std::string& argname);
-
- //! Argument value getter that can be used within NocScript
- expression_literal _nocscript__arg_get_val(const std::string& argname);
-
- //! Argument value setters:
- expression_literal _nocscript__arg_set_int(
- const expression_container::expr_list_type&);
- expression_literal _nocscript__arg_set_string(
- const expression_container::expr_list_type&);
- expression_literal _nocscript__arg_set_double(
- const expression_container::expr_list_type&);
- expression_literal _nocscript__arg_set_intvec(
- const expression_container::expr_list_type&);
-
- //! Variable value getter
- expression_literal _nocscript__var_get(const expression_container::expr_list_type&);
-
- //! Variable value setter
- expression_literal _nocscript__var_set(const expression_container::expr_list_type&);
-
- //! Raw pointer to the block class. Note that since block_iface may
- // only live as a member of a block_ctrl_base, we don't really need
- // the reference counting.
- uhd::rfnoc::block_ctrl_base* _block_ptr;
-
- //! Pointer to the parser object
- parser::sptr _parser;
-
- //! Container for scoped variables
- std::map<std::string, expression_literal> _vars;
-};
-
-}}} /* namespace uhd::rfnoc::nocscript */
-
-#endif /* INCLUDED_LIBUHD_NOCSCRIPT_BLOCK_IFACE_HPP */
diff --git a/host/lib/rfnoc/nocscript/expression.cpp b/host/lib/rfnoc/nocscript/expression.cpp
deleted file mode 100644
index 5e03485be..000000000
--- a/host/lib/rfnoc/nocscript/expression.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "expression.hpp"
-#include "function_table.hpp"
-#include <uhd/utils/cast.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd::rfnoc::nocscript;
-
-std::map<expression::type_t, std::string> expression::type_repr{{TYPE_INT, "INT"},
- {TYPE_DOUBLE, "DOUBLE"},
- {TYPE_STRING, "STRING"},
- {TYPE_BOOL, "BOOL"},
- {TYPE_INT_VECTOR, "INT_VECTOR"}};
-
-/********************************************************************
- * Literal expressions (constants)
- *******************************************************************/
-expression_literal::expression_literal(
- const std::string token_val, expression::type_t type)
- : _bool_val(false), _int_val(0), _double_val(0.0), _val(token_val), _type(type)
-{
- switch (_type) {
- case expression::TYPE_STRING:
- // Remove the leading and trailing quotes:
- _val = _val.substr(1, _val.size() - 2);
- break;
-
- case expression::TYPE_INT:
- if (_val.substr(0, 2) == "0x") {
- _int_val = uhd::cast::hexstr_cast<int>(_val);
- } else {
- _int_val = std::stoi(_val);
- }
- break;
-
- case expression::TYPE_DOUBLE:
- _double_val = std::stod(_val);
- break;
-
- case expression::TYPE_BOOL:
- if (boost::to_upper_copy(_val) == "TRUE") {
- _bool_val = true;
- } else {
- // lexical cast to bool is too picky
- _bool_val = (std::stoi(_val) != 0);
- }
- break;
-
- case expression::TYPE_INT_VECTOR: {
- std::string str_vec = _val.substr(1, _val.size() - 2);
- std::vector<std::string> subtoken_list;
- boost::split(
- subtoken_list, str_vec, boost::is_any_of(", "), boost::token_compress_on);
- for (const std::string& t : subtoken_list) {
- _int_vector_val.push_back(std::stoi(t));
- }
- break;
- }
-
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-expression_literal::expression_literal(bool b)
- : _bool_val(b), _int_val(0), _double_val(0.0), _val(""), _type(expression::TYPE_BOOL)
-{
- // nop
-}
-
-expression_literal::expression_literal(int i)
- : _bool_val(false)
- , _int_val(i)
- , _double_val(0.0)
- , _val("")
- , _type(expression::TYPE_INT)
-{
- // nop
-}
-
-expression_literal::expression_literal(double d)
- : _bool_val(false)
- , _int_val(0)
- , _double_val(d)
- , _val("")
- , _type(expression::TYPE_DOUBLE)
-{
- // nop
-}
-
-expression_literal::expression_literal(const std::string& s)
- : _bool_val(false)
- , _int_val(0)
- , _double_val(0.0)
- , _val(s)
- , _type(expression::TYPE_STRING)
-{
- // nop
-}
-
-expression_literal::expression_literal(const std::vector<int> v)
- : _bool_val(false)
- , _int_val(0)
- , _double_val(0.0)
- , _int_vector_val(v)
- , _val("")
- , _type(expression::TYPE_INT_VECTOR)
-{
- // nop
-}
-
-bool expression_literal::to_bool() const
-{
- switch (_type) {
- case TYPE_INT:
- return bool(std::stoi(_val));
- case TYPE_STRING:
- return not _val.empty();
- case TYPE_DOUBLE:
- return bool(std::stod(_val));
- case TYPE_BOOL:
- return _bool_val;
- case TYPE_INT_VECTOR:
- return not _int_vector_val.empty();
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-int expression_literal::get_int() const
-{
- if (_type != TYPE_INT) {
- throw uhd::type_error("Cannot call get_int() on non-int value.");
- }
-
- return _int_val;
-}
-
-double expression_literal::get_double() const
-{
- if (_type != TYPE_DOUBLE) {
- throw uhd::type_error("Cannot call get_double() on non-double value.");
- }
-
- return _double_val;
-}
-
-std::string expression_literal::get_string() const
-{
- if (_type != TYPE_STRING) {
- throw uhd::type_error("Cannot call get_string() on non-string value.");
- }
-
- return _val;
-}
-
-bool expression_literal::get_bool() const
-{
- if (_type != TYPE_BOOL) {
- throw uhd::type_error("Cannot call get_bool() on non-boolean value.");
- }
-
- return _bool_val;
-}
-
-std::vector<int> expression_literal::get_int_vector() const
-{
- if (_type != TYPE_INT_VECTOR) {
- throw uhd::type_error("Cannot call get_bool() on non-boolean value.");
- }
-
- return _int_vector_val;
-}
-
-std::string expression_literal::repr() const
-{
- switch (_type) {
- case TYPE_INT:
- return std::to_string(_int_val);
- case TYPE_STRING:
- return _val;
- case TYPE_DOUBLE:
- return std::to_string(_double_val);
- case TYPE_BOOL:
- return _bool_val ? "TRUE" : "FALSE";
- case TYPE_INT_VECTOR: {
- std::stringstream sstr;
- sstr << "[";
- for (size_t i = 0; i < _int_vector_val.size(); i++) {
- if (i > 0) {
- sstr << ", ";
- }
- sstr << _int_vector_val[i];
- }
- sstr << "]";
- return sstr.str();
- }
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-bool expression_literal::operator==(const expression_literal& rhs) const
-{
- if (rhs.infer_type() != _type) {
- return false;
- }
-
- switch (_type) {
- case TYPE_INT:
- return get_int() == rhs.get_int();
- case TYPE_STRING:
- return get_string() == rhs.get_string();
- case TYPE_DOUBLE:
- return get_double() == rhs.get_double();
- case TYPE_BOOL:
- return get_bool() == rhs.get_bool();
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
-}
-
-/********************************************************************
- * Containers
- *******************************************************************/
-expression_container::sptr expression_container::make()
-{
- return sptr(new expression_container);
-}
-
-expression::type_t expression_container::infer_type() const
-{
- if (_combiner == COMBINE_OR or _combiner == COMBINE_AND) {
- return TYPE_BOOL;
- }
-
- if (_sub_exprs.empty()) {
- return TYPE_BOOL;
- }
-
- return _sub_exprs.back()->infer_type();
-}
-
-void expression_container::add(expression::sptr new_expr)
-{
- _sub_exprs.push_back(new_expr);
-}
-
-bool expression_container::empty() const
-{
- return _sub_exprs.empty();
-}
-
-void expression_container::set_combiner_safe(const combiner_type c)
-{
- if (_combiner == COMBINE_NOTSET) {
- _combiner = c;
- return;
- }
-
- throw uhd::syntax_error("Attempting to override combiner type");
-}
-
-expression_literal expression_container::eval()
-{
- if (_sub_exprs.empty()) {
- return expression_literal(true);
- }
-
- expression_literal ret_val;
- for (const expression::sptr& sub_expr : _sub_exprs) {
- ret_val = sub_expr->eval();
- if (_combiner == COMBINE_AND and ret_val.to_bool() == false) {
- return ret_val;
- }
- if (_combiner == COMBINE_OR and ret_val.to_bool() == true) {
- return ret_val;
- }
- // For ALL, we return the last one, so just overwrite it
- }
- return ret_val;
-}
-
-/********************************************************************
- * Functions
- *******************************************************************/
-std::string expression_function::to_string(
- const std::string& name, const argtype_list_type& types)
-{
- std::string s = name;
- int arg_count = 0;
- for (const expression::type_t type : types) {
- if (arg_count == 0) {
- s += "(";
- } else {
- s += ", ";
- }
- s += type_repr[type];
- arg_count++;
- }
- s += ")";
-
- return s;
-}
-
-expression_function::expression_function(
- const std::string& name, const function_table::sptr func_table)
- : _name(name), _func_table(func_table)
-{
- _combiner = COMBINE_ALL;
- if (not _func_table->function_exists(_name)) {
- throw uhd::syntax_error(str(boost::format("Unknown function: %s") % _name));
- }
-}
-
-void expression_function::add(expression::sptr new_expr)
-{
- expression_container::add(new_expr);
- _arg_types.push_back(new_expr->infer_type());
-}
-
-expression::type_t expression_function::infer_type() const
-{
- return _func_table->get_type(_name, _arg_types);
-}
-
-expression_literal expression_function::eval()
-{
- return _func_table->eval(_name, _arg_types, _sub_exprs);
-}
-
-
-std::string expression_function::repr() const
-{
- return to_string(_name, _arg_types);
-}
-
-expression_function::sptr expression_function::make(
- const std::string& name, const function_table::sptr func_table)
-{
- return sptr(new expression_function(name, func_table));
-}
-
-/********************************************************************
- * Variables
- *******************************************************************/
-expression_variable::expression_variable(const std::string& token_val,
- type_getter_type type_getter,
- value_getter_type value_getter)
- : _type_getter(type_getter), _value_getter(value_getter)
-{
- // We can assume this is true because otherwise, it's not a valid token:
- UHD_ASSERT_THROW(not token_val.empty() and token_val[0] == '$');
-
- _varname = token_val.substr(1);
-}
-
-expression::type_t expression_variable::infer_type() const
-{
- return _type_getter(_varname);
-}
-
-expression_literal expression_variable::eval()
-{
- return _value_getter(_varname);
-}
-
-expression_variable::sptr expression_variable::make(const std::string& token_val,
- type_getter_type type_getter,
- value_getter_type value_getter)
-{
- return sptr(new expression_variable(token_val, type_getter, value_getter));
-}
diff --git a/host/lib/rfnoc/nocscript/expression.hpp b/host/lib/rfnoc/nocscript/expression.hpp
deleted file mode 100644
index 309741295..000000000
--- a/host/lib/rfnoc/nocscript/expression.hpp
+++ /dev/null
@@ -1,360 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/exception.hpp>
-#include <boost/function.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/shared_ptr.hpp>
-#include <map>
-#include <vector>
-
-#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP
-# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP
-
-namespace uhd { namespace rfnoc { namespace nocscript {
-
-// Forward declaration for expression::eval()
-class expression_literal;
-
-/*! Virtual base class for Noc-Script expressions.
- */
-class expression
-{
-public:
- typedef boost::shared_ptr<expression> sptr;
-
- //! All the possible return types for expressions within Noc-Script
- enum type_t { TYPE_INT, TYPE_DOUBLE, TYPE_STRING, TYPE_BOOL, TYPE_INT_VECTOR };
-
- // TODO make this a const and fix the [] usage
- static std::map<type_t, std::string> type_repr;
-
- //! Returns the type of this expression without evaluating it
- virtual type_t infer_type() const = 0;
-
- //! Evaluate current expression and return its return value
- virtual expression_literal eval() = 0;
-};
-
-/*! Literal (constant) expression class
- *
- * A literal is any value that is literally given in the NoC-Script
- * source code, such as '5', '"FOO"', or '2.3'.
- */
-class expression_literal : public expression
-{
-public:
- typedef boost::shared_ptr<expression_literal> sptr;
-
- template <typename expr_type> static sptr make(expr_type x)
- {
- return boost::make_shared<expression_literal>(x);
- };
-
- /*! Generate the literal expression from its token string representation.
- * This includes markup, e.g. a string would still have the quotes, and
- * a hex value would still have leading 0x.
- */
- expression_literal(const std::string token_val, expression::type_t type);
-
- //! Create a boolean literal expression from a C++ bool.
- expression_literal(bool b = false);
- //! Create an integer literal expression from a C++ int.
- expression_literal(int i);
- //! Create a double literal expression from a C++ double.
- expression_literal(double d);
- //! Create a string literal expression from a C++ string.
- expression_literal(const std::string& s);
- //! Create an int vector literal expression from a C++ vector<int>.
- expression_literal(std::vector<int> v);
-
- virtual ~expression_literal() {}
-
- expression::type_t infer_type() const
- {
- return _type;
- }
-
- //! Literals aren't evaluated as such, so the evaluation
- // simply returns a copy of itself.
- expression_literal eval()
- {
- return *this; // TODO make sure this is copy
- }
-
- /*! A 'type cast' to bool. Cast rules are similar to most
- * scripting languages:
- * - Integers and doubles are false if zero, true otherwise
- * - Strings are false if empty, true otherwise
- * - Vectors are false if empty, true otherwise
- */
- bool to_bool() const;
-
- /*! Convenience function to typecast to C++ int
- *
- * Note that the current type must be TYPE_INT.
- *
- * \return C++ int representation of current literal
- * \throws uhd::type_error if type didn't match
- */
- int get_int() const;
-
- /*! Convenience function to typecast to C++ double
- *
- * Note that the current type must be TYPE_DOUBLE.
- *
- * \return C++ double representation of current literal
- * \throws uhd::type_error if type didn't match
- */
- double get_double() const;
-
- /*! Convenience function to typecast to C++ std::string.
- *
- * Note that the current type must be TYPE_STRING.
- *
- * \return String representation of current literal.
- * \throws uhd::type_error if type didn't match.
- */
- std::string get_string() const;
-
- /*! Convenience function to typecast to C++ int vector.
- *
- * Note that the current type must be TYPE_INT_VECTOR.
- *
- * \return String representation of current literal.
- * \throws uhd::type_error if type didn't match.
- */
- std::vector<int> get_int_vector() const;
-
- /*! Convenience function to typecast to C++ bool.
- *
- * Note that the current type must be TYPE_BOOL.
- * See also expression_literal::to_bool() for a type-cast
- * style function.
- *
- * \return bool representation of current literal.
- * \throws uhd::type_error if type didn't match.
- */
- bool get_bool() const;
-
- //! String representation
- std::string repr() const;
-
- bool operator==(const expression_literal& rhs) const;
-
-private:
- //! For TYPE_BOOL
- bool _bool_val;
-
- //! For TYPE_INT
- int _int_val;
-
- //! For TYPE_DOUBLE
- double _double_val;
-
- //! For TYPE_INT_VECTOR
- std::vector<int> _int_vector_val;
-
- //! Store the token value
- std::string _val;
-
- //! Current expression type
- expression::type_t _type;
-};
-
-UHD_INLINE std::ostream& operator<<(std::ostream& out, const expression_literal& l)
-{
- out << l.repr();
- return out;
-}
-
-UHD_INLINE std::ostream& operator<<(std::ostream& out, const expression_literal::sptr& l)
-{
- out << l->repr();
- return out;
-}
-
-/*! Contains multiple (sub-)expressions.
- */
-class expression_container : public expression
-{
-public:
- typedef boost::shared_ptr<expression_container> sptr;
- typedef std::vector<expression::sptr> expr_list_type;
-
- //! Return an sptr to an empty container
- static sptr make();
-
- //! List of valid combination types (see expression_container::eval()).
- enum combiner_type { COMBINE_ALL, COMBINE_AND, COMBINE_OR, COMBINE_NOTSET };
-
- //! Create an empty container
- expression_container() : _combiner(COMBINE_NOTSET){};
- virtual ~expression_container() {}
-
- /*! Type-deduction rules for containers are:
- * - If the combination type is COMBINE_ALL or COMBINE_AND,
- * return value must be TYPE_BOOL
- * - In all other cases, we return the last expression return
- * value, and hence its type is relevant
- */
- expression::type_t infer_type() const;
-
- /*! Add another expression container to this container.
- */
- virtual void add(expression::sptr new_expr);
-
- virtual bool empty() const;
-
- void set_combiner_safe(const combiner_type c);
-
- void set_combiner(const combiner_type c)
- {
- _combiner = c;
- };
-
- combiner_type get_combiner() const
- {
- return _combiner;
- };
-
- /*! Evaluate a container by evaluating its sub-expressions.
- *
- * If a container contains multiple sub-expressions, the rules
- * for evaluating them depend on the combiner_type:
- * - COMBINE_ALL: Run all the sub-expressions and return the last
- * expression's return value
- * - COMBINE_AND: Run sub-expressions, in order, until one of them
- * returns false. Following expressions are not evaluated (like
- * most C++ compilers).
- * - COMBINE_OR: Run sub-expressions, in order, until one of them
- * returns true. Following expressions are not evaluated.
- *
- * In the special case where no sub-expressions are contained, always
- * returns true.
- */
- virtual expression_literal eval();
-
-protected:
- //! Store all the sub-expressions, in order
- expr_list_type _sub_exprs;
- combiner_type _combiner;
-};
-
-// Forward declaration:
-class function_table;
-/*! A function call is a special type of container.
- *
- * All arguments are sub-expressions. The combiner type is
- * always COMBINE_ALL in this case (changing the combiner type
- * does not affect anything).
- *
- * The actual function maps to a C++ function available through
- * a uhd::rfnoc::nocscript::function_table object.
- *
- * The recommended to use this is:
- * 1. Create a function object giving its name (e.g. ADD)
- * 2. Use the add() method to add all the function arguments
- * in the right order (left to right).
- * 3. Once step 2 is complete, the function object can be used.
- * Call infer_type() to get the return value, if required.
- * 4. Calling eval() will call into the function table. The
- * argument expressions are evaluated, if so required, inside
- * the function (lazy evalulation). Functions do not need
- * to evaluate arguments.
- */
-class expression_function : public expression_container
-{
-public:
- typedef boost::shared_ptr<expression_function> sptr;
- typedef std::vector<expression::type_t> argtype_list_type;
-
- //! Return an sptr to a function object without args
- static sptr make(
- const std::string& name, const boost::shared_ptr<function_table> func_table);
-
- static std::string to_string(const std::string& name, const argtype_list_type& types);
-
- expression_function(
- const std::string& name, const boost::shared_ptr<function_table> func_table);
- ~expression_function() {}
-
- //! Add an argument expression
- virtual void add(expression::sptr new_expr);
-
- /*! Looks up the function type in the function table.
- *
- * Note that this will only work after all arguments have been
- * added, as they are also used to look up a function's type in the
- * function table.
- */
- expression::type_t infer_type() const;
-
- /*! Evaluate all arguments, then the function itself.
- */
- expression_literal eval();
-
- //! String representation
- std::string repr() const;
-
-private:
- std::string _name;
- const boost::shared_ptr<function_table> _func_table;
- std::vector<expression::type_t> _arg_types;
-};
-
-
-/*! Variable expression
- *
- * Variables are like literals, only their type and value aren't known
- * at parse-time. Instead, we provide a function object to look up
- * variable's types and value.
- */
-class expression_variable : public expression
-{
-public:
- typedef boost::shared_ptr<expression_variable> sptr;
- typedef boost::function<expression::type_t(const std::string&)> type_getter_type;
- typedef boost::function<expression_literal(const std::string&)> value_getter_type;
-
- static sptr make(const std::string& token_val,
- type_getter_type type_getter,
- value_getter_type value_getter);
-
- /*! Create a variable object from its token value
- * (e.g. '$spp', i.e. including the '$' symbol). The variable
- * does not have to exist at this point.
- */
- expression_variable(const std::string& token_val,
- type_getter_type type_getter,
- value_getter_type value_getter);
-
- virtual ~expression_variable() {}
-
- /*! Looks up the variable type in the variable table.
- *
- * \throws Depending on \p type_getter, this may throw when the variable does not
- * exist. Recommended behaviour is to throw uhd::syntax_error.
- */
- expression::type_t infer_type() const;
-
- /*! Look up a variable's value in the variable table.
- *
- * \throws Depending on \p value_getter, this may throw when the variable does not
- * exist. Recommended behaviour is to throw uhd::syntax_error.
- */
- expression_literal eval();
-
-private:
- std::string _varname;
- type_getter_type _type_getter;
- value_getter_type _value_getter;
-};
-
-}}} /* namespace uhd::rfnoc::nocscript */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_EXPR_HPP */
diff --git a/host/lib/rfnoc/nocscript/function_table.cpp b/host/lib/rfnoc/nocscript/function_table.cpp
deleted file mode 100644
index 57e32363d..000000000
--- a/host/lib/rfnoc/nocscript/function_table.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "function_table.hpp"
-#include "basic_functions.hpp"
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <map>
-
-using namespace uhd::rfnoc::nocscript;
-
-class function_table_impl : public function_table
-{
-public:
- struct function_info
- {
- expression::type_t return_type;
- function_ptr function;
-
- function_info() : return_type(expression::TYPE_INT){};
- function_info(
- const expression::type_t return_type_, const function_ptr& function_)
- : return_type(return_type_), function(function_){};
- };
- // Should be an unordered_map... sigh, we'll get to C++11 someday.
- typedef std::map<std::string,
- std::map<expression_function::argtype_list_type, function_info>>
- table_type;
-
- /************************************************************************
- * Structors
- ***********************************************************************/
- function_table_impl()
- {
- _REGISTER_ALL_FUNCS();
- }
-
- ~function_table_impl(){};
-
-
- /************************************************************************
- * Interface implementation
- ***********************************************************************/
- bool function_exists(const std::string& name) const
- {
- return bool(_table.count(name));
- }
-
- bool function_exists(const std::string& name,
- const expression_function::argtype_list_type& arg_types) const
- {
- table_type::const_iterator it = _table.find(name);
- return (it != _table.end()) and bool(it->second.count(arg_types));
- }
-
- expression::type_t get_type(const std::string& name,
- const expression_function::argtype_list_type& arg_types) const
- {
- table_type::const_iterator it = _table.find(name);
- if (it == _table.end() or (it->second.find(arg_types) == it->second.end())) {
- throw uhd::syntax_error(
- str(boost::format("Unable to retrieve return value for function %s")
- % expression_function::to_string(name, arg_types)));
- }
- return it->second.find(arg_types)->second.return_type;
- }
-
- expression_literal eval(const std::string& name,
- const expression_function::argtype_list_type& arg_types,
- expression_container::expr_list_type& arguments)
- {
- if (not function_exists(name, arg_types)) {
- throw uhd::syntax_error(
- str(boost::format("Cannot eval() function %s, not a known signature")
- % expression_function::to_string(name, arg_types)));
- }
-
- return _table[name][arg_types].function(arguments);
- }
-
- void register_function(const std::string& name,
- const function_table::function_ptr& ptr,
- const expression::type_t return_type,
- const expression_function::argtype_list_type& sig)
- {
- _table[name][sig] = function_info(return_type, ptr);
- }
-
-private:
- table_type _table;
-};
-
-function_table::sptr function_table::make()
-{
- return sptr(new function_table_impl());
-}
diff --git a/host/lib/rfnoc/nocscript/function_table.hpp b/host/lib/rfnoc/nocscript/function_table.hpp
deleted file mode 100644
index 63125ab1b..000000000
--- a/host/lib/rfnoc/nocscript/function_table.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "expression.hpp"
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP
-# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP
-
-namespace uhd { namespace rfnoc { namespace nocscript {
-
-class function_table
-{
-public:
- typedef boost::shared_ptr<function_table> sptr;
- typedef boost::function<expression_literal(expression_container::expr_list_type&)>
- function_ptr;
-
- static sptr make();
- virtual ~function_table(){};
-
- /*! Check if any function with a given name exists
- *
- * \returns True, if any function with name \p name is registered.
- */
- virtual bool function_exists(const std::string& name) const = 0;
-
- /*! Check if a function with a given name and list of argument types exists
- *
- * \returns True, if such a function is registered.
- */
- virtual bool function_exists(const std::string& name,
- const expression_function::argtype_list_type& arg_types) const = 0;
-
- /*! Get the return type of a function with given name and argument type list
- *
- * \returns The function's return type
- * \throws uhd::syntax_error if no such function is registered
- */
- virtual expression::type_t get_type(const std::string& name,
- const expression_function::argtype_list_type& arg_types) const = 0;
-
- /*! Calls the function \p name with the argument list \p arguments
- *
- * \param arg_types A list of types for each argument
- * \param arguments An expression list of the arguments
- * \returns The return value of the called function
- * \throws uhd::syntax_error if no such function is found
- */
- virtual expression_literal eval(const std::string& name,
- const expression_function::argtype_list_type& arg_types,
- expression_container::expr_list_type& arguments) = 0;
-
- /*! Register a new function
- *
- * \param name Name of the function (e.g. 'ADD')
- * \param ptr Function object
- * \param return_type The function's return value
- * \param sig The function signature (list of argument types)
- */
- virtual void register_function(const std::string& name,
- const function_ptr& ptr,
- const expression::type_t return_type,
- const expression_function::argtype_list_type& sig) = 0;
-};
-
-}}} /* namespace uhd::rfnoc::nocscript */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_FUNCTABLE_HPP */
diff --git a/host/lib/rfnoc/nocscript/gen_basic_funcs.py b/host/lib/rfnoc/nocscript/gen_basic_funcs.py
deleted file mode 100755
index fec6b04ad..000000000
--- a/host/lib/rfnoc/nocscript/gen_basic_funcs.py
+++ /dev/null
@@ -1,465 +0,0 @@
-#!/usr/bin/env python
-"""
-Generate the function list for the basic NocScript functions
-"""
-
-import re
-import os
-import sys
-from mako.template import Template
-
-#############################################################################
-# This is the interesting part: Add new functions in here
-#
-# Notes:
-# - Lines starting with # are considered comments, and will be removed from
-# the output
-# - C++ comments will be copied onto the generated file if inside functions
-# - Docstrings start with //! and are required
-# - Function signature is RETURN_TYPE NAME(ARG_TYPE1, ARG_TYPE2, ...)
-# - Function body is valid C++
-# - If your function requires special includes, put them in INCLUDE_LIST
-# - End of functions is delimited by s/^}/, so take care with the indents!
-# - Use these substitutions:
-# - ${RETURN}(...): Create a valid return value
-# - ${args[n]}: Access the n-th argument
-#
-INCLUDE_LIST = """
-#include <boost/math/special_functions/round.hpp>
-#include <chrono>
-#include <thread>
-"""
-FUNCTION_LIST = """
-CATEGORY: Math Functions
-//! Returns x + y
-INT ADD(INT, INT)
-{
- ${RETURN}(${args[0]} + ${args[1]});
-}
-
-//! Returns x + y
-DOUBLE ADD(DOUBLE, DOUBLE)
-{
- ${RETURN}(${args[0]} + ${args[1]});
-}
-
-//! Returns x * y
-DOUBLE MULT(DOUBLE, DOUBLE)
-{
- ${RETURN}(${args[0]} * ${args[1]});
-}
-
-//! Returns x * y
-INT MULT(INT, INT)
-{
- ${RETURN}(${args[0]} * ${args[1]});
-}
-
-//! Returns x / y
-DOUBLE DIV(DOUBLE, DOUBLE)
-{
- ${RETURN}(${args[0]} / ${args[1]});
-}
-
-//! Returns true if x <= y (Less or Equal)
-BOOL LE(INT, INT)
-{
- ${RETURN}(bool(${args[0]} <= ${args[1]}));
-}
-
-//! Returns true if x <= y (Less or Equal)
-BOOL LE(DOUBLE, DOUBLE)
-{
- ${RETURN}(bool(${args[0]} <= ${args[1]}));
-}
-
-//! Returns true if x >= y (Greater or Equal)
-BOOL GE(INT, INT)
-{
- ${RETURN}(bool(${args[0]} >= ${args[1]}));
-}
-
-//! Returns true if x >= y (Greater or Equal)
-BOOL GE(DOUBLE, DOUBLE)
-{
- ${RETURN}(bool(${args[0]} >= ${args[1]}));
-}
-
-//! Returns true if x < y (Less Than)
-BOOL LT(INT, INT)
-{
- ${RETURN}(bool(${args[0]} < ${args[1]}));
-}
-
-//! Returns true if x > y (Greater Than)
-BOOL GT(INT, INT)
-{
- ${RETURN}(bool(${args[0]} > ${args[1]}));
-}
-
-//! Returns true if x < y (Less Than)
-BOOL LT(DOUBLE, DOUBLE)
-{
- ${RETURN}(bool(${args[0]} < ${args[1]}));
-}
-
-//! Returns true if x > y (Greater Than)
-BOOL GT(DOUBLE, DOUBLE)
-{
- ${RETURN}(bool(${args[0]} > ${args[1]}));
-}
-
-//! Round x and return it as an integer
-INT IROUND(DOUBLE)
-{
- ${RETURN}(int(boost::math::iround(${args[0]})));
-}
-
-//! Returns true if x is a power of 2
-BOOL IS_PWR_OF_2(INT)
-{
- if (${args[0]} < 0) return ${FALSE};
- int i = ${args[0]};
- while ( (i & 1) == 0 and (i > 1) ) {
- i >>= 1;
- }
- ${RETURN}(bool(i == 1));
-}
-
-//! Returns floor(log2(x)).
-INT LOG2(INT)
-{
- if (${args[0]} < 0) {
- throw uhd::runtime_error(str(
- boost::format("In NocScript function ${func_name}: Cannot calculate log2() of negative number.")
- ));
- }
-
- int power_value = ${args[0]};
- int log2_value = 0;
- while ( (power_value & 1) == 0 and (power_value > 1) ) {
- power_value >>= 1;
- log2_value++;
- }
- ${RETURN}(log2_value);
-}
-
-//! Returns x % y
-INT MODULO(INT, INT)
-{
- ${RETURN}(${args[0]} % ${args[1]});
-}
-
-//! Returns true if x == y
-BOOL EQUAL(INT, INT)
-{
- ${RETURN}(bool(${args[0]} == ${args[1]}));
-}
-
-//! Returns true if x == y
-BOOL EQUAL(DOUBLE, DOUBLE)
-{
- ${RETURN}(bool(${args[0]} == ${args[1]}));
-}
-
-//! Returns true if x == y
-BOOL EQUAL(STRING, STRING)
-{
- ${RETURN}(bool(${args[0]} == ${args[1]}));
-}
-
-CATEGORY: Bitwise Operations
-//! Returns x >> y
-INT SHIFT_RIGHT(INT, INT)
-{
- ${RETURN}(${args[0]} >> ${args[1]});
-}
-
-//! Returns x << y
-INT SHIFT_LEFT(INT, INT)
-{
- ${RETURN}(${args[0]} << ${args[1]});
-}
-
-//! Returns x & y
-INT BITWISE_AND(INT, INT)
-{
- ${RETURN}(${args[0]} & ${args[1]});
-}
-
-//! Returns x | y
-INT BITWISE_OR(INT, INT)
-{
- ${RETURN}(${args[0]} | ${args[1]});
-}
-
-//! Returns x ^ y
-INT BITWISE_XOR(INT, INT)
-{
- ${RETURN}(${args[0]} ^ ${args[1]});
-}
-
-CATEGORY: Boolean Logic
-//! Returns x xor y.
-BOOL XOR(BOOL, BOOL)
-{
- ${RETURN}(${args[0]} xor ${args[1]});
-}
-
-//! Returns !x
-BOOL NOT(BOOL)
-{
- ${RETURN}(not ${args[0]});
-}
-
-//! Always returns true
-BOOL TRUE()
-{
- return ${TRUE};
-}
-
-//! Always returns false
-BOOL FALSE()
-{
- return ${FALSE};
-}
-
-CATEGORY: Conditional Execution
-//! Executes x, if true, execute y. Returns true if x is true.
-BOOL IF(BOOL, BOOL)
-{
- if (${args[0]}) {
- ${args[1]};
- ${RETURN}(true);
- }
- ${RETURN}(false);
-}
-
-//! Executes x, if true, execute y, otherwise, execute z. Returns true if x is true.
-BOOL IF_ELSE(BOOL, BOOL, BOOL)
-{
- if (${args[0]}) {
- ${args[1]};
- ${RETURN}(true);
- } else {
- ${args[2]};
- }
- ${RETURN}(false);
-}
-
-CATEGORY: Execution Control
-//! Sleep for x seconds. Fractions are allowed. Millisecond accuracy.
-BOOL SLEEP(DOUBLE)
-{
- int ms = ${args[0]} / 1000;
- std::this_thread::sleep_for(std::chrono::milliseconds(ms));
- ${RETURN}(true);
-}
-"""
-# End of interesting part. The rest will take this and turn into a C++
-# header file.
-#############################################################################
-
-HEADER = """<% import time %>//
-///////////////////////////////////////////////////////////////////////
-// This file was generated by ${file} on ${time.strftime("%c")}
-///////////////////////////////////////////////////////////////////////
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-/****************************************************************************
- * This file is autogenerated! Any manual changes in here will be
- * overwritten by calling nocscript_gen_basic_funcs.py!
- ***************************************************************************/
-
-#include "expression.hpp"
-#include "function_table.hpp"
-#include <uhd/exception.hpp>
-#include <boost/format.hpp>
-#include <boost/assign/list_of.hpp>
-${INCLUDE_LIST}
-
-#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP
-#define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP
-
-namespace uhd { namespace rfnoc { namespace nocscript {
-"""
-
-# Not a Mako template:
-FOOTER="""
-}}} /* namespace uhd::rfnoc::nocscript */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_BASICFUNCS_HPP */
-"""
-
-# Not a Mako template:
-FUNC_TEMPLATE = """
-expression_literal {NAME}(expression_container::expr_list_type &{ARGS})
-{BODY}
-"""
-
-REGISTER_MACRO_TEMPLATE = """#define _REGISTER_ALL_FUNCS()${registry}
-"""
-
-REGISTER_COMMANDS_TEMPLATE = """
- % if len(arglist):
- expression_function::argtype_list_type ${func_name}_args = boost::assign::list_of
- % for this_type in arglist:
- (expression::TYPE_${this_type})
- % endfor
- ;
- % else:
- expression_function::argtype_list_type ${func_name}_args;
- % endif
- register_function(
- "${name}",
- boost::bind(&${func_name}, _1),
- expression::TYPE_${retval},
- ${func_name}_args
- );"""
-
-DOXY_TEMPLATE = """/*! \page page_nocscript_funcs NocScript Function Reference
-% for cat, func_by_name in func_list_tree.items():
-- ${cat}
-% for func_name, func_info_list in func_by_name.items():
- - ${func_name}: ${func_info_list[0]['docstring']}
-% for func_info in func_info_list:
- - ${func_info['arglist']} -> ${func_info['retval']}
-% endfor
-% endfor
-% endfor
-
-*/
-"""
-
-def parse_tmpl(_tmpl_text, **kwargs):
- return Template(_tmpl_text).render(**kwargs)
-
-def make_cxx_func_name(func_dict):
- """
- Creates a unique C++ function name from a function description
- """
- return "{name}__{retval}__{arglist}".format(
- name=func_dict['name'],
- retval=func_dict['retval'],
- arglist="_".join(func_dict['arglist'])
- )
-
-def make_cxx_func_body(func_dict):
- """
- Formats the function body properly
- """
- type_lookup_methods = {
- 'INT': 'get_int',
- 'DOUBLE': 'get_double',
- 'BOOL': 'get_bool',
- 'STRING': 'get_string',
- }
- args_lookup = []
- for idx, arg_type in enumerate(func_dict['arglist']):
- args_lookup.append("args[{idx}]->eval().{getter}()".format(idx=idx, getter=type_lookup_methods[arg_type]))
- return parse_tmpl(
- func_dict['body'],
- args=args_lookup,
- FALSE='expression_literal(false)',
- TRUE='expression_literal(true)',
- RETURN='return expression_literal',
- **func_dict
- )
-
-def prep_function_list():
- """
- - Remove all comments
- - Split the function list into individual functions
- - Split the functions into return value, name, argument list and body
- """
- comment_remove_re = re.compile(r'^\s*#.*$', flags=re.MULTILINE)
- func_list_wo_comments = comment_remove_re.sub('', FUNCTION_LIST)
- func_splitter_re = re.compile(r'(?<=^})\s*$', flags=re.MULTILINE)
- func_list_split = func_splitter_re.split(func_list_wo_comments)
- func_list_split = [x.strip() for x in func_list_split if len(x.strip())]
- func_list = []
- last_category = ''
- for func in func_list_split:
- split_regex = r'(^CATEGORY: (?P<cat>[^\n]*)\s*)?' \
- r'//!(?P<docstring>[^\n]*)\s*' + \
- r'(?P<retval>[A-Z][A-Z0-9_]*)\s+' + \
- r'(?P<funcname>[A-Z][A-Z0-9_]*)\s*\((?P<arglist>[^\)]*)\)\s*' + \
- r'(?P<funcbody>^{.*)'
- split_re = re.compile(split_regex, flags=re.MULTILINE|re.DOTALL)
- mo = split_re.match(func)
- if mo.group('cat'):
- last_category = mo.group('cat').strip()
- func_dict = {
- 'docstring': mo.group('docstring').strip(),
- 'name': mo.group('funcname'),
- 'retval': mo.group('retval'),
- 'arglist': [x.strip() for x in mo.group('arglist').split(',') if len(x.strip())],
- 'body': mo.group('funcbody'),
- 'category': last_category,
- }
- func_dict['func_name'] = make_cxx_func_name(func_dict)
- func_list.append(func_dict)
- return func_list
-
-def write_function_header(output_filename):
- """
- Create the .hpp file that defines all the NocScript functions in C++.
- """
- func_list = prep_function_list()
- # Step 1: Write the prototypes
- func_prototypes = ''
- registry_commands = ''
- for func in func_list:
- func_prototypes += FUNC_TEMPLATE.format(
- NAME=func['func_name'],
- BODY=make_cxx_func_body(func),
- ARGS="args" if len(func['arglist']) else ""
- )
- registry_commands += parse_tmpl(
- REGISTER_COMMANDS_TEMPLATE,
- **func
- )
- # Step 2: Write the registry process
- register_func = parse_tmpl(REGISTER_MACRO_TEMPLATE, registry=registry_commands)
- register_func = register_func.replace('\n', ' \\\n')
-
- # Final step: Join parts and write to file
- full_file = "\n".join((
- parse_tmpl(HEADER, file = os.path.basename(__file__), INCLUDE_LIST=INCLUDE_LIST),
- func_prototypes,
- register_func,
- FOOTER,
- ))
- open(output_filename, 'w').write(full_file)
-
-def write_manual_file(output_filename):
- """
- Write the Doxygen file for the NocScript functions.
- """
- func_list = prep_function_list()
- func_list_tree = {}
- for func in func_list:
- if func['category'] not in func_list_tree:
- func_list_tree[func['category']] = {}
- if func['name'] not in func_list_tree[func['category']]:
- func_list_tree[func['category']][func['name']] = []
- func_list_tree[func['category']][func['name']].append(func)
- open(output_filename, 'w').write(parse_tmpl(DOXY_TEMPLATE, func_list_tree=func_list_tree))
-
-
-def main():
- if len(sys.argv) < 2:
- print("No output file specified!")
- exit(1)
- outfile = sys.argv[1]
- if os.path.splitext(outfile)[1] == '.dox':
- write_manual_file(outfile)
- else:
- write_function_header(outfile)
-
-if __name__ == "__main__":
- main()
diff --git a/host/lib/rfnoc/nocscript/parser.cpp b/host/lib/rfnoc/nocscript/parser.cpp
deleted file mode 100644
index 8ef1b7f44..000000000
--- a/host/lib/rfnoc/nocscript/parser.cpp
+++ /dev/null
@@ -1,357 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "parser.hpp"
-#include <uhd/utils/cast.hpp>
-#include <boost/assign.hpp>
-#include <boost/bind.hpp>
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/spirit/include/lex_lexertl.hpp>
-#include <sstream>
-#include <stack>
-
-using namespace uhd::rfnoc::nocscript;
-namespace lex = boost::spirit::lex;
-
-class parser_impl : public parser
-{
-public:
- /******************************************************************
- * Structors TODO make them protected
- *****************************************************************/
- parser_impl(function_table::sptr ftable,
- expression_variable::type_getter_type var_type_getter,
- expression_variable::value_getter_type var_value_getter)
- : _ftable(ftable)
- , _var_type_getter(var_type_getter)
- , _var_value_getter(var_value_getter)
- {
- // nop
- }
-
- virtual ~parser_impl() {}
-
-
- /******************************************************************
- * Parsing
- *****************************************************************/
- //! List of parser tokens
- enum token_ids {
- ID_WHITESPACE = lex::min_token_id + 42,
- ID_KEYWORD,
- ID_ARG_SEP,
- ID_PARENS_OPEN,
- ID_PARENS_CLOSE,
- ID_VARIABLE,
- ID_LITERAL_DOUBLE,
- ID_LITERAL_INT,
- ID_LITERAL_HEX,
- ID_LITERAL_STR,
- ID_LITERAL_VECTOR_INT
- };
-
- //! The Lexer object used for NocScript
- template <typename Lexer> struct ns_lexer : lex::lexer<Lexer>
- {
- ns_lexer()
- {
- this->self.add("\\s+", ID_WHITESPACE)(",", ID_ARG_SEP)(
- "[A-Z][A-Z0-9_]*", ID_KEYWORD)("\\(", ID_PARENS_OPEN)(
- "\\)", ID_PARENS_CLOSE)("\\$[a-z][a-z0-9_]*", ID_VARIABLE)(
- "-?\\d+\\.\\d+", ID_LITERAL_DOUBLE)("-?\\d+", ID_LITERAL_INT)(
- "0x[0-9A-F]+", ID_LITERAL_HEX)("\\\"[^\\\"]*\\\"", ID_LITERAL_STR)(
- "'[^']*'", ID_LITERAL_STR) // both work
- ("\\[[0-9]\\]", ID_LITERAL_VECTOR_INT);
- }
- };
-
-private:
- struct grammar_props
- {
- function_table::sptr ftable;
- expression_variable::type_getter_type var_type_getter;
- expression_variable::value_getter_type var_value_getter;
-
- //! Store the last keyword
- std::string function_name;
- std::string error;
- std::stack<expression_container::sptr> expr_stack;
-
- grammar_props(function_table::sptr ftable_,
- expression_variable::type_getter_type var_type_getter_,
- expression_variable::value_getter_type var_value_getter_)
- : ftable(ftable_)
- , var_type_getter(var_type_getter_)
- , var_value_getter(var_value_getter_)
- , function_name("")
- {
- UHD_ASSERT_THROW(expr_stack.empty());
- // Push an empty container to the stack to hold the result
- expr_stack.push(expression_container::make());
- }
-
- expression::sptr get_result()
- {
- UHD_ASSERT_THROW(expr_stack.size() == 1);
- return expr_stack.top();
- }
- };
-
- //! This isn't strictly a grammar, as it also includes semantic
- // actions etc. I'm not going to spend ages thinking of a better
- // name at this point.
- struct grammar
- {
- // Implementation detail specific to boost::bind (see Boost::Spirit
- // examples)
- typedef bool result_type;
-
- static const int VALID_COMMA = 0x1;
- static const int VALID_PARENS_OPEN = 0x2;
- static const int VALID_PARENS_CLOSE = 0x4;
- static const int VALID_EXPRESSION = 0x8 + 0x02;
- static const int VALID_OPERATOR = 0x10;
-
- // !This function operator gets called for each of the matched tokens.
- template <typename Token>
- bool operator()(Token const& t, grammar_props& P, int& next_valid_state) const
- {
- //! This is totally not how Boost::Spirit is meant to be used,
- // as there's token types etc. But for now let's just convert
- // every token to a string, and then handle it as such.
- std::stringstream sstr;
- sstr << t.value();
- std::string val = sstr.str();
- // std::cout << "VAL: " << val << std::endl;
- // std::cout << "Next valid states:\n"
- //<< boost::format("VALID_COMMA [%s]\n") % ((next_valid_state & 0x1) ?
- //"x" : " ")
- //<< boost::format("VALID_PARENS_OPEN [%s]\n") % ((next_valid_state & 0x2) ?
- //"x" : " ")
- //<< boost::format("VALID_PARENS_CLOSE [%s]\n") % ((next_valid_state & 0x4) ?
- //"x" : " ")
- //<< boost::format("VALID_EXPRESSION [%s]\n") % ((next_valid_state & (0x8 +
- //0x02)) ? "x" : " ")
- //<< boost::format("VALID_OPERATOR [%s]\n") % ((next_valid_state & 0x10)
- //? "x" : " ")
- //<< std::endl;
-
- switch (t.id()) {
- case ID_WHITESPACE:
- // Ignore
- break;
-
- case ID_KEYWORD:
- // Ambiguous, could be an operator (AND, OR) or a function name (ADD,
- // MULT...). So first, check which it is:
- if (val == "AND" or val == "OR") {
- if (not(next_valid_state & VALID_OPERATOR)) {
- P.error = str(boost::format("Unexpected operator: %s") % val);
- return false;
- }
- next_valid_state = VALID_EXPRESSION;
- try {
- if (val == "AND") {
- P.expr_stack.top()->set_combiner_safe(
- expression_container::COMBINE_AND);
- } else if (val == "OR") {
- P.expr_stack.top()->set_combiner_safe(
- expression_container::COMBINE_OR);
- }
- } catch (const uhd::syntax_error&) {
- P.error = str(boost::format("Operator %s is mixing operator "
- "types within this container.")
- % val);
- }
- // Right now, we can't have multiple operator types within a
- // container. We might be able to change that, if there's enough
- // demand. Either we keep track of multiple operators, or we open
- // a new container. In the latter case, we'd need a way of keeping
- // track of those containers, so it's a bit tricky.
- break;
- }
- // If it's not a keyword, it has to be a function, so check the
- // function table:
- if (not(next_valid_state & VALID_EXPRESSION)) {
- P.error = str(boost::format("Unexpected expression: %s") % val);
- return false;
- }
- if (not P.ftable->function_exists(val)) {
- P.error = str(boost::format("Unknown function: %s") % val);
- return false;
- }
- P.function_name = val;
- next_valid_state = VALID_PARENS_OPEN;
- break;
-
- // Every () creates a new container, either a raw container or
- // a function.
- case ID_PARENS_OPEN:
- if (not(next_valid_state & VALID_PARENS_OPEN)) {
- P.error = str(boost::format("Unexpected parentheses."));
- return false;
- }
- if (not P.function_name.empty()) {
- // We've already checked the function name exists
- P.expr_stack.push(
- expression_function::make(P.function_name, P.ftable));
- P.function_name.clear();
- } else {
- P.expr_stack.push(expression_container::make());
- }
- // Push another empty container to hold the first element/argument
- // in this container:
- P.expr_stack.push(expression_container::make());
- next_valid_state = VALID_EXPRESSION | VALID_PARENS_CLOSE;
- break;
-
- case ID_PARENS_CLOSE: {
- if (not(next_valid_state & VALID_PARENS_CLOSE)) {
- P.error = str(boost::format("Unexpected parentheses."));
- return false;
- }
- if (P.expr_stack.size() < 2) {
- P.error = str(boost::format("Unbalanced closing parentheses."));
- return false;
- }
- // First pop the last expression inside the parentheses,
- // if it's not empty, add it to the top container (this also avoids
- // adding arguments to functions if none were provided):
- expression_container::sptr c = P.expr_stack.top();
- P.expr_stack.pop();
- if (not c->empty()) {
- P.expr_stack.top()->add(c);
- }
- // At the end of (), either a function or container is complete,
- // so pop that and add it to its top container:
- expression_container::sptr c2 = P.expr_stack.top();
- P.expr_stack.pop();
- P.expr_stack.top()->add(c2);
- next_valid_state = VALID_OPERATOR | VALID_COMMA | VALID_PARENS_CLOSE;
- } break;
-
- case ID_ARG_SEP: {
- if (not(next_valid_state & VALID_COMMA)) {
- P.error = str(boost::format("Unexpected comma."));
- return false;
- }
- next_valid_state = VALID_EXPRESSION;
- // If stack size is 1, we're on the base container, which means we
- // simply string stuff.
- if (P.expr_stack.size() == 1) {
- break;
- }
- // Otherwise, a ',' always means we add the previous expression to
- // the current container:
- expression_container::sptr c = P.expr_stack.top();
- P.expr_stack.pop();
- P.expr_stack.top()->add(c);
- // It also means another expression is following, so create another
- // empty container for that:
- P.expr_stack.push(expression_container::make());
- } break;
-
- // All the atomic expressions just get added to the current container:
-
- case ID_VARIABLE: {
- if (not(next_valid_state & VALID_EXPRESSION)) {
- P.error = str(boost::format("Unexpected expression."));
- return false;
- }
- expression_variable::sptr v = expression_variable::make(
- val, P.var_type_getter, P.var_value_getter);
- P.expr_stack.top()->add(v);
- next_valid_state = VALID_OPERATOR | VALID_COMMA | VALID_PARENS_CLOSE;
- } break;
-
- default:
- // If we get here, we assume it's a literal expression
- {
- if (not(next_valid_state & VALID_EXPRESSION)) {
- P.error = str(boost::format("Unexpected expression."));
- return false;
- }
- expression::type_t token_type;
- switch (t.id()) { // A map lookup would be more elegant, but we'd
- // need a nicer C++ for that
- case ID_LITERAL_DOUBLE:
- token_type = expression::TYPE_DOUBLE;
- break;
- case ID_LITERAL_INT:
- token_type = expression::TYPE_INT;
- break;
- case ID_LITERAL_HEX:
- token_type = expression::TYPE_INT;
- break;
- case ID_LITERAL_STR:
- token_type = expression::TYPE_STRING;
- break;
- case ID_LITERAL_VECTOR_INT:
- token_type = expression::TYPE_INT_VECTOR;
- break;
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
- P.expr_stack.top()->add(
- boost::make_shared<expression_literal>(val, token_type));
- next_valid_state = VALID_OPERATOR | VALID_COMMA
- | VALID_PARENS_CLOSE;
- break;
- }
-
- } // end switch
- return true;
- }
- };
-
-public:
- expression::sptr create_expr_tree(const std::string& code)
- {
- // Create empty stack and keyword states
- grammar_props P(_ftable, _var_type_getter, _var_value_getter);
- int next_valid_state = grammar::VALID_EXPRESSION;
-
- // Create a lexer instance
- ns_lexer<lex::lexertl::lexer<>> lexer_functor;
-
- // Tokenize the string
- char const* first = code.c_str();
- char const* last = &first[code.size()];
- bool r = lex::tokenize(first,
- last, // Iterators
- lexer_functor, // Lexer
- boost::bind(grammar(),
- _1,
- boost::ref(P),
- boost::ref(next_valid_state)) // Function object
- );
-
- // Check the parsing worked:
- if (not r or P.expr_stack.size() != 1) {
- std::string rest(first, last);
- throw uhd::syntax_error(
- str(boost::format("Parsing stopped at: %s\nError message: %s") % rest
- % P.error));
- }
-
- // Clear stack and return result
- return P.get_result();
- }
-
-private:
- function_table::sptr _ftable;
- expression_variable::type_getter_type _var_type_getter;
- expression_variable::value_getter_type _var_value_getter;
-};
-
-parser::sptr parser::make(function_table::sptr ftable,
- expression_variable::type_getter_type var_type_getter,
- expression_variable::value_getter_type var_value_getter)
-{
- return sptr(new parser_impl(ftable, var_type_getter, var_value_getter));
-}
diff --git a/host/lib/rfnoc/nocscript/parser.hpp b/host/lib/rfnoc/nocscript/parser.hpp
deleted file mode 100644
index e9d9f0820..000000000
--- a/host/lib/rfnoc/nocscript/parser.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright 2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "expression.hpp"
-#include "function_table.hpp"
-#include <boost/shared_ptr.hpp>
-
-#ifndef INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP
-# define INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP
-
-namespace uhd { namespace rfnoc { namespace nocscript {
-
-class parser
-{
-public:
- typedef boost::shared_ptr<parser> sptr;
-
- static sptr make(function_table::sptr ftable,
- expression_variable::type_getter_type var_type_getter,
- expression_variable::value_getter_type var_value_getter);
-
- /*! The main parsing call: Turn a string of code into an expression tree.
- *
- * Evaluating the returned object will execute the code.
- *
- * \throws uhd::syntax_error if \p code contains syntax errors
- */
- virtual expression::sptr create_expr_tree(const std::string& code) = 0;
-};
-
-}}} /* namespace uhd::rfnoc::nocscript */
-
-#endif /* INCLUDED_LIBUHD_RFNOC_NOCSCRIPT_PARSER_HPP */
diff --git a/host/lib/rfnoc/node_ctrl_base.cpp b/host/lib/rfnoc/node_ctrl_base.cpp
deleted file mode 100644
index a6ee80f8b..000000000
--- a/host/lib/rfnoc/node_ctrl_base.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/node_ctrl_base.hpp>
-#include <uhd/utils/log.hpp>
-#include <boost/range/adaptor/map.hpp>
-
-using namespace uhd::rfnoc;
-
-std::string node_ctrl_base::unique_id() const
-{
- // Most instantiations will override this, so we don't need anything
- // more elegant here.
- return str(boost::format("%08X") % size_t(this));
-}
-
-void node_ctrl_base::clear()
-{
- UHD_LOG_TRACE(unique_id(), "node_ctrl_base::clear()");
- // Reset connections:
- _upstream_nodes.clear();
- _downstream_nodes.clear();
-}
-
-void node_ctrl_base::_register_downstream_node(node_ctrl_base::sptr, size_t)
-{
- throw uhd::runtime_error(
- "Attempting to register a downstream block on a non-source node.");
-}
-
-void node_ctrl_base::_register_upstream_node(node_ctrl_base::sptr, size_t)
-{
- throw uhd::runtime_error(
- "Attempting to register an upstream block on a non-sink node.");
-}
-
-void node_ctrl_base::set_downstream_port(const size_t this_port, const size_t remote_port)
-{
- if (not _downstream_nodes.count(this_port) and remote_port != ANY_PORT) {
- throw uhd::value_error(
- str(boost::format(
- "[%s] Cannot set remote downstream port: Port %d not connected.")
- % unique_id() % this_port));
- }
- _downstream_ports[this_port] = remote_port;
-}
-
-size_t node_ctrl_base::get_downstream_port(const size_t this_port)
-{
- if (not _downstream_ports.count(this_port) or not _downstream_nodes.count(this_port)
- or _downstream_ports[this_port] == ANY_PORT) {
- throw uhd::value_error(
- str(boost::format(
- "[%s] Cannot retrieve remote downstream port: Port %d not connected.")
- % unique_id() % this_port));
- }
- return _downstream_ports[this_port];
-}
-
-void node_ctrl_base::set_upstream_port(const size_t this_port, const size_t remote_port)
-{
- if (not _upstream_nodes.count(this_port) and remote_port != ANY_PORT) {
- throw uhd::value_error(str(
- boost::format("[%s] Cannot set remote upstream port: Port %d not connected.")
- % unique_id() % this_port));
- }
- _upstream_ports[this_port] = remote_port;
-}
-
-size_t node_ctrl_base::get_upstream_port(const size_t this_port)
-{
- if (not _upstream_ports.count(this_port) or not _upstream_nodes.count(this_port)
- or _upstream_ports[this_port] == ANY_PORT) {
- throw uhd::value_error(
- str(boost::format(
- "[%s] Cannot retrieve remote upstream port: Port %d not connected.")
- % unique_id() % this_port));
- }
- return _upstream_ports[this_port];
-}
-
-void node_ctrl_base::disconnect()
-{
- // Notify neighbours:
- for (node_map_t::iterator i = _downstream_nodes.begin(); i != _downstream_nodes.end();
- ++i) {
- sptr downstream_node = i->second.lock();
- if (not downstream_node) {
- // Actually this is not OK
- continue;
- }
- downstream_node->disconnect_input_port(_downstream_ports[i->first]);
- }
- for (node_map_t::iterator i = _upstream_nodes.begin(); i != _upstream_nodes.end();
- ++i) {
- sptr upstream_node = i->second.lock();
- if (not upstream_node) {
- // Actually this is not OK
- continue;
- }
- upstream_node->disconnect_output_port(_upstream_ports[i->first]);
- }
- // Clear own maps:
- _downstream_nodes.clear();
- _downstream_ports.clear();
- _upstream_nodes.clear();
- _upstream_ports.clear();
-}
-
-void node_ctrl_base::disconnect_output_port(const size_t output_port)
-{
- if (_downstream_nodes.count(output_port) == 0
- or _downstream_ports.count(output_port) == 0) {
- throw uhd::assertion_error(
- str(boost::format("[%s] Attempting to disconnect output port %u, which is "
- "not registered as connected!")
- % unique_id() % output_port));
- }
- _downstream_nodes.erase(output_port);
- _downstream_ports.erase(output_port);
-}
-
-void node_ctrl_base::disconnect_input_port(const size_t input_port)
-{
- if (_upstream_nodes.count(input_port) == 0
- or _upstream_ports.count(input_port) == 0) {
- throw uhd::assertion_error(
- str(boost::format("[%s] Attempting to disconnect input port %u, which is not "
- "registered as connected!")
- % unique_id() % input_port));
- }
- _upstream_nodes.erase(input_port);
- _upstream_ports.erase(input_port);
-}
diff --git a/host/lib/rfnoc/null_block_ctrl_impl.cpp b/host/lib/rfnoc/null_block_ctrl_impl.cpp
deleted file mode 100644
index 1de41d256..000000000
--- a/host/lib/rfnoc/null_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-// Copyright 2014-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/null_block_ctrl.hpp>
-#include <uhd/rfnoc/traffic_counter.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/log.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();
-
- traffic_counter::write_reg_fn_t write = [this](const uint32_t addr,
- const uint32_t data) {
- const uint64_t traffic_counter_sr_base = 192;
- sr_write(addr + traffic_counter_sr_base, data);
- };
-
- traffic_counter::read_reg_fn_t read = [this](const uint32_t addr) {
- const uint64_t traffic_counter_rb_base = 64;
- return user_reg_read64(addr + traffic_counter_rb_base);
- };
-
- _traffic_counter =
- std::make_shared<traffic_counter>(_tree, _root_path, write, read);
- }
-
- 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);
- }
-
-private:
- traffic_counter::sptr _traffic_counter;
-};
-
-UHD_RFNOC_BLOCK_REGISTER(null_block_ctrl, "NullSrcSink");
diff --git a/host/lib/rfnoc/radio_ctrl_impl.cpp b/host/lib/rfnoc/radio_ctrl_impl.cpp
deleted file mode 100644
index 94c3e6ae0..000000000
--- a/host/lib/rfnoc/radio_ctrl_impl.cpp
+++ /dev/null
@@ -1,533 +0,0 @@
-//
-// Copyright 2014-2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "../../transport/super_recv_packet_handler.hpp"
-#include <uhd/convert.hpp>
-#include <uhd/types/direction.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-#include <boost/format.hpp>
-#include <tuple>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-static const size_t BYTES_PER_SAMPLE = 4;
-const std::string radio_ctrl::ALL_LOS = "all";
-
-/****************************************************************************
- * Structors and init
- ***************************************************************************/
-// Note: block_ctrl_base must be called before this, but has to be called by
-// the derived class because of virtual inheritance
-radio_ctrl_impl::radio_ctrl_impl() : _tick_rate(rfnoc::rate_node_ctrl::RATE_UNDEFINED)
-{
- _num_rx_channels = get_output_ports().size();
- _num_tx_channels = get_input_ports().size();
- _continuous_streaming = std::vector<bool>(2, false);
-
- for (size_t i = 0; i < _num_rx_channels; i++) {
- _rx_streamer_active[i] = false;
- }
- for (size_t i = 0; i < _num_tx_channels; i++) {
- _tx_streamer_active[i] = false;
- }
-
- /////////////////////////////////////////////////////////////////////////
- // Setup peripherals
- /////////////////////////////////////////////////////////////////////////
- for (size_t i = 0; i < _get_num_radios(); i++) {
- _register_loopback_self_test(i);
- _perifs[i].ctrl = this->get_ctrl_iface(i);
- // FIXME there's currently no way to set the underflow policy
-
- if (i == 0) {
- time_core_3000::readback_bases_type time64_rb_bases;
- time64_rb_bases.rb_now = regs::rb_addr(regs::RB_TIME_NOW);
- time64_rb_bases.rb_pps = regs::rb_addr(regs::RB_TIME_PPS);
- _time64 = time_core_3000::make(
- _perifs[i].ctrl, regs::sr_addr(regs::TIME), time64_rb_bases);
- this->set_time_now(0.0);
- }
-
- // Reset the RX control engine
- sr_write(regs::RX_CTRL_HALT, 1, i);
- }
-
- ////////////////////////////////////////////////////////////////////
- // Register the time keeper
- ////////////////////////////////////////////////////////////////////
- if (not _tree->exists(fs_path("time") / "now")) {
- _tree->create<time_spec_t>(fs_path("time") / "now").set_publisher([this]() {
- return this->get_time_now();
- });
- }
- if (not _tree->exists(fs_path("time") / "pps")) {
- _tree->create<time_spec_t>(fs_path("time") / "pps").set_publisher([this]() {
- return this->get_time_last_pps();
- });
- }
- if (not _tree->exists(fs_path("time") / "cmd")) {
- _tree->create<time_spec_t>(fs_path("time") / "cmd");
- }
- _tree->access<time_spec_t>(fs_path("time") / "now")
- .add_coerced_subscriber(
- [this](const time_spec_t& time_spec) { this->set_time_now(time_spec); });
- _tree->access<time_spec_t>(fs_path("time") / "pps")
- .add_coerced_subscriber(
- [this](const time_spec_t& time_spec) { this->set_time_next_pps(time_spec); });
- for (size_t i = 0; i < _get_num_radios(); i++) {
- _tree->access<time_spec_t>("time/cmd")
- .add_coerced_subscriber([this, i](const time_spec_t& time_spec) {
- this->set_command_tick_rate(this->_tick_rate, i);
- this->set_command_time(time_spec, i);
- });
- }
- // spp gets created in the XML file
- _tree->access<int>(get_arg_path("spp") / "value")
- .add_coerced_subscriber([this](const int spp) { this->_update_spp(spp); })
- .update();
-}
-
-void radio_ctrl_impl::_register_loopback_self_test(size_t chan)
-{
- size_t hash = size_t(time(NULL));
- for (size_t i = 0; i < 100; i++) {
- boost::hash_combine(hash, i);
- sr_write(regs::TEST, uint32_t(hash), chan);
- uint32_t result = user_reg_read32(regs::RB_TEST, chan);
- if (result != uint32_t(hash)) {
- UHD_LOGGER_ERROR("RFNOC RADIO") << "Register loopback test failed";
- UHD_LOGGER_ERROR("RFNOC RADIO")
- << boost::format("expected: %x result: %x") % uint32_t(hash) % result;
- return; // exit on any failure
- }
- }
- UHD_LOG_DEBUG(unique_id(), "Register loopback test passed");
-}
-
-
-/****************************************************************************
- * API calls
- ***************************************************************************/
-double radio_ctrl_impl::set_rate(double rate)
-{
- std::lock_guard<std::mutex> lock(_mutex);
- _tick_rate = rate;
- _time64->set_tick_rate(_tick_rate);
- _time64->self_test();
- set_command_tick_rate(rate);
- return _tick_rate;
-}
-
-void radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan)
-{
- _tx_antenna[chan] = ant;
-}
-
-void radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan)
-{
- _rx_antenna[chan] = ant;
-}
-
-double radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan)
-{
- return _tx_freq[chan] = freq;
-}
-
-double radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan)
-{
- return _rx_freq[chan] = freq;
-}
-
-double radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan)
-{
- return _tx_gain[chan] = gain;
-}
-
-double radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)
-{
- return _rx_gain[chan] = gain;
-}
-
-double radio_ctrl_impl::set_tx_bandwidth(const double bandwidth, const size_t chan)
-{
- return _tx_bandwidth[chan] = bandwidth;
-}
-
-double radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan)
-{
- return _rx_bandwidth[chan] = bandwidth;
-}
-
-void radio_ctrl_impl::set_time_sync(const uhd::time_spec_t& time)
-{
- _time64->set_time_sync(time);
-}
-
-double radio_ctrl_impl::get_rate() const
-{
- return _tick_rate;
-}
-
-std::string radio_ctrl_impl::get_tx_antenna(const size_t chan) /* const */
-{
- return _tx_antenna.at(chan);
-}
-
-std::string radio_ctrl_impl::get_rx_antenna(const size_t chan) /* const */
-{
- return _rx_antenna.at(chan);
-}
-
-double radio_ctrl_impl::get_tx_frequency(const size_t chan) /* const */
-{
- return _tx_freq.at(chan);
-}
-
-double radio_ctrl_impl::get_rx_frequency(const size_t chan) /* const */
-{
- return _rx_freq.at(chan);
-}
-
-double radio_ctrl_impl::get_tx_gain(const size_t chan) /* const */
-{
- return _tx_gain.at(chan);
-}
-
-double radio_ctrl_impl::get_rx_gain(const size_t chan) /* const */
-{
- return _rx_gain.at(chan);
-}
-
-double radio_ctrl_impl::get_tx_bandwidth(const size_t chan) /* const */
-{
- return _tx_bandwidth.at(chan);
-}
-
-double radio_ctrl_impl::get_rx_bandwidth(const size_t chan) /* const */
-{
- return _rx_bandwidth.at(chan);
-}
-
-/******************************************************************************
- * LO controls
- *****************************************************************************/
-std::vector<std::string> radio_ctrl_impl::get_rx_lo_names(const size_t /* chan */)
-{
- return std::vector<std::string>();
-}
-
-std::vector<std::string> radio_ctrl_impl::get_rx_lo_sources(
- const std::string& /* name */, const size_t /* chan */)
-{
- return std::vector<std::string>();
-}
-
-freq_range_t radio_ctrl_impl::get_rx_lo_freq_range(
- const std::string& /* name */, const size_t /* chan */)
-{
- return freq_range_t();
-}
-
-void radio_ctrl_impl::set_rx_lo_source(
- const std::string& /* src */, const std::string& /* name */, const size_t /* chan */)
-{
- throw uhd::not_implemented_error("set_rx_lo_source is not supported on this radio");
-}
-
-const std::string radio_ctrl_impl::get_rx_lo_source(
- const std::string& /* name */, const size_t /* chan */)
-{
- return "internal";
-}
-
-void radio_ctrl_impl::set_rx_lo_export_enabled(
- bool /* enabled */, const std::string& /* name */, const size_t /* chan */)
-{
- throw uhd::not_implemented_error(
- "set_rx_lo_export_enabled is not supported on this radio");
-}
-
-bool radio_ctrl_impl::get_rx_lo_export_enabled(
- const std::string& /* name */, const size_t /* chan */)
-{
- return false; // Not exporting non-existant LOs
-}
-
-double radio_ctrl_impl::set_rx_lo_freq(
- double /* freq */, const std::string& /* name */, const size_t /* chan */)
-{
- throw uhd::not_implemented_error("set_rx_lo_freq is not supported on this radio");
-}
-
-double radio_ctrl_impl::get_rx_lo_freq(
- const std::string& /* name */, const size_t /* chan */)
-{
- return 0;
-}
-
-std::vector<std::string> radio_ctrl_impl::get_tx_lo_names(const size_t /* chan */
-)
-{
- return std::vector<std::string>();
-}
-
-std::vector<std::string> radio_ctrl_impl::get_tx_lo_sources(
- const std::string& /* name */, const size_t /* chan */
-)
-{
- return std::vector<std::string>();
-}
-
-freq_range_t radio_ctrl_impl::get_tx_lo_freq_range(
- const std::string& /* name */, const size_t /* chan */
-)
-{
- return freq_range_t();
-}
-
-void radio_ctrl_impl::set_tx_lo_source(
- const std::string& /* src */, const std::string& /* name */, const size_t /* chan */
-)
-{
- throw uhd::not_implemented_error("set_tx_lo_source is not supported on this radio");
-}
-
-const std::string radio_ctrl_impl::get_tx_lo_source(
- const std::string& /* name */, const size_t /* chan */
-)
-{
- return "internal";
-}
-
-void radio_ctrl_impl::set_tx_lo_export_enabled(
- const bool /* enabled */, const std::string& /* name */, const size_t /* chan */
-)
-{
- throw uhd::not_implemented_error(
- "set_tx_lo_export_enabled is not supported on this radio");
-}
-
-bool radio_ctrl_impl::get_tx_lo_export_enabled(
- const std::string& /* name */, const size_t /* chan */
-)
-{
- return false; // Not exporting non-existant LOs
-}
-
-double radio_ctrl_impl::set_tx_lo_freq(
- const double /* freq */, const std::string& /* name */, const size_t /* chan */
-)
-{
- throw uhd::not_implemented_error("set_tx_lo_freq is not supported on this radio");
-}
-
-double radio_ctrl_impl::get_tx_lo_freq(const std::string& /* name */, const size_t chan)
-{
- return get_tx_frequency(chan);
-}
-
-void radio_ctrl_impl::enable_rx_timestamps(const bool enable, const size_t chan)
-{
- const uint32_t output_format = 0 | (enable ? 0x01 : 0x00);
- sr_write(regs::RX_CTRL_OUTPUT_FORMAT, output_format, chan);
-}
-
-/***********************************************************************
- * RX Streamer-related methods (from source_block_ctrl_base)
- **********************************************************************/
-//! Pass stream commands to the radio
-void radio_ctrl_impl::issue_stream_cmd(
- const uhd::stream_cmd_t& stream_cmd, const size_t chan)
-{
- std::lock_guard<std::mutex> lock(_mutex);
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::issue_stream_cmd() " << chan << " "
- << char(stream_cmd.stream_mode);
- if (not _is_streamer_active(uhd::RX_DIRECTION, chan)) {
- UHD_RFNOC_BLOCK_TRACE()
- << "radio_ctrl_impl::issue_stream_cmd() called on inactive "
- "channel. Skipping.";
- return;
- }
- constexpr size_t max_num_samps = 0x0fffffff;
- if (stream_cmd.num_samps > max_num_samps) {
- UHD_LOG_ERROR("RFNOC RADIO",
- "Requesting too many samples in a single burst! "
- "Requested "
- + std::to_string(stream_cmd.num_samps)
- + ", maximum "
- "is "
- + std::to_string(max_num_samps) + ".");
- UHD_LOG_INFO("RFNOC RADIO",
- "Note that a decimation block will increase the number of samples "
- "per burst by the decimation factor. Your application may have "
- "requested fewer samples.");
- throw uhd::value_error("Requested too many samples in a single burst.");
- }
- _continuous_streaming[chan] =
- (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
-
- // setup the mode to instruction flags
- typedef std::tuple<bool, bool, bool, bool> inst_t;
- static const std::map<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst{
- // reload, chain, samps, stop
- {stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false)},
- {stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true)},
- {stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false)},
- {stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false)}};
-
- // setup the instruction flag values
- bool inst_reload, inst_chain, inst_samps, inst_stop;
- std::tie(inst_reload, inst_chain, inst_samps, inst_stop) =
- mode_to_inst.at(stream_cmd.stream_mode);
-
- // calculate the word from flags and length
- const uint32_t cmd_word =
- 0 | (uint32_t((stream_cmd.stream_now) ? 1 : 0) << 31)
- | (uint32_t((inst_chain) ? 1 : 0) << 30) | (uint32_t((inst_reload) ? 1 : 0) << 29)
- | (uint32_t((inst_stop) ? 1 : 0) << 28)
- | ((inst_samps) ? stream_cmd.num_samps : ((inst_stop) ? 0 : 1));
-
- // issue the stream command
- const uint64_t ticks =
- (stream_cmd.stream_now) ? 0 : stream_cmd.time_spec.to_ticks(get_rate());
- sr_write(regs::RX_CTRL_CMD, cmd_word, chan);
- sr_write(regs::RX_CTRL_TIME_HI, uint32_t(ticks >> 32), chan);
- sr_write(regs::RX_CTRL_TIME_LO, uint32_t(ticks >> 0), chan); // latches the command
-}
-
-std::vector<size_t> radio_ctrl_impl::get_active_rx_ports()
-{
- std::vector<size_t> active_rx_ports;
- typedef std::map<size_t, bool> map_t;
- for (map_t::value_type& m : _rx_streamer_active) {
- if (m.second) {
- active_rx_ports.push_back(m.first);
- }
- }
- return active_rx_ports;
-}
-
-/***********************************************************************
- * Radio controls (radio_ctrl specific)
- **********************************************************************/
-void radio_ctrl_impl::set_rx_streamer(bool active, const size_t port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_rx_streamer() " << port << " -> "
- << active;
- if (port > _num_rx_channels) {
- throw uhd::value_error(str(
- boost::format("[%s] Can't (un)register RX streamer on port %d (invalid port)")
- % unique_id() % port));
- }
- _rx_streamer_active[port] = active;
- if (not check_radio_config()) {
- throw std::runtime_error(
- str(boost::format("[%s]: Invalid radio configuration.") % unique_id()));
- }
-}
-
-void radio_ctrl_impl::set_tx_streamer(bool active, const size_t port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_tx_streamer() " << port << " -> "
- << active;
- if (port > _num_tx_channels) {
- throw uhd::value_error(str(
- boost::format("[%s] Can't (un)register TX streamer on port %d (invalid port)")
- % unique_id() % port));
- }
- _tx_streamer_active[port] = active;
- if (not check_radio_config()) {
- throw std::runtime_error(
- str(boost::format("[%s]: Invalid radio configuration.") % unique_id()));
- }
-}
-
-// Subscribers to block args:
-// TODO move to nocscript
-void radio_ctrl_impl::_update_spp(int spp)
-{
- std::lock_guard<std::mutex> lock(_mutex);
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::_update_spp(): Requested spp: " << spp;
- if (spp == 0) {
- spp = DEFAULT_PACKET_SIZE / BYTES_PER_SAMPLE;
- }
- UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::_update_spp(): Setting spp to: " << spp;
- for (size_t i = 0; i < _num_rx_channels; i++) {
- sr_write(regs::RX_CTRL_MAXLEN, uint32_t(spp), i);
- }
-}
-
-void radio_ctrl_impl::set_time_now(const time_spec_t& time_spec)
-{
- _time64->set_time_now(time_spec);
-}
-
-void radio_ctrl_impl::set_time_next_pps(const time_spec_t& time_spec)
-{
- _time64->set_time_next_pps(time_spec);
-}
-
-time_spec_t radio_ctrl_impl::get_time_now()
-{
- return _time64->get_time_now();
-}
-
-time_spec_t radio_ctrl_impl::get_time_last_pps()
-{
- return _time64->get_time_last_pps();
-}
-
-void radio_ctrl_impl::set_time_source(const std::string& source)
-{
- _tree->access<std::string>("time_source/value").set(source);
-}
-
-std::string radio_ctrl_impl::get_time_source()
-{
- return _tree->access<std::string>("time_source/value").get();
-}
-
-std::vector<std::string> radio_ctrl_impl::get_time_sources()
-{
- return _tree->access<std::vector<std::string>>("time_source/options").get();
-}
-
-void radio_ctrl_impl::set_clock_source(const std::string& source)
-{
- _tree->access<std::string>("clock_source/value").set(source);
-}
-
-std::string radio_ctrl_impl::get_clock_source()
-{
- return _tree->access<std::string>("clock_source/value").get();
-}
-
-std::vector<std::string> radio_ctrl_impl::get_clock_sources()
-{
- return _tree->access<std::vector<std::string>>("clock_source/options").get();
-}
-
-
-std::vector<std::string> radio_ctrl_impl::get_gpio_banks() const
-{
- return std::vector<std::string>();
-}
-
-void radio_ctrl_impl::set_gpio_attr(
- const std::string&, const std::string&, const uint32_t, const uint32_t)
-{
- throw uhd::not_implemented_error("set_gpio_attr was not defined for this radio");
-}
-
-uint32_t radio_ctrl_impl::get_gpio_attr(const std::string&, const std::string&)
-{
- throw uhd::not_implemented_error("get_gpio_attr was not defined for this radio");
-}
diff --git a/host/lib/rfnoc/rate_node_ctrl.cpp b/host/lib/rfnoc/rate_node_ctrl.cpp
deleted file mode 100644
index 08abf4f78..000000000
--- a/host/lib/rfnoc/rate_node_ctrl.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/rate_node_ctrl.hpp>
-#include <boost/bind.hpp>
-
-using namespace uhd::rfnoc;
-
-const double rate_node_ctrl::RATE_UNDEFINED = -1.0;
-
-static double _get_input_samp_rate(rate_node_ctrl::sptr node, size_t port)
-{
- return node->get_input_samp_rate(port);
-}
-
-static double _get_output_samp_rate(rate_node_ctrl::sptr node, size_t port)
-{
- return node->get_output_samp_rate(port);
-}
-
-
-// FIXME add recursion limiters (i.e. list of explored nodes)
-double rate_node_ctrl::get_input_samp_rate(size_t /* port */
-)
-{
- try {
- return find_downstream_unique_property<rate_node_ctrl, double>(
- boost::bind(_get_input_samp_rate, _1, _2), RATE_UNDEFINED);
- } catch (const uhd::runtime_error& ex) {
- throw uhd::runtime_error(
- str(boost::format("Multiple sampling rates downstream of %s: %s.")
- % unique_id() % ex.what()));
- }
-}
-
-double rate_node_ctrl::get_output_samp_rate(size_t /* port */
-)
-{
- try {
- return find_upstream_unique_property<rate_node_ctrl, double>(
- boost::bind(_get_output_samp_rate, _1, _2), RATE_UNDEFINED);
- } catch (const uhd::runtime_error& ex) {
- throw uhd::runtime_error(
- str(boost::format("Multiple sampling rates upstream of %s: %s.") % unique_id()
- % ex.what()));
- }
-}
diff --git a/host/lib/rfnoc/rx_stream_terminator.cpp b/host/lib/rfnoc/rx_stream_terminator.cpp
deleted file mode 100644
index 18ecb4974..000000000
--- a/host/lib/rfnoc/rx_stream_terminator.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include "../transport/super_recv_packet_handler.hpp"
-#include <uhd/rfnoc/source_node_ctrl.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/radio_ctrl_impl.hpp>
-#include <uhdlib/rfnoc/rx_stream_terminator.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd::rfnoc;
-
-size_t rx_stream_terminator::_count = 0;
-
-rx_stream_terminator::rx_stream_terminator()
- : _term_index(_count)
- , _samp_rate(rate_node_ctrl::RATE_UNDEFINED)
- , _tick_rate(tick_node_ctrl::RATE_UNDEFINED)
-{
- _count++;
-}
-
-std::string rx_stream_terminator::unique_id() const
-{
- return str(boost::format("RX Terminator %d") % _term_index);
-}
-
-void rx_stream_terminator::set_tx_streamer(bool, const size_t)
-{
- /* nop */
-}
-
-void rx_stream_terminator::set_rx_streamer(bool active, const size_t)
-{
- // TODO this is identical to source_node_ctrl::set_rx_streamer() -> factor out
- UHD_RFNOC_BLOCK_TRACE() << "rx_stream_terminator::set_rx_streamer() " << active;
- for (const node_ctrl_base::node_map_pair_t upstream_node : _upstream_nodes) {
- source_node_ctrl::sptr curr_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(upstream_node.second.lock());
- if (curr_upstream_block_ctrl) {
- curr_upstream_block_ctrl->set_rx_streamer(
- active, get_upstream_port(upstream_node.first));
- }
- _rx_streamer_active[upstream_node.first] = active;
- }
-}
-
-void rx_stream_terminator::handle_overrun(
- boost::weak_ptr<uhd::rx_streamer> streamer, const size_t)
-{
- std::unique_lock<std::mutex> l(_overrun_handler_mutex, std::defer_lock);
- if (!l.try_lock()) {
- // We're already handling overruns, so just stop right there
- return;
- }
-
- std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl_impl>> upstream_radio_nodes =
- find_upstream_node<uhd::rfnoc::radio_ctrl_impl>();
- const size_t n_radios = upstream_radio_nodes.size();
- if (n_radios == 0) {
- return;
- }
-
- UHD_RFNOC_BLOCK_TRACE() << "rx_stream_terminator::handle_overrun()";
- boost::shared_ptr<uhd::transport::sph::recv_packet_streamer> my_streamer =
- boost::dynamic_pointer_cast<uhd::transport::sph::recv_packet_streamer>(
- streamer.lock());
- if (not my_streamer)
- return; // If the rx_streamer has expired then overflow handling makes no sense.
-
- bool in_continuous_streaming_mode = true;
- int num_channels = 0;
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl_impl>& node :
- upstream_radio_nodes) {
- num_channels += node->get_active_rx_ports().size();
- for (const size_t port : node->get_active_rx_ports()) {
- in_continuous_streaming_mode = in_continuous_streaming_mode
- && node->in_continuous_streaming_mode(port);
- }
- }
- if (num_channels == 0) {
- return;
- }
-
- if (num_channels == 1 and in_continuous_streaming_mode) {
- std::vector<size_t> active_rx_ports =
- upstream_radio_nodes[0]->get_active_rx_ports();
- if (active_rx_ports.empty()) {
- return;
- }
- const size_t port = active_rx_ports[0];
- upstream_radio_nodes[0]->issue_stream_cmd(
- stream_cmd_t::STREAM_MODE_START_CONTINUOUS, port);
- return;
- }
-
- /////////////////////////////////////////////////////////////
- // MIMO overflow recovery time
- /////////////////////////////////////////////////////////////
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl_impl>& node :
- upstream_radio_nodes) {
- for (const size_t port : node->get_active_rx_ports()) {
- // check all the ports on all the radios
- node->rx_ctrl_clear_cmds(port);
- node->issue_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, port);
- }
- }
- // flush transports
- my_streamer->flush_all(0.001); // TODO flushing will probably have to go away.
- // restart streaming on all channels
- if (in_continuous_streaming_mode) {
- stream_cmd_t stream_cmd(stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
- stream_cmd.stream_now = false;
- stream_cmd.time_spec =
- upstream_radio_nodes[0]->get_time_now() + time_spec_t(0.05);
-
- for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl_impl>& node :
- upstream_radio_nodes) {
- for (const size_t port : node->get_active_rx_ports()) {
- node->issue_stream_cmd(stream_cmd, port);
- }
- }
- }
-}
-
-rx_stream_terminator::~rx_stream_terminator()
-{
- UHD_RFNOC_BLOCK_TRACE() << "rx_stream_terminator::~rx_stream_terminator() ";
- set_rx_streamer(false, 0);
-}
diff --git a/host/lib/rfnoc/scalar_node_ctrl.cpp b/host/lib/rfnoc/scalar_node_ctrl.cpp
deleted file mode 100644
index f197da0b5..000000000
--- a/host/lib/rfnoc/scalar_node_ctrl.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/scalar_node_ctrl.hpp>
-#include <boost/bind.hpp>
-
-using namespace uhd::rfnoc;
-
-const double scalar_node_ctrl::SCALE_UNDEFINED = -1.0;
-
-static double _get_input_factor(scalar_node_ctrl::sptr node, size_t port)
-{
- return node->get_input_scale_factor(port);
-}
-
-static double _get_output_factor(scalar_node_ctrl::sptr node, size_t port)
-{
- return node->get_output_scale_factor(port);
-}
-
-// FIXME add recursion limiters (i.e. list of explored nodes)
-double scalar_node_ctrl::get_input_scale_factor(size_t /* port */
-)
-{
- try {
- return find_downstream_unique_property<scalar_node_ctrl, double>(
- boost::bind(_get_input_factor, _1, _2), SCALE_UNDEFINED);
- } catch (const uhd::runtime_error& ex) {
- throw uhd::runtime_error(
- str(boost::format("Multiple scaling factors rates downstream of %s: %s.")
- % unique_id() % ex.what()));
- }
-}
-
-double scalar_node_ctrl::get_output_scale_factor(size_t /* port */
-)
-{
- try {
- return find_upstream_unique_property<scalar_node_ctrl, double>(
- boost::bind(_get_output_factor, _1, _2), SCALE_UNDEFINED);
- } catch (const uhd::runtime_error& ex) {
- throw uhd::runtime_error(
- str(boost::format("Multiple scaling factors rates upstream of %s: %s.")
- % unique_id() % ex.what()));
- }
-}
diff --git a/host/lib/rfnoc/siggen_block_ctrl_impl.cpp b/host/lib/rfnoc/siggen_block_ctrl_impl.cpp
deleted file mode 100644
index dc4035962..000000000
--- a/host/lib/rfnoc/siggen_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Copyright 2016-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/siggen_block_ctrl.hpp>
-#include <uhd/utils/log.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd::rfnoc;
-
-class siggen_block_ctrl_impl : public siggen_block_ctrl
-{
-public:
- UHD_RFNOC_BLOCK_CONSTRUCTOR(siggen_block_ctrl)
- {
- // nop
- }
-
- void issue_stream_cmd(const uhd::stream_cmd_t& stream_cmd, const size_t)
- {
- UHD_LOGGER_TRACE(unique_id()) << "issue_stream_cmd()" << std::endl;
- if (not stream_cmd.stream_now) {
- throw uhd::not_implemented_error(
- "siggen_block does not support timed commands.");
- }
- switch (stream_cmd.stream_mode) {
- case uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS:
- sr_write("ENABLE", true);
- break;
-
- case uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS:
- sr_write("ENABLE", 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("siggen_block does not support "
- "streaming modes other than CONTINUOUS");
-
- default:
- UHD_THROW_INVALID_CODE_PATH();
- }
- }
-};
-
-UHD_RFNOC_BLOCK_REGISTER(siggen_block_ctrl, "SigGen");
diff --git a/host/lib/rfnoc/sink_block_ctrl_base.cpp b/host/lib/rfnoc/sink_block_ctrl_base.cpp
deleted file mode 100644
index f1d65350a..000000000
--- a/host/lib/rfnoc/sink_block_ctrl_base.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/rfnoc/sink_block_ctrl_base.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/utils.hpp>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-
-/***********************************************************************
- * Stream signatures
- **********************************************************************/
-stream_sig_t sink_block_ctrl_base::get_input_signature(size_t block_port) const
-{
- if (not _tree->exists(_root_path / "ports" / "in" / block_port)) {
- throw uhd::runtime_error(str(boost::format("Invalid port number %d for block %s")
- % block_port % unique_id()));
- }
-
- return _resolve_port_def(
- _tree->access<blockdef::port_t>(_root_path / "ports" / "in" / block_port).get());
-}
-
-std::vector<size_t> sink_block_ctrl_base::get_input_ports() const
-{
- std::vector<size_t> input_ports;
- input_ports.reserve(_tree->list(_root_path / "ports" / "in").size());
- for (const std::string port : _tree->list(_root_path / "ports" / "in")) {
- input_ports.push_back(boost::lexical_cast<size_t>(port));
- }
- return input_ports;
-}
-
-/***********************************************************************
- * FPGA Configuration
- **********************************************************************/
-size_t sink_block_ctrl_base::get_fifo_size(size_t block_port) const
-{
- if (_tree->exists(_root_path / "input_buffer_size" / std::to_string(block_port))) {
- return _tree
- ->access<size_t>(
- _root_path / "input_buffer_size" / std::to_string(block_port))
- .get();
- }
- return 0;
-}
-
-size_t sink_block_ctrl_base::get_mtu(size_t block_port) const
-{
- if (_tree->exists(_root_path / "mtu" / std::to_string(block_port))) {
- return _tree->access<size_t>(_root_path / "mtu" / std::to_string(block_port))
- .get();
- }
- return 0;
-}
-
-void sink_block_ctrl_base::configure_flow_control_in(
- const size_t bytes, const size_t block_port)
-{
- UHD_RFNOC_BLOCK_TRACE()
- << boost::format("sink_block_ctrl_base::configure_flow_control_in(bytes=%d)")
- % bytes;
-
- uint32_t bytes_word = 0;
- if (bytes) {
- // Bit 32 enables flow control
- bytes_word = (1 << 31) | bytes;
- }
- sr_write(SR_FLOW_CTRL_BYTES_PER_ACK, bytes_word, block_port);
-}
-
-void sink_block_ctrl_base::set_error_policy(const std::string& policy)
-{
- if (policy == "next_packet") {
- sr_write(SR_ERROR_POLICY, (1 << 2) | 1);
- } else if (policy == "next_burst") {
- sr_write(SR_ERROR_POLICY, (1 << 3) | 1);
- } else if (policy == "continue") {
- sr_write(SR_ERROR_POLICY, (1 << 1) | 1);
- } else if (policy == "wait") {
- sr_write(SR_ERROR_POLICY, 1);
- } else
- throw uhd::value_error(
- "Block input cannot handle requested error policy: " + policy);
-}
-
-/***********************************************************************
- * Hooks
- **********************************************************************/
-size_t sink_block_ctrl_base::_request_input_port(
- const size_t suggested_port, const uhd::device_addr_t&) const
-{
- const std::set<size_t> valid_input_ports =
- utils::str_list_to_set<size_t>(_tree->list(_root_path / "ports" / "in"));
- return utils::node_map_find_first_free(
- _upstream_nodes, suggested_port, valid_input_ports);
-}
-// vim: sw=4 et:
diff --git a/host/lib/rfnoc/sink_node_ctrl.cpp b/host/lib/rfnoc/sink_node_ctrl.cpp
deleted file mode 100644
index 53a26d7ed..000000000
--- a/host/lib/rfnoc/sink_node_ctrl.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/sink_node_ctrl.hpp>
-#include <uhd/rfnoc/source_node_ctrl.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/utils.hpp>
-
-using namespace uhd::rfnoc;
-
-size_t sink_node_ctrl::connect_upstream(
- node_ctrl_base::sptr upstream_node, size_t port, const uhd::device_addr_t& args)
-{
- boost::mutex::scoped_lock lock(_input_mutex);
- port = _request_input_port(port, args);
- _register_upstream_node(upstream_node, port);
- return port;
-}
-
-void sink_node_ctrl::set_tx_streamer(bool active, const size_t port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "sink_node_ctrl::set_tx_streamer() " << active << " "
- << port;
-
- /* Enable all downstream connections:
- for(const node_ctrl_base::node_map_pair_t downstream_node: list_downstream_nodes()) {
- sptr curr_downstream_block_ctrl =
- boost::dynamic_pointer_cast<sink_node_ctrl>(downstream_node.second.lock());
- if (curr_downstream_block_ctrl) {
- curr_downstream_block_ctrl->set_tx_streamer(
- active,
- get_downstream_port(downstream_node.first)
- );
- }
- }
- */
-
- // Only enable 1:1
- if (list_downstream_nodes().count(port)) {
- sink_node_ctrl::sptr this_downstream_block_ctrl =
- boost::dynamic_pointer_cast<sink_node_ctrl>(
- list_downstream_nodes().at(port).lock());
- if (this_downstream_block_ctrl) {
- this_downstream_block_ctrl->set_tx_streamer(
- active, get_downstream_port(port));
- }
- }
-
- _tx_streamer_active[port] = active;
-}
-
-size_t sink_node_ctrl::_request_input_port(
- const size_t suggested_port, const uhd::device_addr_t&) const
-{
- return utils::node_map_find_first_free(_upstream_nodes, suggested_port);
-}
-
-void sink_node_ctrl::_register_upstream_node(
- node_ctrl_base::sptr upstream_node, size_t port)
-{
- // Do all the checks:
- if (port == ANY_PORT) {
- throw uhd::type_error("Invalid input port number.");
- }
- if (_upstream_nodes.count(port) and not _upstream_nodes[port].expired()) {
- throw uhd::runtime_error(
- str(boost::format("On node %s, input port %d is already connected.")
- % unique_id() % port));
- }
- if (not boost::dynamic_pointer_cast<source_node_ctrl>(upstream_node)) {
- throw uhd::type_error("Attempting to register a non-source block as upstream.");
- }
- // Alles klar, Herr Kommissar :)
-
- _upstream_nodes[port] = boost::weak_ptr<node_ctrl_base>(upstream_node);
-}
diff --git a/host/lib/rfnoc/source_block_ctrl_base.cpp b/host/lib/rfnoc/source_block_ctrl_base.cpp
deleted file mode 100644
index 2ddb455a1..000000000
--- a/host/lib/rfnoc/source_block_ctrl_base.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/constants.hpp>
-#include <uhd/rfnoc/source_block_ctrl_base.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/utils.hpp>
-#include <chrono>
-#include <thread>
-
-using namespace uhd;
-using namespace uhd::rfnoc;
-
-/***********************************************************************
- * Streaming operations
- **********************************************************************/
-void source_block_ctrl_base::issue_stream_cmd(
- const uhd::stream_cmd_t& stream_cmd, const size_t chan)
-{
- UHD_RFNOC_BLOCK_TRACE() << "source_block_ctrl_base::issue_stream_cmd()";
- if (_upstream_nodes.empty()) {
- UHD_LOGGER_WARNING("RFNOC")
- << "issue_stream_cmd() not implemented for " << get_block_id();
- return;
- }
-
- for (const node_ctrl_base::node_map_pair_t upstream_node : _upstream_nodes) {
- // FIXME: Need proper mapping from input port to output port
- // The code below assumes the input port and output port are the same
- // if the number of upstream and downstream ports are the same.
- // The stream command is limited to only that port to prevent issuing
- // it on the wrong block and port.
- if (_num_input_ports == _num_output_ports
- and upstream_node.first != chan) {
- continue;
- }
- source_node_ctrl::sptr this_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(upstream_node.second.lock());
- if (this_upstream_block_ctrl) {
- this_upstream_block_ctrl->issue_stream_cmd(
- stream_cmd, get_upstream_port(upstream_node.first));
- }
- }
-}
-
-/***********************************************************************
- * Stream signatures
- **********************************************************************/
-stream_sig_t source_block_ctrl_base::get_output_signature(size_t block_port) const
-{
- if (not _tree->exists(_root_path / "ports" / "out" / block_port)) {
- throw uhd::runtime_error(str(boost::format("Invalid port number %d for block %s")
- % block_port % unique_id()));
- }
-
- return _resolve_port_def(
- _tree->access<blockdef::port_t>(_root_path / "ports" / "out" / block_port).get());
-}
-
-std::vector<size_t> source_block_ctrl_base::get_output_ports() const
-{
- std::vector<size_t> output_ports;
- output_ports.reserve(_tree->list(_root_path / "ports" / "out").size());
- for (const std::string port : _tree->list(_root_path / "ports" / "out")) {
- output_ports.push_back(boost::lexical_cast<size_t>(port));
- }
- return output_ports;
-}
-
-/***********************************************************************
- * FPGA Configuration
- **********************************************************************/
-void source_block_ctrl_base::set_destination(
- uint32_t next_address, size_t output_block_port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "source_block_ctrl_base::set_destination() "
- << uhd::sid_t(next_address);
- sid_t new_sid(next_address);
- new_sid.set_src(get_address(output_block_port));
- UHD_RFNOC_BLOCK_TRACE() << " Setting SID: " << new_sid << " ";
- sr_write(SR_NEXT_DST_SID, (1 << 16) | next_address, output_block_port);
-}
-
-void source_block_ctrl_base::configure_flow_control_out(const bool enable_fc_output,
- const bool lossless_link,
- const size_t buf_size_bytes,
- const size_t pkt_limit,
- const size_t block_port,
- UHD_UNUSED(const uhd::sid_t& sid))
-{
- UHD_RFNOC_BLOCK_TRACE()
- << "source_block_ctrl_base::configure_flow_control_out() buf_size_bytes=="
- << buf_size_bytes;
- if (buf_size_bytes == 0) {
- throw uhd::runtime_error(
- str(boost::format(
- "Invalid window size %d for block %s. Window size cannot be 0 bytes.")
- % buf_size_bytes % unique_id()));
- }
-
- // Enable source flow control module and conditionally enable byte based and/or packet
- // count based flow control
- const bool enable_byte_fc = (buf_size_bytes != 0);
- const bool enable_pkt_cnt_fc = (pkt_limit != 0);
- const uint32_t config = (enable_fc_output ? 1 : 0) | ((enable_byte_fc ? 1 : 0) << 1)
- | ((enable_pkt_cnt_fc ? 1 : 0) << 2)
- | ((lossless_link ? 1 : 0) << 3);
-
- // Resize the FC window.
- // Precondition: No data can be buffered upstream.
- if (enable_byte_fc) {
- sr_write(SR_FLOW_CTRL_WINDOW_SIZE, buf_size_bytes, block_port);
- }
- if (enable_pkt_cnt_fc) {
- sr_write(SR_FLOW_CTRL_PKT_LIMIT, pkt_limit, block_port);
- }
-
- // Enable the FC window.
- // Precondition: The window size and/or packet limit must be set.
- sr_write(SR_FLOW_CTRL_EN, config, block_port);
-}
-
-size_t source_block_ctrl_base::get_mtu(size_t block_port) const
-{
- if (_tree->exists(_root_path / "mtu" / std::to_string(block_port))) {
- return _tree->access<size_t>(_root_path / "mtu" / std::to_string(block_port))
- .get();
- }
- return 0;
-}
-
-
-/***********************************************************************
- * Hooks
- **********************************************************************/
-size_t source_block_ctrl_base::_request_output_port(
- const size_t suggested_port, const uhd::device_addr_t&) const
-{
- const std::set<size_t> valid_output_ports =
- utils::str_list_to_set<size_t>(_tree->list(_root_path / "ports" / "out"));
- return utils::node_map_find_first_free(
- _downstream_nodes, suggested_port, valid_output_ports);
-}
-// vim: sw=4 et:
diff --git a/host/lib/rfnoc/source_node_ctrl.cpp b/host/lib/rfnoc/source_node_ctrl.cpp
deleted file mode 100644
index 23a17a463..000000000
--- a/host/lib/rfnoc/source_node_ctrl.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/sink_node_ctrl.hpp>
-#include <uhd/rfnoc/source_node_ctrl.hpp>
-#include <uhd/utils/log.hpp>
-#include <uhdlib/rfnoc/utils.hpp>
-
-using namespace uhd::rfnoc;
-
-size_t source_node_ctrl::connect_downstream(
- node_ctrl_base::sptr downstream_node, size_t port, const uhd::device_addr_t& args)
-{
- boost::mutex::scoped_lock lock(_output_mutex);
- port = _request_output_port(port, args);
- _register_downstream_node(downstream_node, port);
- return port;
-}
-
-void source_node_ctrl::set_rx_streamer(bool active, const size_t port)
-{
- UHD_RFNOC_BLOCK_TRACE() << "source_node_ctrl::set_rx_streamer() " << port << " -> "
- << active;
-
- /* This will enable all upstream blocks:
- for(const node_ctrl_base::node_map_pair_t upstream_node: list_upstream_nodes()) {
- sptr curr_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(upstream_node.second.lock());
- if (curr_upstream_block_ctrl) {
- curr_upstream_block_ctrl->set_rx_streamer(
- active,
- get_upstream_port(upstream_node.first)
- );
- }
- }
- */
-
- // This only enables 1:1 (if output 1 is enabled, enable what's connected to input 1)
- if (list_upstream_nodes().count(port)) {
- source_node_ctrl::sptr this_upstream_block_ctrl =
- boost::dynamic_pointer_cast<source_node_ctrl>(
- list_upstream_nodes().at(port).lock());
- if (this_upstream_block_ctrl) {
- this_upstream_block_ctrl->set_rx_streamer(active, get_upstream_port(port));
- }
- }
-
- _rx_streamer_active[port] = active;
-}
-
-size_t source_node_ctrl::_request_output_port(
- const size_t suggested_port, const uhd::device_addr_t&) const
-{
- return utils::node_map_find_first_free(_downstream_nodes, suggested_port);
-}
-
-void source_node_ctrl::_register_downstream_node(
- node_ctrl_base::sptr downstream_node, size_t port)
-{
- // Do all the checks:
- if (port == ANY_PORT) {
- throw uhd::type_error(
- str(boost::format("[%s] Invalid output port number (ANY).") % unique_id()));
- }
- if (_downstream_nodes.count(port) and not _downstream_nodes[port].expired()) {
- throw uhd::runtime_error(
- str(boost::format("On node %s, output port %d is already connected.")
- % unique_id() % port));
- }
- if (not boost::dynamic_pointer_cast<sink_node_ctrl>(downstream_node)) {
- throw uhd::type_error("Attempting to register a non-sink block as downstream.");
- }
- // Alles klar, Herr Kommissar :)
-
- _downstream_nodes[port] = boost::weak_ptr<node_ctrl_base>(downstream_node);
-}
diff --git a/host/lib/rfnoc/stream_sig.cpp b/host/lib/rfnoc/stream_sig.cpp
deleted file mode 100644
index 55d1cb005..000000000
--- a/host/lib/rfnoc/stream_sig.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright 2014 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/stream_sig.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd::rfnoc;
-
-stream_sig_t::stream_sig_t() : item_type(""), vlen(0), packet_size(0), is_bursty(false)
-{
- // nop
-}
-
-std::string stream_sig_t::to_string()
-{
- return str(
- boost::format("%s,vlen=%d,packet_size=%d") % item_type % vlen % packet_size);
-}
-
-std::string stream_sig_t::to_pp_string()
-{
- return str(boost::format("Data type: %s | Vector Length: %d | Packet size: %d")
- % item_type % vlen % packet_size);
-}
-
-size_t stream_sig_t::get_bytes_per_item() const
-{
- if (item_type == "") {
- return 0;
- }
-
- return uhd::convert::get_bytes_per_item(item_type);
-}
-
-bool stream_sig_t::is_compatible(
- const stream_sig_t& output_sig, const stream_sig_t& input_sig)
-{
- /// Item types:
- if (not(input_sig.item_type.empty() or output_sig.item_type.empty())
- and input_sig.item_type != output_sig.item_type) {
- return false;
- }
-
- /// Vector lengths
- if (output_sig.vlen and input_sig.vlen) {
- if (input_sig.vlen != output_sig.vlen) {
- return false;
- }
- }
-
- /// Packet sizes
- if (output_sig.packet_size and input_sig.packet_size) {
- if (input_sig.packet_size != output_sig.packet_size) {
- return false;
- }
- }
-
- // You may pass
- return true;
-}
-// vim: sw=4 et:
diff --git a/host/lib/rfnoc/tick_node_ctrl.cpp b/host/lib/rfnoc/tick_node_ctrl.cpp
deleted file mode 100644
index 40131e72f..000000000
--- a/host/lib/rfnoc/tick_node_ctrl.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/tick_node_ctrl.hpp>
-
-using namespace uhd::rfnoc;
-
-const double tick_node_ctrl::RATE_UNDEFINED = 0;
-
-double tick_node_ctrl::get_tick_rate(
- const std::set<node_ctrl_base::sptr>& _explored_nodes)
-{
- // First, see if we've implemented _get_tick_rate()
- {
- double my_tick_rate = _get_tick_rate();
- if (my_tick_rate != RATE_UNDEFINED) {
- return my_tick_rate;
- }
- }
-
- // If not, we ask all our neighbours for the tick rate.
- // This will fail if we get different values.
- std::set<node_ctrl_base::sptr> explored_nodes(_explored_nodes);
- explored_nodes.insert(shared_from_this());
- // Here, we need all up- and downstream nodes. Note that we have the rule
- // that there can only be one tick rate in all of the nodes, that means we
- // don't only search active neighbouring nodes.
- std::vector<sptr> neighbouring_tick_nodes =
- find_downstream_node<tick_node_ctrl>(false);
- {
- std::vector<sptr> upstream_neighbouring_tick_nodes =
- find_upstream_node<tick_node_ctrl>(false);
- neighbouring_tick_nodes.insert(neighbouring_tick_nodes.end(),
- upstream_neighbouring_tick_nodes.begin(),
- upstream_neighbouring_tick_nodes.end());
- } // neighbouring_tick_nodes is now initialized
- double ret_val = RATE_UNDEFINED;
- for (const sptr& node : neighbouring_tick_nodes) {
- if (_explored_nodes.count(node)) {
- continue;
- }
- double tick_rate = node->get_tick_rate(explored_nodes);
- if (tick_rate == RATE_UNDEFINED) {
- continue;
- }
- if (ret_val == RATE_UNDEFINED) {
- ret_val = tick_rate;
- // TODO: Remember name of this node so we can make the throw message more
- // descriptive.
- continue;
- }
- if (tick_rate != ret_val) {
- throw uhd::runtime_error(str(
- // TODO add node names
- boost::format("Conflicting tick rates: One neighbouring block specifies "
- "%d MHz, another %d MHz.")
- % tick_rate % ret_val));
- }
- }
- return ret_val;
-}
diff --git a/host/lib/rfnoc/tx_stream_terminator.cpp b/host/lib/rfnoc/tx_stream_terminator.cpp
deleted file mode 100644
index fa4148fbb..000000000
--- a/host/lib/rfnoc/tx_stream_terminator.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright 2014-2015 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/sink_node_ctrl.hpp>
-#include <uhdlib/rfnoc/tx_stream_terminator.hpp>
-#include <boost/format.hpp>
-
-using namespace uhd::rfnoc;
-
-size_t tx_stream_terminator::_count = 0;
-
-tx_stream_terminator::tx_stream_terminator()
- : _term_index(_count)
- , _samp_rate(rate_node_ctrl::RATE_UNDEFINED)
- , _tick_rate(tick_node_ctrl::RATE_UNDEFINED)
-{
- _count++;
-}
-
-std::string tx_stream_terminator::unique_id() const
-{
- return str(boost::format("TX Terminator %d") % _term_index);
-}
-
-void tx_stream_terminator::set_rx_streamer(bool, const size_t)
-{
- /* nop */
-}
-
-void tx_stream_terminator::set_tx_streamer(bool active, const size_t /* port */)
-{
- // TODO this is identical to sink_node_ctrl::set_tx_streamer() -> factor out
- UHD_RFNOC_BLOCK_TRACE() << "tx_stream_terminator::set_tx_streamer() " << active;
- for (const node_ctrl_base::node_map_pair_t downstream_node : _downstream_nodes) {
- sink_node_ctrl::sptr curr_downstream_block_ctrl =
- boost::dynamic_pointer_cast<sink_node_ctrl>(downstream_node.second.lock());
- if (curr_downstream_block_ctrl) {
- curr_downstream_block_ctrl->set_tx_streamer(
- active, get_downstream_port(downstream_node.first));
- }
- _tx_streamer_active[downstream_node.first] = active;
- }
-}
-
-tx_stream_terminator::~tx_stream_terminator()
-{
- UHD_RFNOC_BLOCK_TRACE() << "tx_stream_terminator::~tx_stream_terminator() ";
- set_tx_streamer(false, 0);
-}
diff --git a/host/lib/rfnoc/wb_iface_adapter.cpp b/host/lib/rfnoc/wb_iface_adapter.cpp
deleted file mode 100644
index d035ce881..000000000
--- a/host/lib/rfnoc/wb_iface_adapter.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright 2016 Ettus Research LLC
-// Copyright 2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/rfnoc/constants.hpp>
-#include <uhdlib/rfnoc/wb_iface_adapter.hpp>
-
-using namespace uhd::rfnoc;
-
-wb_iface_adapter::wb_iface_adapter(ctrl_iface::sptr iface,
- const gettickrate_type& gettickrate_functor_,
- const settime_type& settime_functor_,
- const gettime_type& gettime_functor_)
- : _iface(iface)
- , gettickrate_functor(gettickrate_functor_)
- , settime_functor(settime_functor_)
- , gettime_functor(gettime_functor_)
-{
- // nop
-}
-
-void wb_iface_adapter::poke32(const wb_addr_type addr, const uint32_t data)
-{
- const uint64_t timestamp = gettime_functor().to_ticks(gettickrate_functor());
- _iface->send_cmd_pkt(addr / 4, data, false, timestamp);
-}
-
-uint32_t wb_iface_adapter::peek32(const wb_addr_type addr)
-{
- const uint64_t reg_value = peek64(addr);
- return ((addr / 4) & 0x1) ? uint32_t(reg_value >> 32)
- : uint32_t(reg_value & 0xffffffff);
-}
-
-uint64_t wb_iface_adapter::peek64(const wb_addr_type addr)
-{
- const uint64_t timestamp = gettime_functor().to_ticks(gettickrate_functor());
- // TODO: Figure out if we should have a timestamp here
- _iface->send_cmd_pkt(SR_READBACK_ADDR, addr / 8, false, timestamp);
- return _iface->send_cmd_pkt(SR_READBACK, SR_READBACK_REG_USER, true, timestamp);
-}
diff --git a/host/lib/rfnoc/window_block_ctrl_impl.cpp b/host/lib/rfnoc/window_block_ctrl_impl.cpp
deleted file mode 100644
index c1a814706..000000000
--- a/host/lib/rfnoc/window_block_ctrl_impl.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-//
-// Copyright 2014-2018 Ettus Research, a National Instruments Company
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-
-#include <uhd/convert.hpp>
-#include <uhd/rfnoc/window_block_ctrl.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");