diff options
Diffstat (limited to 'host/lib/rfnoc')
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"); |