diff options
218 files changed, 244 insertions, 22930 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 17af21824..53e5cba7e 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -301,8 +301,6 @@ link_directories(${Boost_LIBRARY_DIRS}) ######################################################################## # Additional settings for build environment ######################################################################## -# Note: RFNoC never gets fully disabled, but the public APIs do -set(ENABLE_RFNOC ON CACHE BOOL "Export RFNoC includes and symbols") include(UHDGlobalDefs) include(UHDLog) @@ -470,12 +468,7 @@ endforeach(Boost_Comp) if(ENABLE_USB) list(APPEND UHD_LINK_LIST_STATIC "usb-1.0") endif(ENABLE_USB) -# UHDConfig.cmake also needs UHD_RFNOC_FOUND -if(ENABLE_RFNOC) - set(UHD_RFNOC_FOUND "TRUE") -else() - set(UHD_RFNOC_FOUND "FALSE") -endif(ENABLE_RFNOC) +set(UHD_RFNOC_FOUND "TRUE") configure_file( ${CMAKE_SOURCE_DIR}/cmake/Modules/UHDConfigVersion.cmake.in diff --git a/host/cmake/Modules/UHDGlobalDefs.cmake b/host/cmake/Modules/UHDGlobalDefs.cmake index a10d256b5..a137de569 100644 --- a/host/cmake/Modules/UHDGlobalDefs.cmake +++ b/host/cmake/Modules/UHDGlobalDefs.cmake @@ -16,10 +16,5 @@ else() math(EXPR UHD_VERSION_ADDED "1000000 * ${UHD_VERSION_MAJOR} + 10000 * ${UHD_VERSION_API} + 100 * ${UHD_VERSION_ABI} + ${UHD_VERSION_PATCH}") endif(UHD_VERSION_DEVEL) -## RFNoC -if(ENABLE_RFNOC) - add_definitions(-DUHD_RFNOC_ENABLED) -endif(ENABLE_RFNOC) - ## make sure the code knows about config.h add_definitions(-DHAVE_CONFIG_H) diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 8df7c1069..08e4a6766 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -37,9 +37,6 @@ if(ENABLE_MANUAL) set(DOXYGEN_FPGA_MANUAL_REFERENCE "<a href=\"http://files.ettus.com/manual/md_fpga.html\">Part III: FPGA Manual</a>") set(DOXYGEN_STRIP_EXTRA "") set(DOXYGEN_EXCLUDE_DIRS "") - if(NOT ENABLE_RFNOC) - set(DOXYGEN_EXCLUDE_DIRS "${DOXYGEN_EXCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/include/uhd/rfnoc") - endif(NOT ENABLE_RFNOC) # Now, check if we have the FPGA sources as well. # If so, pull them in: if(HAS_FPGA_SUBMODULE) @@ -73,7 +70,7 @@ if(ENABLE_DOXYGEN) file(GLOB_RECURSE header_files ${CMAKE_SOURCE_DIR}/include/*.hpp) file(GLOB_RECURSE h_files ${CMAKE_SOURCE_DIR}/include/*.h) list(APPEND header_files ${h_files}) - set(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files} "${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/gen_basic_funcs.py") + set(DOXYGEN_DEPENDENCIES ${DOXYGEN_DEPENDENCIES} ${header_files}) if(ENABLE_DOXYGEN_FULL) set(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/lib ${CMAKE_SOURCE_DIR}/python") else(ENABLE_DOXYGEN_FULL) diff --git a/host/docs/block_desc_files.dox b/host/docs/block_desc_files.dox deleted file mode 100644 index 20f54e24a..000000000 --- a/host/docs/block_desc_files.dox +++ /dev/null @@ -1,16 +0,0 @@ -/*! \page page_rfnoc_descriptor_file RFNoC Block Descriptor Files - - -\section rfnoc_descriptor_file_nocscript NocScript - -NocScript is a simple DSL designed to augment block definition files for RFNoC. - -\li Statically Typed -\li No implicit typecasting -\li Very few operators - -See \subpage page_nocscript_funcs for a full function reference. - -*/ -// vim:ft=doxygen: - diff --git a/host/docs/mainpage.dox.in b/host/docs/mainpage.dox.in index ebe509fc8..4b3371a57 100644 --- a/host/docs/mainpage.dox.in +++ b/host/docs/mainpage.dox.in @@ -13,7 +13,6 @@ Follow these links to get to the section of the manual you wish to consult, or u \li \subpage page_devices "Part I: Devices & Usage Manual" \li \subpage page_uhd "Part II: UHD Development Manual" \li @DOXYGEN_FPGA_MANUAL_REFERENCE@ -\li \subpage page_rfnoc "Part IV: RFNoC Development Manual" ### Further Information diff --git a/host/docs/rfnoc.dox b/host/docs/rfnoc.dox deleted file mode 100644 index 602b75b46..000000000 --- a/host/docs/rfnoc.dox +++ /dev/null @@ -1,6 +0,0 @@ -/*! \page page_rfnoc RFNoC Development Manual - -\li \subpage page_rfnoc_descriptor_file - -*/ -// vim:ft=doxygen: diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 735795d55..8578e2035 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -28,19 +28,13 @@ set(example_sources latency_test.cpp gpio.cpp sync_to_gps.cpp + rfnoc_nullsource_ce_rx.cpp + rfnoc_rx_to_file.cpp + #rfnoc_radio_loopback.cpp + #benchmark_streamer.cpp + #replay_samples_from_file.cpp ) -if(ENABLE_RFNOC) - list(APPEND - example_sources - rfnoc_nullsource_ce_rx.cpp - rfnoc_rx_to_file.cpp - rfnoc_radio_loopback.cpp - replay_samples_from_file.cpp - benchmark_streamer.cpp - ) -endif(ENABLE_RFNOC) - if(ENABLE_OCTOCLOCK) list(APPEND example_sources test_clock_synch.cpp) endif(ENABLE_OCTOCLOCK) diff --git a/host/examples/benchmark_streamer.cpp b/host/examples/benchmark_streamer.cpp index 2b82acf7e..c2f3a4b2c 100644 --- a/host/examples/benchmark_streamer.cpp +++ b/host/examples/benchmark_streamer.cpp @@ -5,7 +5,6 @@ // #include <uhd/convert.hpp> -#include <uhd/device3.hpp> #include <uhd/rfnoc/block_ctrl.hpp> #include <uhd/rfnoc/ddc_block_ctrl.hpp> #include <uhd/rfnoc/duc_block_ctrl.hpp> diff --git a/host/examples/rfnoc_nullsource_ce_rx.cpp b/host/examples/rfnoc_nullsource_ce_rx.cpp index 640e5bcff..368b6ab5d 100644 --- a/host/examples/rfnoc_nullsource_ce_rx.cpp +++ b/host/examples/rfnoc_nullsource_ce_rx.cpp @@ -20,7 +20,6 @@ // crossbar (provided it has stream-through capabilities) // and then streams the result to the host, writing it into a file. -#include <uhd/device3.hpp> #include <uhd/exception.hpp> #include <uhd/rfnoc/block_control.hpp> #include <uhd/rfnoc/null_block_control.hpp> diff --git a/host/examples/rfnoc_radio_loopback.cpp b/host/examples/rfnoc_radio_loopback.cpp index 92046eebc..dffe30b3b 100644 --- a/host/examples/rfnoc_radio_loopback.cpp +++ b/host/examples/rfnoc_radio_loopback.cpp @@ -8,7 +8,6 @@ // Example UHD/RFNoC application: Connect an rx radio to a tx radio and // run a loopback. -#include <uhd/device3.hpp> #include <uhd/rfnoc/radio_ctrl.hpp> #include <uhd/utils/math.hpp> #include <uhd/utils/safe_main.hpp> diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 95770038e..429d4fe63 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -1,13 +1,11 @@ # # Copyright 2010-2011,2013-2015 Ettus Research LLC # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # -# This is a temporary include - remove once rfnoc is replaced by erfnoc -add_subdirectory(erfnoc) - add_subdirectory(rfnoc) add_subdirectory(transport) add_subdirectory(types) @@ -35,14 +33,6 @@ UHD_INSTALL(FILES COMPONENT headers ) -if(ENABLE_RFNOC) - UHD_INSTALL(FILES - device3.hpp - DESTINATION ${INCLUDE_DIR}/uhd - COMPONENT headers - ) -endif(ENABLE_RFNOC) - if(ENABLE_C_API) UHD_INSTALL(FILES config.h diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 383159005..812006ab5 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -111,13 +111,6 @@ typedef ptrdiff_t ssize_t; # endif // UHD_DLL_EXPORTS #endif // UHD_STATIC_LIB -#ifdef UHD_RFNOC_ENABLED -# define UHD_RFNOC_API UHD_API -#else -# define UHD_RFNOC_API -#endif // UHD_RFNOC_ENABLED - - // Platform defines for conditional parts of headers: // Taken from boost/config/select_platform_config.hpp, // however, we define macros, not strings for platforms. diff --git a/host/include/uhd/device3.hpp b/host/include/uhd/device3.hpp deleted file mode 100644 index c4d0d94fe..000000000 --- a/host/include/uhd/device3.hpp +++ /dev/null @@ -1,145 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_UHD_DEVICE3_HPP -#define INCLUDED_UHD_DEVICE3_HPP - -#include <uhd/device.hpp> -#include <uhd/rfnoc/block_ctrl_base.hpp> -#include <uhd/rfnoc/graph.hpp> -#include <boost/core/demangle.hpp> -#include <boost/thread/mutex.hpp> -#include <vector> - -namespace uhd { - -/*! - * \brief Extends uhd::device for third-generation USRP devices. - * - * Generation-3 devices are characterized by the following traits: - * - They support RFNoC (RF Network-on-Chip). - * - Data transport uses the compressed VITA (CVITA/CHDR) data format. - */ -class UHD_API device3 : public uhd::device -{ -public: - typedef boost::shared_ptr<device3> sptr; - - //! Same as uhd::device::make(), but will fail if not actually a device3 - static sptr make(const device_addr_t& hint, const size_t which = 0); - - virtual rfnoc::graph::sptr create_graph(const std::string& name = "") = 0; - - /*! Reset blocks after a stream. - * - * TODO write docs - */ - void clear(); - - /*! \brief Checks if an RFNoC block exists on the device. - * - * \param block_id Canonical block name (e.g. "0/FFT_1"). - * \return true if a block with the specified id exists - * \note this access is not thread safe if peformed during block enumeration - */ - bool has_block(const rfnoc::block_id_t& block_id) const; - - /*! Same as has_block(), but with a type check. - * - * \return true if a block of type T with the specified id exists - * \note this access is not thread safe if peformed during block enumeration - */ - template <typename T> bool has_block(const rfnoc::block_id_t& block_id) const - { - if (has_block(block_id)) { - return bool(boost::dynamic_pointer_cast<T>(get_block_ctrl(block_id))); - } else { - return false; - } - } - - /*! \brief Returns a block controller class for an RFNoC block. - * - * If the given block ID is not valid (i.e. such a block does not exist - * on this device), it will throw a uhd::lookup_error. - * - * \param block_id Canonical block name (e.g. "0/FFT_1"). - * \note this access is not thread safe if peformed during block enumeration - */ - rfnoc::block_ctrl_base::sptr get_block_ctrl(const rfnoc::block_id_t& block_id) const; - - /*! Same as get_block_ctrl(), but with a type cast. - * - * If you have a block controller class that is derived from block_ctrl_base, - * use this function to access its specific methods. - * If the given block ID is not valid (i.e. such a block does not exist - * on this device) or if the type does not match, it will throw a uhd::lookup_error. - * - * \code{.cpp} - * // Assume DEV is a device3::sptr - * uhd::rfnoc::my_block_ctrl::sptr block_controller = - * get_block_ctrl<my_block_ctrl>("0/MyBlock_0"); - * block_controller->my_own_block_method(); - * \endcode - * \note this access is not thread safe if peformed during block enumeration - */ - template <typename T> - boost::shared_ptr<T> get_block_ctrl(const rfnoc::block_id_t& block_id) const - { - boost::shared_ptr<T> blk = - boost::dynamic_pointer_cast<T>(get_block_ctrl(block_id)); - if (blk) { - return blk; - } else { - throw uhd::lookup_error(str( - boost::format("This device does not have a block of type %s with ID: %s") - % boost::core::demangle(typeid(T).name()) % block_id.to_string())); - } - } - - /*! Returns the block ids of all blocks that match the specified hint - * Uses block_ctrl_base::match() internally. - * If no matching block is found, it returns an empty vector. - * - * To access specialized block controller classes (i.e. derived from block_ctrl_base), - * use the templated version of this function, e.g. - * \code{.cpp} - * // Assume DEV is a device3::sptr - * null_block_ctrl::sptr null_block = - * DEV->find_blocks<null_block_ctrl>("NullSrcSink"); \endcode \note this access is not - * thread safe if peformed during block enumeration - */ - std::vector<rfnoc::block_id_t> find_blocks(const std::string& block_id_hint) const; - - /*! Type-cast version of find_blocks(). - */ - template <typename T> - std::vector<rfnoc::block_id_t> find_blocks(const std::string& block_id_hint) const - { - std::vector<rfnoc::block_id_t> all_block_ids = find_blocks(block_id_hint); - std::vector<rfnoc::block_id_t> filt_block_ids; - for (size_t i = 0; i < all_block_ids.size(); i++) { - if (has_block<T>(all_block_ids[i])) { - filt_block_ids.push_back(all_block_ids[i]); - } - } - return filt_block_ids; - } - -protected: - //! List of *all* RFNoC blocks available on this device. - // It is the responsibility of the deriving class to make - // sure this gets correctly populated. - std::vector<rfnoc::block_ctrl_base::sptr> _rfnoc_block_ctrl; - //! Mutex to protect access to members - boost::mutex _block_ctrl_mutex; -}; - -} // namespace uhd - -#endif /* INCLUDED_UHD_DEVICE3_HPP */ diff --git a/host/include/uhd/erfnoc/CMakeLists.txt b/host/include/uhd/erfnoc/CMakeLists.txt deleted file mode 100644 index e4eddaea2..000000000 --- a/host/include/uhd/erfnoc/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright 2019 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -add_subdirectory(blocks) -add_subdirectory(core)
\ No newline at end of file diff --git a/host/include/uhd/erfnoc/core/CMakeLists.txt b/host/include/uhd/erfnoc/core/CMakeLists.txt deleted file mode 100644 index ef7904789..000000000 --- a/host/include/uhd/erfnoc/core/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# Copyright 2019 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -file(GLOB yml_files "*.yml") -file(GLOB json_files "*.json") - -# We always need this, even when RFNoC is 'disabled' -UHD_INSTALL( - FILES ${yml_files} - DESTINATION ${PKG_DATA_DIR}/erfnoc/core - COMPONENT headers # TODO: Different component -) -UHD_INSTALL( - FILES ${json_files} - DESTINATION ${PKG_DATA_DIR}/erfnoc/core - COMPONENT headers # TODO: Different component -)
\ No newline at end of file diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt index d65332dac..20c8cc38a 100644 --- a/host/include/uhd/rfnoc/CMakeLists.txt +++ b/host/include/uhd/rfnoc/CMakeLists.txt @@ -1,58 +1,45 @@ # # Copyright 2014-2016 Ettus Research LLC # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # -if(ENABLE_RFNOC) - UHD_INSTALL(FILES - # Infrastructure - block_ctrl_base.hpp - block_ctrl.hpp - block_control.hpp - blockdef.hpp - block_id.hpp - constants.hpp - defaults.hpp - dirtifier.hpp - graph.hpp - graph_edge.hpp - mb_controller.hpp - noc_block_make_args.hpp - node_ctrl_base.hpp - node_ctrl_base.ipp - node.hpp - node.ipp - rate_node_ctrl.hpp - registry.hpp - scalar_node_ctrl.hpp - sink_block_ctrl_base.hpp - sink_node_ctrl.hpp - source_block_ctrl_base.hpp - source_node_ctrl.hpp - stream_sig.hpp - terminator_node_ctrl.hpp - tick_node_ctrl.hpp - # Block controllers - ddc_block_control.hpp - duc_block_control.hpp - ddc_block_ctrl.hpp - dma_fifo_block_ctrl.hpp - duc_block_ctrl.hpp - fir_block_ctrl.hpp - null_block_ctrl.hpp - null_block_control.hpp - radio_ctrl.hpp - radio_control.hpp - replay_block_ctrl.hpp - siggen_block_ctrl.hpp - window_block_ctrl.hpp - register_iface.hpp - DESTINATION ${INCLUDE_DIR}/uhd/rfnoc - COMPONENT headers - ) -endif(ENABLE_RFNOC) +UHD_INSTALL(FILES + # Infrastructure + actions.hpp + block_id.hpp + blockdef.hpp + constants.hpp + defaults.hpp + dirtifier.hpp + filter_node.hpp + graph_edge.hpp + mb_controller.hpp + noc_block_base.hpp + noc_block_make_args.hpp + node.hpp + node.ipp + property.hpp + property.ipp + radio_control.hpp + register_iface.hpp + register_iface_holder.hpp + registry.hpp + res_source_info.hpp + traffic_counter.hpp + # Block controllers + block_control.hpp + ddc_block_control.hpp + duc_block_control.hpp + null_block_control.hpp + radio_control.hpp + + DESTINATION ${INCLUDE_DIR}/uhd/rfnoc + COMPONENT headers +) + add_subdirectory(blocks) -#add_subdirectory(components) +add_subdirectory(core) diff --git a/host/include/uhd/rfnoc/block_ctrl.hpp b/host/include/uhd/rfnoc/block_ctrl.hpp deleted file mode 100644 index c26ee0f85..000000000 --- a/host/include/uhd/rfnoc/block_ctrl.hpp +++ /dev/null @@ -1,36 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief This is the default implementation of a block_ctrl_base. - * - * For most blocks, this will be a sufficient implementation. All registers - * can be set by sr_write(). The default behaviour of functions is documented - * in uhd::rfnoc::block_ctrl_base. - */ -class UHD_RFNOC_API block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - // Required macro in RFNoC block classes - UHD_RFNOC_BLOCK_OBJECT(block_ctrl) - - // Nothing else here -- all function definitions are in block_ctrl_base, - // source_block_ctrl_base and sink_block_ctrl_base - -}; /* class block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/block_ctrl_base.hpp b/host/include/uhd/rfnoc/block_ctrl_base.hpp deleted file mode 100644 index 7ad2dc67e..000000000 --- a/host/include/uhd/rfnoc/block_ctrl_base.hpp +++ /dev/null @@ -1,436 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP - -#include <uhd/property_tree.hpp> -#include <uhd/rfnoc/block_id.hpp> -#include <uhd/rfnoc/blockdef.hpp> -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/rfnoc/stream_sig.hpp> -#include <uhd/stream.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <uhd/types/wb_iface.hpp> -#include <uhd/utils/static.hpp> -#include <stdint.h> -#include <boost/shared_ptr.hpp> - -namespace uhd { namespace rfnoc { -// Forward declarations -class ctrl_iface; -namespace nocscript { -class block_iface; -} - - -// TODO: Move this out of public section -struct make_args_t -{ - make_args_t(const std::string& key = "") - : device_index(0), block_name(""), block_key(key) - { - } - - //! A valid interface that allows us to read and write registers - std::map<size_t, boost::shared_ptr<ctrl_iface> > ctrl_ifaces; - //! This block's base address (address of block port 0) - uint32_t base_address; - //! The device index (or motherboard index). - size_t device_index; - //! A property tree for this motherboard. Example: If the root a device's - // property tree is /mboards/0, pass a subtree starting at /mboards/0 - // to the constructor. - uhd::property_tree::sptr tree; - //! The name of the block as it will be addressed - std::string block_name; - //! The key of the block, i.e. how it was registered - std::string block_key; -}; - -//! This macro must be put in the public section of an RFNoC -// block class -#define UHD_RFNOC_BLOCK_OBJECT(class_name) typedef boost::shared_ptr<class_name> sptr; - -//! Shorthand for block constructor -#define UHD_RFNOC_BLOCK_CONSTRUCTOR(CLASS_NAME) \ - CLASS_NAME##_impl(const make_args_t& make_args) : block_ctrl_base(make_args) - -//! This macro must be placed inside a block implementation file -// after the class definition -#define UHD_RFNOC_BLOCK_REGISTER(CLASS_NAME, BLOCK_NAME) \ - block_ctrl_base::sptr CLASS_NAME##_make(const make_args_t& make_args) \ - { \ - return block_ctrl_base::sptr(new CLASS_NAME##_impl(make_args)); \ - } \ - UHD_STATIC_BLOCK(register_rfnoc_##CLASS_NAME) \ - { \ - uhd::rfnoc::block_ctrl_base::register_block(&CLASS_NAME##_make, BLOCK_NAME); \ - } - -/*! \brief Base class for all RFNoC block controller objects. - * - * For RFNoC, block controller objects must be derived from - * uhd::rfnoc::block_ctrl_base. This class provides all functions - * that a block *must* provide. Typically, you would not derive - * a block controller class directly from block_ctrl_base, but - * from a class such as uhd::usrp::rfnoc::source_block_ctrl_base or - * uhd::usrp::rfnoc::sink_block_ctrl_base which extends its functionality. - */ -class UHD_RFNOC_API block_ctrl_base; -class block_ctrl_base : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<block_ctrl_base> sptr; - typedef boost::function<sptr(const make_args_t&)> make_t; - - /*********************************************************************** - * Factory functions - **********************************************************************/ - - /*! Register a block controller class into the discovery and factory system. - * - * Note: It is not recommended to call this function directly. - * Rather, use the UHD_RFNOC_BLOCK_REGISTER() macro, which will set up - * the discovery and factory system correctly. - * - * \param make A factory function that makes a block controller object - * \param name A unique block name, e.g. 'FFT'. If a block has this block name, - * it will use \p make to generate the block controller class. - */ - static void register_block(const make_t& make, const std::string& name); - - /*! - * \brief Create a block controller class given a NoC-ID or a block name. - * - * If a block name is given in \p make_args, it will directly try to - * generate a block of this type. If no block name is given, it will - * look up a name using the NoC-ID and use that. - * If it can't find a suitable block controller class, it will generate - * a uhd::rfnoc::block_ctrl. However, if a block name *is* specified, - * it will throw a uhd::runtime_error if this block type is not registered. - * - * \param make_args Valid make args. - * \param noc_id The 64-Bit NoC-ID. - * \return a shared pointer to a new device instance - */ - static sptr make(const make_args_t& make_args, uint64_t noc_id = ~0); - - /*********************************************************************** - * Block Communication and Control - * - * These functions do not require communication with the FPGA. - **********************************************************************/ - - /*! Returns the 16-Bit address for this block. - */ - uint32_t get_address(size_t block_port = 0); - - /*! Returns the unique block ID for this block (e.g. "0/FFT_1"). - */ - block_id_t get_block_id() const - { - return _block_id; - }; - - /*! Shorthand for get_block_id().to_string() - */ - std::string unique_id() const - { - return _block_id.to_string(); - }; - - /*********************************************************************** - * FPGA control & communication - **********************************************************************/ - - /*! Returns a list of valid ports that can be used for sr_write(), sr_read() etc. - */ - std::vector<size_t> get_ctrl_ports() const; - - /*! Allows setting one register on the settings bus. - * - * Note: There is no address translation ("memory mapping") necessary. - * Register 0 is 0, 1 is 1 etc. - * - * \param reg The settings register to write to. - * \param data New value of this register. - * \param port Port on which to write - */ - void sr_write(const uint32_t reg, const uint32_t data, const size_t port = 0); - - /*! Allows setting one register on the settings bus. - * - * Like sr_write(), but takes a register name as argument. - * - * \param reg The settings register to write to. - * \param data New value of this register. - * \param port Port on which to write - * \throw uhd::key_error if \p reg is not a valid register name - * - */ - void sr_write(const std::string& reg, const uint32_t data, const size_t port = 0); - - /*! Allows reading one register on the settings bus (64-Bit version). - * - * \param reg The settings register to be read. - * \param port Port on which to read - * - * Returns the readback value. - */ - uint64_t sr_read64(const settingsbus_reg_t reg, const size_t port = 0); - - /*! Allows reading one register on the settings bus (32-Bit version). - * - * \param reg The settings register to be read. - * \param port Port on which to read - * - * Returns the readback value. - */ - uint32_t sr_read32(const settingsbus_reg_t reg, const size_t port = 0); - - /*! Allows reading one user-defined register (64-Bit version). - * - * This is a shorthand for setting the requested address - * through sr_write() and then reading SR_READBACK_REG_USER - * with sr_read64(). - * - * \param addr The user register address. - * \param port Port on which to read - * \returns the readback value. - */ - uint64_t user_reg_read64(const uint32_t addr, const size_t port = 0); - - /*! Allows reading one user-defined register (64-Bit version). - * - * Identical to user_reg_read64(), but takes a register name - * instead of a numeric address. The register name must be - * defined in the block definition file. - * - * \param reg The user register address. - * \param port Port on which to read - * \returns the readback value. - * \throws uhd::key_error if \p reg is not a valid register name - */ - uint64_t user_reg_read64(const std::string& reg, const size_t port = 0); - - /*! Allows reading one user-defined register (32-Bit version). - * - * This is a shorthand for setting the requested address - * through sr_write() and then reading SR_READBACK_REG_USER - * with sr_read32(). - * - * \param addr The user register address. - * \param port Port on which to read - * \returns the readback value. - */ - uint32_t user_reg_read32(const uint32_t addr, const size_t port = 0); - - /*! Allows reading one user-defined register (32-Bit version). - * - * Identical to user_reg_read32(), but takes a register name - * instead of a numeric address. The register name must be - * defined in the block definition file. - * - * \param reg The user register name. - * \param port Destination port from which to read. - * \returns the readback value. - * \throws uhd::key_error if \p reg is not a valid register name - */ - uint32_t user_reg_read32(const std::string& reg, const size_t port = 0); - - - /*! Sets a command time for all future command packets. - * - * \throws uhd::assertion_error if the underlying interface does not - * actually support timing. - */ - void set_command_time(const time_spec_t& time_spec, const size_t port = ANY_PORT); - - /*! Returns the current command time for all future command packets. - * - * \returns the command time as a time_spec_t. - */ - time_spec_t get_command_time(const size_t port = 0); - - /*! Sets a tick rate for the command timebase. - * - * \param tick_rate The tick rate in Hz - * \param port Port - */ - void set_command_tick_rate(const double tick_rate, const size_t port = ANY_PORT); - - /*! Resets the command time. - * Any command packet after this call will no longer have a time associated - * with it. - * - * \throws uhd::assertion_error if the underlying interface does not - * actually support timing. - */ - void clear_command_time(const size_t port); - - /*! Reset block after streaming operation. - * - * This does the following: - * - Reset flow control (sequence numbers etc.) - * - Clear the list of connected blocks - * - * Internally, rfnoc::node_ctrl_base::clear() and _clear() are called - * (in that order). - * - * Between runs, it can be necessary to call this method, - * or blocks might be left hanging in a streaming state, and can get - * confused when a new application starts. - * - * For custom behaviour, overwrite _clear(). If you do so, you must take - * take care of resetting flow control yourself. - * - * TODO: Find better name (it disconnects, clears FC...) - */ - void clear(); - - /*********************************************************************** - * Argument handling - **********************************************************************/ - /*! Set multiple block args. Calls set_arg() for all individual items. - * - * Note that this function will silently ignore any keys in \p args that - * aren't already registered as block arguments. - */ - void set_args(const uhd::device_addr_t& args, const size_t port = 0); - - //! Set a specific block argument. \p val is converted to the corresponding - // data type using by looking up its type in the block definition. - void set_arg(const std::string& key, const std::string& val, const size_t port = 0); - - //! Direct access to set a block argument. - template <typename T> - void set_arg(const std::string& key, const T& val, const size_t port = 0) - { - _tree->access<T>(get_arg_path(key, port) / "value").set(val); - } - - //! Return all block arguments as a device_addr_t. - uhd::device_addr_t get_args(const size_t port = 0) const; - - //! Return a single block argument in string format. - std::string get_arg(const std::string& key, const size_t port = 0) const; - - //! Direct access to get a block argument. - template <typename T> - T get_arg(const std::string& key, const size_t port = 0) const - { - return _tree->access<T>(get_arg_path(key, port) / "value").get(); - } - - std::string get_arg_type(const std::string& key, const size_t port = 0) const; - -protected: - /*********************************************************************** - * Structors - **********************************************************************/ - block_ctrl_base(void){}; // To allow pure virtual (interface) sub-classes - virtual ~block_ctrl_base(); - - /*! Constructor. This is only called from the internal block factory! - * - * \param make_args All arguments to this constructor are passed in this object. - * Its details are subject to change. Use the - * UHD_RFNOC_BLOCK_CONSTRUCTOR() macro to set up your block's constructor in a - * portable fashion. - */ - block_ctrl_base(const make_args_t& make_args); - - /*********************************************************************** - * Helpers - **********************************************************************/ - stream_sig_t _resolve_port_def(const blockdef::port_t& port_def) const; - - //! Return the property tree path to a block argument \p key on \p port - uhd::fs_path get_arg_path(const std::string& key, size_t port = 0) const - { - return _root_path / "args" / port / key; - }; - - //! Get a control interface object for block port \p block_port - timed_wb_iface::sptr get_ctrl_iface(const size_t block_port); - - /*********************************************************************** - * Hooks & Derivables - **********************************************************************/ - - //! Override this function if your block does something else - // than reset register SR_CLEAR_TX_FC. - virtual void _clear(const size_t port = 0); - - //! Override this function if your block needs to specially handle - // setting the command time - virtual void _set_command_time( - const time_spec_t& time_spec, const size_t port = ANY_PORT); - /*********************************************************************** - * Protected members - **********************************************************************/ - - //! Property sub-tree - uhd::property_tree::sptr _tree; - - //! Root node of this block's properties - uhd::fs_path _root_path; - - //! Block definition (stores info about the block such as ports) - blockdef::sptr _block_def; - -private: - //! Helper function to initialize the port definition nodes in the prop tree - void _init_port_defs(const std::string& direction, - blockdef::ports_t ports, - const size_t first_port_index = 0); - - //! Helper function to initialize the block args (used by ctor only) - void _init_block_args(); - - //! Helper to create a lambda to read tick rate - double get_command_tick_rate(const size_t port); - - //! Helper to start flushing for this block - void _start_drain(const size_t port = 0); - - //! Helper to flush any in-flight packets for this block - bool _flush(const size_t port = 0); - - /*********************************************************************** - * Private members - **********************************************************************/ - //! Objects to actually send and receive the commands - std::map<size_t, boost::shared_ptr<ctrl_iface> > _ctrl_ifaces; - std::map<size_t, time_spec_t> _cmd_timespecs; - std::map<size_t, double> _cmd_tickrates; - - //! The base address of this block (the address of block port 0) - uint32_t _base_address; - - //! 64-bit NoC ID of this block - uint64_t _noc_id; - - //! noc_shell compat number, as one 64-bit number [major,minor] - uint64_t _compat_num; - - //! The (unique) block ID. - block_id_t _block_id; - - //! Interface to NocScript parser - boost::shared_ptr<nocscript::block_iface> _nocscript_iface; -}; /* class block_ctrl_base */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_BLOCK_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/block_id.hpp b/host/include/uhd/rfnoc/block_id.hpp index 77b2ba5a0..106fb394f 100644 --- a/host/include/uhd/rfnoc/block_id.hpp +++ b/host/include/uhd/rfnoc/block_id.hpp @@ -37,7 +37,7 @@ namespace rfnoc { * * This class can represent these block IDs. */ -class UHD_RFNOC_API block_id_t +class UHD_API block_id_t { public: block_id_t(); diff --git a/host/include/uhd/rfnoc/blockdef.hpp b/host/include/uhd/rfnoc/blockdef.hpp index 30c5219e1..e35c8e234 100644 --- a/host/include/uhd/rfnoc/blockdef.hpp +++ b/host/include/uhd/rfnoc/blockdef.hpp @@ -19,7 +19,7 @@ namespace uhd { namespace rfnoc { /*! Reads and stores block definitions for blocks and components. */ -class UHD_RFNOC_API blockdef : public boost::enable_shared_from_this<blockdef> +class UHD_API blockdef : public boost::enable_shared_from_this<blockdef> { public: typedef boost::shared_ptr<blockdef> sptr; diff --git a/host/include/uhd/rfnoc/blocks/CMakeLists.txt b/host/include/uhd/rfnoc/blocks/CMakeLists.txt index 08537673a..28e33f651 100644 --- a/host/include/uhd/rfnoc/blocks/CMakeLists.txt +++ b/host/include/uhd/rfnoc/blocks/CMakeLists.txt @@ -1,15 +1,14 @@ # -# Copyright 2014-2016 Ettus Research LLC -# Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Company # # SPDX-License-Identifier: GPL-3.0-or-later # -file(GLOB xml_files "*.xml") +file(GLOB yml_files "*.yml") # We always need this, even when RFNoC is 'disabled' UHD_INSTALL( - FILES ${xml_files} + FILES ${yml_files} DESTINATION ${PKG_DATA_DIR}/rfnoc/blocks COMPONENT headers # TODO: Different component ) diff --git a/host/include/uhd/rfnoc/blocks/addsub.xml b/host/include/uhd/rfnoc/blocks/addsub.xml deleted file mode 100644 index 2412e5022..000000000 --- a/host/include/uhd/rfnoc/blocks/addsub.xml +++ /dev/null @@ -1,50 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <!--The Adder & Subtractor takes inputs from Block Ports 0 & 1 and--> - <!--outputs the addition / subtraction of the values on Block Ports 0 & 1.--> - <!--- Block Port 0 + Block Port 1 => Block Port 0--> - <!--- Block Port 0 - Block Port 1 => Block Port 1--> - <name>Adder & Subtractor</name> - <blockname>AddSub</blockname> - <ids> - <id revision="0">ADD0</id> - </ids> - <!--Order matters. The first listed port is port 0, etc.--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - <port>0</port> - </sink> - <sink> - <name>in1</name> - <type>sc16</type> - <port>1</port> - </sink> - <source> - <name>sum</name> - <type>sc16</type> - </source> - <source> - <name>diff</name> - <type>sc16</type> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/block.xml b/host/include/uhd/rfnoc/blocks/block.xml deleted file mode 100644 index dfe616c45..000000000 --- a/host/include/uhd/rfnoc/blocks/block.xml +++ /dev/null @@ -1,17 +0,0 @@ -<!--Default XML file--> -<nocblock> - <name>Block</name> - <blockname>Block</blockname> - <ids> - <id revision="0">FFFFFFFFFFFFFFFF</id> - </ids> - <!--One input, one output. If this is used, better have all the info the C++ file.--> - <ports> - <sink> - <name>in</name> - </sink> - <source> - <name>out</name> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/ddc.xml b/host/include/uhd/rfnoc/blocks/ddc.xml deleted file mode 100644 index 43e325c0e..000000000 --- a/host/include/uhd/rfnoc/blocks/ddc.xml +++ /dev/null @@ -1,154 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Rx DSP (DDC/CORDIC)</name> - <blockname>DDC</blockname> - <key>DDC</key> - <!--There can be several of these:--> - <ids> - <id revision="0">DDC0000000000000</id> - </ids> - <!-- Registers --> - <registers> - <!-- AXI rate change block registers --> - <setreg> - <name>N</name> - <address>128</address> - </setreg> - <setreg> - <name>M</name> - <address>129</address> - </setreg> - <setreg> - <!-- 1 bit, enable clear user --> - <name>CONFIG</name> - <address>130</address> - </setreg> - <!-- DDC block registers --> - <setreg> - <!-- DDS phase increment word --> - <name>DDS_FREQ</name> - <address>132</address> - </setreg> - <setreg> - <!-- Scaling factor to compensate for gain through filters and CORDIC --> - <name>SCALE_IQ</name> - <address>133</address> - </setreg> - <setreg> - <!-- DDC control word, 10 bits total, 2 bits for Halfbands, 8 bits for CIC rate --> - <name>DECIM_WORD</name> - <address>134</address> - </setreg> - <setreg> - <!-- Real mode, swap IQ --> - <name>MODE</name> - <address>135</address> - </setreg> - <setreg> - <!-- Filter coefficients reload --> - <name>RELOAD</name> - <address>136</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>0</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>1</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <source> - <name>out1</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/erfnoc/blocks/ddc_1x64.yml b/host/include/uhd/rfnoc/blocks/ddc_1x64.yml index 3d21ea527..3d21ea527 100644 --- a/host/include/uhd/erfnoc/blocks/ddc_1x64.yml +++ b/host/include/uhd/rfnoc/blocks/ddc_1x64.yml diff --git a/host/include/uhd/erfnoc/blocks/ddc_2x64.yml b/host/include/uhd/rfnoc/blocks/ddc_2x64.yml index a79a07c8f..a79a07c8f 100644 --- a/host/include/uhd/erfnoc/blocks/ddc_2x64.yml +++ b/host/include/uhd/rfnoc/blocks/ddc_2x64.yml diff --git a/host/include/uhd/rfnoc/blocks/ddc_eiscat.xml b/host/include/uhd/rfnoc/blocks/ddc_eiscat.xml deleted file mode 100644 index df39ce891..000000000 --- a/host/include/uhd/rfnoc/blocks/ddc_eiscat.xml +++ /dev/null @@ -1,331 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>EISCAT Rx DSP (DDC/CORDIC)</name> - <blockname>DDC</blockname> - <key>DDC</key> - <!--There can be several of these:--> - <ids> - <id revision="0">DDC5E15CA7000000</id> - </ids> - <!-- Registers --> - <registers> - <!-- AXI rate change block registers --> - <setreg> - <name>N</name> - <address>128</address> - </setreg> - <setreg> - <name>M</name> - <address>129</address> - </setreg> - <setreg> - <!-- 1 bit, enable clear user --> - <name>CONFIG</name> - <address>130</address> - </setreg> - <!-- DDC block registers --> - <setreg> - <!-- DDS phase increment word --> - <name>DDS_FREQ</name> - <address>132</address> - </setreg> - <setreg> - <!-- Scaling factor to compensate for gain through filters and CORDIC --> - <name>SCALE_IQ</name> - <address>133</address> - </setreg> - <setreg> - <!-- DDC control word, 10 bits total, 2 bits for Halfbands, 8 bits for CIC rate --> - <name>DECIM_WORD</name> - <address>134</address> - </setreg> - <setreg> - <!-- Real mode, swap IQ --> - <!-- Real mode = bit 1, swap IQ = bit 0 --> - <name>MODE</name> - <address>135</address> - </setreg> - <setreg> - <!-- Filter coefficients reload --> - <name>RELOAD</name> - <address>136</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>0</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>mode</name> - <type>int</type> - <value>2</value> - <port>0</port> - <action>SR_WRITE("MODE", $mode)</action> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>1</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>mode</name> - <type>int</type> - <value>2</value> - <port>1</port> - <action>SR_WRITE("MODE", $mode)</action> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>2</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>mode</name> - <type>int</type> - <value>2</value> - <port>2</port> - <action>SR_WRITE("MODE", $mode)</action> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>2</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>2</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>2</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>2</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>3</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>mode</name> - <type>int</type> - <value>2</value> - <port>3</port> - <action>SR_WRITE("MODE", $mode)</action> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>3</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>3</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>3</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>3</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>4</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>mode</name> - <type>int</type> - <value>2</value> - <port>4</port> - <action>SR_WRITE("MODE", $mode)</action> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>4</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>4</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>4</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>4</port> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>s16</type> - </sink> - <sink> - <name>in1</name> - <type>s16</type> - </sink> - <sink> - <name>in2</name> - <type>s16</type> - </sink> - <sink> - <name>in3</name> - <type>s16</type> - </sink> - <sink> - <name>in4</name> - <type>s16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <source> - <name>out1</name> - <type>sc16</type> - </source> - <source> - <name>out2</name> - <type>sc16</type> - </source> - <source> - <name>out3</name> - <type>sc16</type> - </source> - <source> - <name>out4</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/ddc_single.xml b/host/include/uhd/rfnoc/blocks/ddc_single.xml deleted file mode 100644 index 1843adb5b..000000000 --- a/host/include/uhd/rfnoc/blocks/ddc_single.xml +++ /dev/null @@ -1,117 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Rx DSP (DDC/CORDIC)</name> - <blockname>DDC</blockname> - <key>DDC</key> - <!--There can be several of these:--> - <ids> - <id revision="0">DDC0000000000001</id> - </ids> - <!-- Registers --> - <registers> - <!-- AXI rate change block registers --> - <setreg> - <name>N</name> - <address>128</address> - </setreg> - <setreg> - <name>M</name> - <address>129</address> - </setreg> - <setreg> - <!-- 1 bit, enable clear user --> - <name>CONFIG</name> - <address>130</address> - </setreg> - <!-- DDC block registers --> - <setreg> - <!-- DDS phase increment word --> - <name>DDS_FREQ</name> - <address>132</address> - </setreg> - <setreg> - <!-- Scaling factor to compensate for gain through filters and CORDIC --> - <name>SCALE_IQ</name> - <address>133</address> - </setreg> - <setreg> - <!-- DDC control word, 10 bits total, 2 bits for Halfbands, 8 bits for CIC rate --> - <name>DECIM_WORD</name> - <address>134</address> - </setreg> - <setreg> - <!-- Real mode, swap IQ --> - <name>MODE</name> - <address>135</address> - </setreg> - <setreg> - <!-- Filter coefficients reload --> - <name>RELOAD</name> - <address>136</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>0</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($fullscale, 0.0)</check> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>1</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/debug.xml b/host/include/uhd/rfnoc/blocks/debug.xml deleted file mode 100644 index 9210b8c2c..000000000 --- a/host/include/uhd/rfnoc/blocks/debug.xml +++ /dev/null @@ -1,49 +0,0 @@ -<nocblock> - <name>Debug</name> - <blockname>Debug</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">DEB1200000000000</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>CONFIG</name> - <address>128</address> - </setreg> - <setreg> - <name>PAYLOAD_SIZE</name> - <address>129</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>config</name> - <type>int</type> - <value>0</value> - <action>SR_WRITE("CONFIG", $config)</action> - </arg> - <arg> - <name>spp</name> - <type>int</type> - <value>64</value> - <action>SR_WRITE("PAYLOAD_SIZE", $spp)</action> - </arg> - </args> - <!-- Ports --> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - </sink> - <source> - <name>out</name> - <type>sc16</type> - </source> - <source> - <name>stats</name> - <type>sc16</type> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/digital_gain.xml b/host/include/uhd/rfnoc/blocks/digital_gain.xml deleted file mode 100644 index 8d22dec04..000000000 --- a/host/include/uhd/rfnoc/blocks/digital_gain.xml +++ /dev/null @@ -1,39 +0,0 @@ -<nocblock> - <name>Digital Gain</name> - <blockname>DigitalGain</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">B160</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>GAIN</name> - <address>128</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <check>GE($gain, 0.0) AND LE($gain, 32767.0)</check> - <check_message>Invalid gain.</check_message> - <action> - SR_WRITE("GAIN", IROUND($gain)) - </action> - </arg> - </args> - <!-- Ports --> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/dma_fifo.xml b/host/include/uhd/rfnoc/blocks/dma_fifo.xml deleted file mode 100644 index 0de791b22..000000000 --- a/host/include/uhd/rfnoc/blocks/dma_fifo.xml +++ /dev/null @@ -1,64 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>DMA FIFO</name> - <blockname>DmaFIFO</blockname> - <key>DmaFIFO</key> - <!--There can be several of these:--> - <ids> - <id revision="0">F1F0D00000000000</id> - </ids> - <!-- Registers --> - <registers> - </registers> - <!-- Args --> - <args> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>0</value>--> - <port>0</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>0</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>1</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>1</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - </sink> - <sink> - <name>in1</name> - </sink> - <source> - <name>out0</name> - </source> - <source> - <name>out1</name> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/dma_fifo_x4.xml b/host/include/uhd/rfnoc/blocks/dma_fifo_x4.xml deleted file mode 100644 index b02e7c8c9..000000000 --- a/host/include/uhd/rfnoc/blocks/dma_fifo_x4.xml +++ /dev/null @@ -1,109 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>DMA FIFO</name> - <blockname>DmaFIFO</blockname> - <key>DmaFIFO</key> - <!--There can be several of these:--> - <ids> - <id revision="0">F1F0D00000000004</id> - </ids> - <!-- Registers --> - <registers> - </registers> - <!-- Args --> - <args> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>0</value>--> - <port>0</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>0</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>1</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>1</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>67108864</value>--> - <port>2</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>2</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - <arg> - <name>base_addr</name> - <type>int</type> - <!--<value>100663296</value>--> - <port>3</port> - <check>EQUAL($base_addr, 0) OR IS_PWR_OF_2($base_addr)</check> - <check_message>The base address must be 0 or a positive power of 2.</check_message> - </arg> - <arg> - <name>depth</name> - <type>int</type> - <!--<value>33554432</value>--> - <port>3</port> - <check>IS_PWR_OF_2($depth)</check> - <check_message>The FIFO depth must be a positive power of 2.</check_message> - </arg> - - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - </sink> - <sink> - <name>in1</name> - </sink> - <sink> - <name>in2</name> - </sink> - <sink> - <name>in3</name> - </sink> - <source> - <name>out0</name> - </source> - <source> - <name>out1</name> - </source> - <source> - <name>out2</name> - </source> - <source> - <name>out3</name> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/duc.xml b/host/include/uhd/rfnoc/blocks/duc.xml deleted file mode 100644 index ea83942da..000000000 --- a/host/include/uhd/rfnoc/blocks/duc.xml +++ /dev/null @@ -1,145 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Tx DSP (DUC/CORDIC)</name> - <blockname>DUC</blockname> - <key>DUC</key> - <!--There can be several of these:--> - <ids> - <id revision="0">D0C0000000000002</id> - </ids> - <!-- Registers --> - <registers> - <!-- AXI rate change block registers --> - <setreg> - <name>N</name> - <address>128</address> - </setreg> - <setreg> - <name>M</name> - <address>129</address> - </setreg> - <setreg> - <!-- 1 bit, enable clear user --> - <name>CONFIG</name> - <address>130</address> - </setreg> - <!-- DUC block registers --> - <setreg> - <name>INTERP_WORD</name> <!--Includes the half-bands and the CIC--> - <address>131</address> - </setreg> - <setreg> - <name>DDS_FREQ</name> - <address>132</address> - </setreg> - <setreg> - <name>SCALE_IQ</name> - <address>133</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>0</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($fullscale, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - </arg> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>1</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - <check>GE($fullscale, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - </arg> -</args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <source> - <name>out1</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/erfnoc/blocks/duc_1x64.yml b/host/include/uhd/rfnoc/blocks/duc_1x64.yml index 515f426f2..515f426f2 100644 --- a/host/include/uhd/erfnoc/blocks/duc_1x64.yml +++ b/host/include/uhd/rfnoc/blocks/duc_1x64.yml diff --git a/host/include/uhd/erfnoc/blocks/duc_2x64.yml b/host/include/uhd/rfnoc/blocks/duc_2x64.yml index fd8add930..fd8add930 100644 --- a/host/include/uhd/erfnoc/blocks/duc_2x64.yml +++ b/host/include/uhd/rfnoc/blocks/duc_2x64.yml diff --git a/host/include/uhd/rfnoc/blocks/duc_single.xml b/host/include/uhd/rfnoc/blocks/duc_single.xml deleted file mode 100644 index 235788989..000000000 --- a/host/include/uhd/rfnoc/blocks/duc_single.xml +++ /dev/null @@ -1,96 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Tx DSP (DUC/CORDIC)</name> - <blockname>DUC</blockname> - <key>DUC</key> - <!--There can be several of these:--> - <ids> - <id revision="0">D0C0000000000000</id> - </ids> - <!-- Registers --> - <registers> - <!-- AXI rate change block registers --> - <setreg> - <name>N</name> - <address>128</address> - </setreg> - <setreg> - <name>M</name> - <address>129</address> - </setreg> - <setreg> - <!-- 1 bit, enable clear user --> - <name>CONFIG</name> - <address>130</address> - </setreg> - <!-- DUC block registers --> - <setreg> - <name>INTERP_WORD</name> <!--Includes the half-bands and the CIC--> - <address>131</address> - </setreg> - <setreg> - <name>DDS_FREQ</name> - <address>132</address> - </setreg> - <setreg> - <name>SCALE_IQ</name> - <address>133</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>freq</name> - <type>double</type> - <value>0.0</value> - <port>0</port> - <!--<action>--> - <!--SR_WRITE("CORDIC_FREQ", $cordic_freq)--> - <!--</action>--> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>input_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($input_rate, 0.0)</check> - <check_message>The input rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>output_rate</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($output_rate, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - </arg> - <arg> - <name>fullscale</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - <check>GE($fullscale, 0.0)</check> - <check_message>The output rate must be a positive value (in Hz).</check_message> - <!--FIXME Calculate this properly--> - </arg> - <arg> - <name>scalar_correction</name> - <type>double</type> - <value>1.0</value> - <port>0</port> - </arg> -</args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - </sink> - <source> - <name>out</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/fft.xml b/host/include/uhd/rfnoc/blocks/fft.xml deleted file mode 100644 index af51d0ddb..000000000 --- a/host/include/uhd/rfnoc/blocks/fft.xml +++ /dev/null @@ -1,147 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>FFT</name> - <blockname>FFT</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">FF70</id> - </ids> - <!-- Registers --> - <registers> - <!--Note: AXI config bus uses 129 & 130--> - <setreg> - <name>FFT_RESET</name> - <address>131</address> - </setreg> - <setreg> - <name>FFT_SIZE_LOG2</name> - <address>132</address> - </setreg> - <setreg> - <name>MAGNITUDE_OUT</name> - <address>133</address> - </setreg> - <setreg> - <name>FFT_DIRECTION</name> - <address>134</address> - </setreg> - <setreg> - <name>FFT_SCALING</name> - <address>135</address> - </setreg> - <setreg> - <name>FFT_SHIFT_CONFIG</name> - <address>136</address> - </setreg> - <readback> - <name>RB_FFT_RESET</name> - <address>0</address> - </readback> - <readback> - <name>RB_MAGNITUDE_OUT</name> - <address>1</address> - </readback> - <readback> - <name>RB_FFT_SIZE_LOG2</name> - <address>2</address> - </readback> - <readback> - <name>RB_FFT_DIRECTION</name> - <address>3</address> - </readback> - <readback> - <name>RB_FFT_SCALING</name> - <address>4</address> - </readback> - <readback> - <name>RB_FFT_SHIFT_CONFIG</name> - <address>5</address> - </readback> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>256</value> - <check>GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)</check> - <check_message>FFT size must be in [16, 4096] and a power of two.</check_message> - <action>SR_WRITE("FFT_SIZE_LOG2", LOG2($spp))</action> - </arg> - <arg> - <name>shift</name> - <type>string</type> - <value>normal</value> - <check>EQUAL($shift, "normal") OR EQUAL($shift, "reverse") OR EQUAL($shift, "natural")</check> - <check_message>FFT direction must be either "normal", "reverse", or "natural".</check_message> - <action> - IF(EQUAL($shift, "normal"), SR_WRITE("FFT_SHIFT_CONFIG", 0)) OR - IF(EQUAL($shift, "reverse"), SR_WRITE("FFT_SHIFT_CONFIG", 1)) OR - IF(EQUAL($shift, "natural"), SR_WRITE("FFT_SHIFT_CONFIG", 2)) - </action> - </arg> - <arg> - <name>direction</name> - <type>string</type> - <value>forward</value> - <check>EQUAL($direction, "forward") OR EQUAL($direction, "reverse")</check> - <check_message>FFT direction must be either "forward" or "reverse".</check_message> - <action> - IF(EQUAL($direction, "forward"), SR_WRITE("FFT_DIRECTION", 1)) OR - IF(EQUAL($direction, "reverse"), SR_WRITE("FFT_DIRECTION", 0)) - </action> - </arg> - <arg> - <name>scaling</name> - <type>int</type> - <!--scaling per radix-4 butterfly--> - <value>1706</value> - <action>SR_WRITE("FFT_SCALING", $scaling)</action> - </arg> - <arg> - <name>otype</name> - <type>string</type> - <value>sc16</value> - <check>EQUAL($otype, "sc16")</check> - <check_message>Output data type must be sc16.</check_message> - <!--TODO: Check against mag-out value (requires GET() function) --> - </arg> - <arg> - <name>reset</name> - <type>int</type> - <value>1</value> - <action> - IF(NOT(EQUAL($reset, 0)), SR_WRITE("FFT_RESET", 1) AND SR_WRITE("FFT_RESET", 0)) - </action> - <!--TODO: Set to zero after setting, add publisher--> - </arg> - <arg> - <name>magnitude_out</name> - <type>string</type> - <value>COMPLEX</value> - <check>EQUAL($magnitude_out, "COMPLEX") OR EQUAL($magnitude_out, "MAGNITUDE") OR EQUAL($magnitude_out, "MAGNITUDE_SQUARED")</check> - <check_message>Output format must be one of: COMPLEX, MAGNITUDE, MAGNITUDE_SQUARED.</check_message> - <action> - IF(EQUAL($magnitude_out, "COMPLEX"), SR_WRITE("MAGNITUDE_OUT", 0)) OR - IF(EQUAL($magnitude_out, "MAGNITUDE"), SR_WRITE("MAGNITUDE_OUT", 1)) OR - IF(EQUAL($magnitude_out, "MAGNITUDE_SQUARED"), SR_WRITE("MAGNITUDE_OUT", 2)) - </action> - <!--TODO: add publisher--> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out</name> - <type>$otype</type> <!--TODO make this dependent on the output type --> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/fifo.xml b/host/include/uhd/rfnoc/blocks/fifo.xml deleted file mode 100644 index 07b01c6ea..000000000 --- a/host/include/uhd/rfnoc/blocks/fifo.xml +++ /dev/null @@ -1,36 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>FIFO</name> - <blockname>FIFO</blockname> - <!--Use default block controller--> - <key>Block</key> - <!--There can be several of these:--> - <ids> - <id revision="0">F1F00000</id> - </ids> - <ports> - <sink> - <name>in0</name> - </sink> - <source> - <name>out0</name> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/fir.xml b/host/include/uhd/rfnoc/blocks/fir.xml deleted file mode 100644 index 9a97e3a84..000000000 --- a/host/include/uhd/rfnoc/blocks/fir.xml +++ /dev/null @@ -1,19 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>FIR Filter</name> - <blockname>FIR</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">F112</id> - </ids> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - </sink> - <source> - <name>out</name> - <type>sc16</type> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/fosphor.xml b/host/include/uhd/rfnoc/blocks/fosphor.xml deleted file mode 100644 index b1db73192..000000000 --- a/host/include/uhd/rfnoc/blocks/fosphor.xml +++ /dev/null @@ -1,201 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>fosphor</name> - <blockname>fosphor</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">666F</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>ENABLE</name> - <address>160</address> - </setreg> - <setreg> - <name>CLEAR</name> - <address>161</address> - </setreg> - <setreg> - <name>RANDOM</name> - <address>162</address> - </setreg> - <setreg> - <name>DECIM</name> - <address>168</address> - </setreg> - <setreg> - <name>OFFSET</name> - <address>170</address> - </setreg> - <setreg> - <name>SCALE</name> - <address>171</address> - </setreg> - <setreg> - <name>TRISE</name> - <address>172</address> - </setreg> - <setreg> - <name>TDECAY</name> - <address>173</address> - </setreg> - <setreg> - <name>ALPHA</name> - <address>174</address> - </setreg> - <setreg> - <name>EPSILON</name> - <address>175</address> - </setreg> - <setreg> - <name>WF_CTRL</name> - <address>176</address> - </setreg> - <setreg> - <name>WF_DECIM</name> - <address>177</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>1024</value> - </arg> - <arg> - <name>enable</name> - <type>int</type> - <value>3</value> - <check>GE($enable, 0) AND LE($enable, 3)</check> - <check_message>"fosphor enable value must be within [0, 3]"</check_message> - <action>SR_WRITE("ENABLE", $enable)</action> - </arg> - <arg> - <name>clear</name> - <type>int</type> - <action>IF(NOT(EQUAL($clear, 0)), SR_WRITE("CLEAR", $clear))</action> - </arg> - <arg> - <name>random</name> - <type>int</type> - <value>3</value> - <check>GE($random, 0) AND LE($random, 3)</check> - <check_message>"fosphor random mode value must be within [0, 3]"</check_message> - <action>SR_WRITE("RANDOM", $random)</action> - </arg> - <arg> - <name>decim</name> - <type>int</type> - <value>2</value> - <check>GE($decim, 2) AND LE($decim, 1024)</check> - <check_message>fosphor decim constant must be within [2, 1024]</check_message> - <action>SR_WRITE("DECIM", ADD($decim, -2))</action> - </arg> - <arg> - <name>offset</name> - <type>int</type> - <value>0</value> - <check>GE($offset, 0) AND LE($offset, 65536)</check> - <check_message>"fosphor offset value must be within [0, 65535]"</check_message> - <action>SR_WRITE("OFFSET", $offset)</action> - </arg> - <arg> - <name>scale</name> - <type>int</type> - <value>256</value> - <check>GE($scale, 0) AND LE($scale, 65536)</check> - <check_message>"fosphor scale value must be within [0, 65535]"</check_message> - <action>SR_WRITE("SCALE", $scale)</action> - </arg> - <arg> - <name>trise</name> - <type>int</type> - <value>4096</value> - <check>GE($trise, 0) AND LE($trise, 65536)</check> - <check_message>"fosphor trise value must be within [0, 65535]"</check_message> - <action>SR_WRITE("TRISE", $trise)</action> - </arg> - <arg> - <name>tdecay</name> - <type>int</type> - <value>16384</value> - <check>GE($tdecay, 0) AND LE($tdecay, 65536)</check> - <check_message>"fosphor tdecay value must be within [0, 65535]"</check_message> - <action>SR_WRITE("TDECAY", $tdecay)</action> - </arg> - <arg> - <name>alpha</name> - <type>int</type> - <value>65280</value> - <check>GE($alpha, 0) AND LE($alpha, 65536)</check> - <check_message>"fosphor alpha value must be within [0, 65535]"</check_message> - <action>SR_WRITE("ALPHA", $alpha)</action> - </arg> - <arg> - <name>epsilon</name> - <type>int</type> - <value>1</value> - <check>GE($epsilon, 0) AND LE($epsilon, 65536)</check> - <check_message>"fosphor epsilon value must be within [0, 65535]"</check_message> - <action>SR_WRITE("EPSILON", $epsilon)</action> - </arg> - <arg> - <name>wf_ctrl</name> - <type>int</type> - <value>0</value> - <check>GE($wf_ctrl, 0) AND LE($enable, 255)</check> - <check_message>"fosphor wf_ctrl value must be within [0, 255]"</check_message> - <action>SR_WRITE("WF_CTRL", $wf_ctrl)</action> - </arg> - <arg> - <name>wf_decim</name> - <type>int</type> - <value>8</value> - <check>GE($wf_decim, 2) AND LE($wf_decim, 256)</check> - <check_message>fosphor wf_decim constant must be within [2, 256]</check_message> - <action>SR_WRITE("WF_DECIM", ADD($wf_decim, -2))</action> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out_hist</name> - <type>u8</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - <port>0</port> - </source> - <source> - <name>out_wf</name> - <type>u8</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - <port>1</port> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml b/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml deleted file mode 100644 index 5a99685de..000000000 --- a/host/include/uhd/rfnoc/blocks/keep_one_in_n.xml +++ /dev/null @@ -1,55 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Keep One in N</name> - <blockname>KeepOneInN</blockname> - <doc> - Block controller for the Keep One in N RFNoC block. - - For every N packets received, this block will output a single packet. - - One input / output block port - - N up to 65535 - </doc> - <!--There can be several of these:--> - <ids> - <id revision="0">0246</id> - </ids> - <registers> - <setreg> - <name>SR_N</name> - <address>129</address> - </setreg> - </registers> - <args> - <arg> - <name>n</name> - <type>int</type> - <value>256</value> - <action>SR_WRITE("SR_N", $n)</action> - </arg> - </args> - <ports> - <sink> - <name>in</name> - </sink> - <source> - <name>out</name> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/logpwr.xml b/host/include/uhd/rfnoc/blocks/logpwr.xml deleted file mode 100644 index 9307446e3..000000000 --- a/host/include/uhd/rfnoc/blocks/logpwr.xml +++ /dev/null @@ -1,49 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Log Power</name> - <blockname>LogPwr</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">4C50</id> - </ids> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>256</value> - </arg> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/moving_avg.xml b/host/include/uhd/rfnoc/blocks/moving_avg.xml deleted file mode 100644 index 943c83261..000000000 --- a/host/include/uhd/rfnoc/blocks/moving_avg.xml +++ /dev/null @@ -1,50 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Moving Average</name> - <blockname>MovingAverage</blockname> - <ids> - <id revision="0">AAD2</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>SUM_LEN</name> - <address>192</address> - </setreg> - <setreg> - <name>DIVISOR</name> - <address>193</address> - </setreg> - <readback> - <name>RB_SUM_LEN</name> - <address>0</address> - </readback> - <readback> - <name>RB_DIVISOR</name> - <address>1</address> - </readback> - </registers> - <!-- Args --> - <args> - <arg> - <name>length</name> - <type>int</type> - <value>10</value> - <check>GE($length, 1) AND LE($length, 255)</check> - <check_message>Average length must be in [1, 255].</check_message> - <action>SR_WRITE("SUM_LEN", $length) AND SR_WRITE("DIVISOR", $length)</action> - </arg> - </args> - <!-- Ports --> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <port>0</port> - </sink> - <source> - <name>avg</name> - <type>sc16</type> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/erfnoc/blocks/null_src_sink.yml b/host/include/uhd/rfnoc/blocks/null_src_sink.yml index 1636ea046..1636ea046 100644 --- a/host/include/uhd/erfnoc/blocks/null_src_sink.yml +++ b/host/include/uhd/rfnoc/blocks/null_src_sink.yml diff --git a/host/include/uhd/rfnoc/blocks/nullblock.xml b/host/include/uhd/rfnoc/blocks/nullblock.xml deleted file mode 100644 index f1ed3bbd2..000000000 --- a/host/include/uhd/rfnoc/blocks/nullblock.xml +++ /dev/null @@ -1,30 +0,0 @@ -<nocblock> - <name>Null Source/Sink</name> - <blockname>NullSrcSink</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">0000000000000000</id> - </ids> - <!-- Args --> - <args> - <arg> - <name>line_rate</name> - <type>int</type> - <value>65535</value> - </arg> - <arg> - <name>bpp</name> - <type>int</type> - <value>256</value> - </arg> - </args> - <!-- Ports --> - <ports> - <sink> - <name>dump</name> - </sink> - <source> - <name>src</name> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/ofdmeq.xml b/host/include/uhd/rfnoc/blocks/ofdmeq.xml deleted file mode 100644 index 50218e976..000000000 --- a/host/include/uhd/rfnoc/blocks/ofdmeq.xml +++ /dev/null @@ -1,31 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>OFDM Equalizer</name> - <blockname>OFDMEq</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">FF42</id> - </ids> - <!-- Args --> - <args> - <arg> - <name>fftsize</name> - <type>int</type> - <value>64</value> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$fftsize</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out</name> - <type>sc16</type> - <vlen>$fftsize</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/packetresizer.xml b/host/include/uhd/rfnoc/blocks/packetresizer.xml deleted file mode 100644 index 306218318..000000000 --- a/host/include/uhd/rfnoc/blocks/packetresizer.xml +++ /dev/null @@ -1,55 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Packet Resizer</name> - <blockname>PacketResizer</blockname> - <doc> - Block controller for the Packet Resizer RFNoC block. - - The Packet Resizer RFNoC block changes the packet length of a stream. It can break large - packets into smaller packets or combine small packets into a single larger packet. - </doc> - <ids> - <id revision="0">12E5</id> - </ids> - <registers> - <setreg> - <name>SR_PKT_SIZE</name> - <address>129</address> - </setreg> - </registers> - <args> - <arg> - <name>pkt_size</name> - <type>int</type> - <value>32</value> - <check>GT($pkt_size, 0)</check> - <check_message>Packet size must be positive, non-zero.</check_message> - <action>SR_WRITE("SR_PKT_SIZE", $pkt_size)</action> - </arg> - </args> - <ports> - <sink> - <name>in</name> - </sink> - <source> - <name>out</name> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/erfnoc/blocks/radio_1x64.yml b/host/include/uhd/rfnoc/blocks/radio_1x64.yml index 7fc9b7890..7fc9b7890 100644 --- a/host/include/uhd/erfnoc/blocks/radio_1x64.yml +++ b/host/include/uhd/rfnoc/blocks/radio_1x64.yml diff --git a/host/include/uhd/erfnoc/blocks/radio_2x64.yml b/host/include/uhd/rfnoc/blocks/radio_2x64.yml index 4e7838392..4e7838392 100644 --- a/host/include/uhd/erfnoc/blocks/radio_2x64.yml +++ b/host/include/uhd/rfnoc/blocks/radio_2x64.yml diff --git a/host/include/uhd/rfnoc/blocks/radio_e31x.xml b/host/include/uhd/rfnoc/blocks/radio_e31x.xml deleted file mode 100644 index 0635e397c..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_e31x.xml +++ /dev/null @@ -1,59 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Radio (E31X)</name> - <blockname>Radio</blockname> - <key>E31XRadio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">12AD100000003310</id> - </ids> - <!-- Registers --> - <registers> - <!--<setreg>--> - <!--<name>FFT_RESET</name>--> - <!--<address>131</address>--> - <!--</setreg>--> - <!--<readback>--> - <!--<name>RB_MAGNITUDE_OUT</name>--> - <!--<address>1</address>--> - <!--</readback>--> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>508</value> - <!--<value>256</value>--> - <!--<check>GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)</check>--> - <!--<check_message>FFT size must be in [16, 4096] and a power of two.</check_message>--> - <!--<action>SR_WRITE("FFT_SIZE_LOG2", LOG2($spp)) AND SR_WRITE("AXIS_CONFIG_BUS", ADD(873472, LOG2($spp)))</action>--> - </arg> - </args> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </sink> - <sink> - <name>in1</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </source> - <source> - <name>out1</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/radio_e320.xml b/host/include/uhd/rfnoc/blocks/radio_e320.xml deleted file mode 100644 index 01f286324..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_e320.xml +++ /dev/null @@ -1,53 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Radio (Neon)</name> - <blockname>Radio</blockname> - <key>NeonRadio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">12AD100000003320</id> - </ids> - <!-- Registers --> - <registers> - <!--<setreg>--> - <!--<name>FFT_RESET</name>--> - <!--<address>131</address>--> - <!--</setreg>--> - <!--<readback>--> - <!--<name>RB_MAGNITUDE_OUT</name>--> - <!--<address>1</address>--> - <!--</readback>--> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>364</value> - </arg> - <arg> - <name>gain_mode</name> - <type>string</type> - <value>auto</value> - </arg> - </args> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <source> - <name>out1</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/radio_eiscat.xml b/host/include/uhd/rfnoc/blocks/radio_eiscat.xml deleted file mode 100644 index cc6fb7f3b..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_eiscat.xml +++ /dev/null @@ -1,267 +0,0 @@ -<nocblock> - <name>Radio (EISCAT)</name> - <blockname>Radio</blockname> - <key>EISCATRadio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">E15CA70000000000</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <!--1-Bit register. Enable Beam Stream Channels. There are 10, so this is a 10 bit value. --> - <name>SR_RX_STREAM_ENABLE</name> - <address>159</address> - </setreg> - <setreg> - <!--4-Bit register. - [0] Are we sending the upper or lower 5 beam contirbutions? - [1] = 1, beams_to_here goes directly to output (bypass neighbour contributions, single USRP) - [2] = 1, input to rx_receive direct from jesd_core (bypassing beamforming) - [3] = 1, if bypassing beamforming, instead output counter 00-FF - to output counter [3:0] = 0d10. - to output jesd streams directly [3:0] = 6 --> - <name>SR_BEAMS_TO_NEIGHBOR</name> - <address>202</address> - <value>14</value> - </setreg> - <setreg> - <!--1-Bit register. Are we expecting previous contributions? 1==yes we are --> - <name>SR_PREV_OR_NULL</name> - <address>203</address> - </setreg> - <setreg> - <name>SR_FIR_COMMANDS_RELOAD</name> - <address>198</address> - </setreg> - <setreg> - <name>SR_FIR_COMMANDS_CTRL_TIME_HI</name> - <address>199</address> - </setreg> - <setreg> - <name>SR_FIR_COMMANDS_CTRL_TIME_LO</name> - <address>200</address> - </setreg> - <setreg> - <!-- Use this to actually update taps in RAM --> - <name>SR_FIR_BRAM_WRITE_TAPS</name> - <address>201</address> - </setreg> - <setreg> - <name>SR_SYSREF</name> - <address>221</address> - </setreg> - <setreg> - <name>SR_CHANNEL_GAIN_0</name> - <address>204</address> - </setreg> - <readback> - <name>RB_NUM_TAPS</name> - <address>6</address> - </readback> - <readback> - <name>RB_NUM_CHANNELS</name> - <address>7</address> - </readback> - <readback> - <name>RB_NUM_BEAMS</name> - <address>8</address> - </readback> - <readback> - <name>RB_NUM_FILTERS</name> - <address>9</address> - </readback> - <readback> - <name>RB_STREAM_ENABLED</name> - <address>10</address> - </readback> - </registers> - <!-- Args --> - <args> - <!--Gets applied to all channels--> - <arg> - <name>spp</name> - <type>int</type> - <value>3968</value> - </arg> - <arg> - <name>taps</name> - <type>int</type> - </arg> - <arg> - <name>use_prev</name> - <type>int</type> - <value>0</value> - <check>EQUAL($use_prev, 0) OR EQUAL($use_prev, 1)</check> - <check_message>use_prev must be 0 or 1.</check_message> - <action>SR_WRITE("SR_PREV_OR_NULL", $use_prev)</action> - </arg> - <!--Direct access to the beams register--> - <arg> - <name>configure_beams</name> - <type>int</type> - </arg> - <!--Bit 0: 0: Upper 1: Lower Bit 1: 0: Use neighbours 1: no neighbours--> - <arg> - <name>choose_beams</name> - <type>int</type> - <value>2</value> - </arg> - <arg> - <name>enable_firs</name> - <type>int</type> - <value>1</value> - </arg> - <arg> - <name>enable_counter</name> - <type>int</type> - <value>0</value> - </arg> - <arg> - <name>channel_enable</name> - <type>int</type> - <value>1</value> - <action>SR_WRITE("SR_RX_STREAM_ENABLE", $channel_enable)</action> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <action>SR_WRITE("SR_CHANNEL_GAIN_0", 131071)</action> - <port>0</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>1</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>2</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>3</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>4</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>5</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>6</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>7</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>8</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>9</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>10</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>11</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>12</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>13</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>14</port> - </arg> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <port>15</port> - </arg> - </args> - <ports> - <source> - <name>out0</name> - <type>s16</type> - </source> - <source> - <name>out1</name> - <type>s16</type> - </source> - <source> - <name>out2</name> - <type>s16</type> - </source> - <source> - <name>out3</name> - <type>s16</type> - </source> - <source> - <name>out4</name> - <type>s16</type> - </source> - <sink> - <name>in0</name> - <type>s16</type> - </sink> - <sink> - <name>in1</name> - <type>s16</type> - </sink> - <sink> - <name>in2</name> - <type>s16</type> - </sink> - <sink> - <name>in3</name> - <type>s16</type> - </sink> - <sink> - <name>in4</name> - <type>s16</type> - </sink> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/radio_magnesium.xml b/host/include/uhd/rfnoc/blocks/radio_magnesium.xml deleted file mode 100644 index b9b32f369..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_magnesium.xml +++ /dev/null @@ -1,53 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Radio (Magnesium)</name> - <blockname>Radio</blockname> - <key>MagnesiumRadio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">12AD100000011312</id> - </ids> - <!-- Registers --> - <registers> - <!--<setreg>--> - <!--<name>FFT_RESET</name>--> - <!--<address>131</address>--> - <!--</setreg>--> - <!--<readback>--> - <!--<name>RB_MAGNITUDE_OUT</name>--> - <!--<address>1</address>--> - <!--</readback>--> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>364</value> - </arg> - <arg> - <name>gain_mode</name> - <type>string</type> - <value>auto</value> - </arg> - </args> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <source> - <name>out1</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/radio_rhodium.xml b/host/include/uhd/rfnoc/blocks/radio_rhodium.xml deleted file mode 100644 index 7bbe3c904..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_rhodium.xml +++ /dev/null @@ -1,47 +0,0 @@ -<!--This defines the Radio (Rhodium) NoC-Block.--> -<nocblock> - <name>Radio (Rhodium)</name> - <blockname>Radio</blockname> - <key>RhodiumRadio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">12AD100000000320</id> - </ids> - <!-- Registers --> - <registers> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>364</value> - </arg> - <arg> - <name>spur_dodging</name> - <type>string</type> - <value>disabled</value> - </arg> - <arg> - <name>spur_dodging_threshold</name> - <type>double</type> - <value>2e6</value> - </arg> - <arg> - <name>highband_spur_reduction</name> - <type>string</type> - <value>disabled</value> - </arg> - </args> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/radio_x300.xml b/host/include/uhd/rfnoc/blocks/radio_x300.xml deleted file mode 100644 index 8621ac40f..000000000 --- a/host/include/uhd/rfnoc/blocks/radio_x300.xml +++ /dev/null @@ -1,55 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Radio (X300)</name> - <blockname>Radio</blockname> - <key>X300Radio</key> - <!--There can be several of these:--> - <ids> - <id revision="0">12AD100000000001</id> - </ids> - <!-- Registers --> - <registers> - <!--<setreg>--> - <!--<name>FFT_RESET</name>--> - <!--<address>131</address>--> - <!--</setreg>--> - <!--<readback>--> - <!--<name>RB_MAGNITUDE_OUT</name>--> - <!--<address>1</address>--> - <!--</readback>--> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>364</value> - <!--<value>256</value>--> - <!--<check>GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)</check>--> - <!--<check_message>FFT size must be in [16, 4096] and a power of two.</check_message>--> - <!--<action>SR_WRITE("FFT_SIZE_LOG2", LOG2($spp)) AND SR_WRITE("AXIS_CONFIG_BUS", ADD(873472, LOG2($spp)))</action>--> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </sink> - - <source> - <name>out0</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </source> - <source> - <name>out1</name> - <type>sc16</type> - <!--<vlen>$spp</vlen>--> - <!--<pkt_size>%vlen</pkt_size>--> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/replay.xml b/host/include/uhd/rfnoc/blocks/replay.xml deleted file mode 100644 index 3ffc5c01a..000000000 --- a/host/include/uhd/rfnoc/blocks/replay.xml +++ /dev/null @@ -1,64 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Replay</name> - <blockname>Replay</blockname> - <key>Replay</key> - <!--There can be several of these:--> - <ids> - <id revision="0">4E91A00000000000</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>REC_BASE_ADDR</name> - <address>128</address> - </setreg> - <setreg> - <name>REC_BUFFER_SIZE</name> - <address>129</address> - </setreg> - <setreg> - <name>REC_RESTART</name> - <address>130</address> - </setreg> - <readback> - <name>REC_FULLNESS</name> - <address>131</address> - </readback> - <setreg> - <name>PLAY_BASE_ADDR</name> - <address>132</address> - </setreg> - <setreg> - <name>PLAY_BUFFER_SIZE</name> - <address>133</address> - </setreg> - <setreg> - <name>RX_CTRL_COMMAND</name> - <address>152</address> - </setreg> - <setreg> - <name>RX_CTRL_HALT</name> - <address>155</address> - </setreg> - <setreg> - <name>RX_CTRL_MAXLEN</name> - <address>156</address> - </setreg> - </registers> - <!-- Args --> - <args> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/replay_x2.xml b/host/include/uhd/rfnoc/blocks/replay_x2.xml deleted file mode 100644 index a267a85de..000000000 --- a/host/include/uhd/rfnoc/blocks/replay_x2.xml +++ /dev/null @@ -1,72 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Replay</name> - <blockname>Replay</blockname> - <key>Replay</key> - <!--There can be several of these:--> - <ids> - <id revision="0">4E91A00000000002</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>REC_BASE_ADDR</name> - <address>128</address> - </setreg> - <setreg> - <name>REC_BUFFER_SIZE</name> - <address>129</address> - </setreg> - <setreg> - <name>REC_RESTART</name> - <address>130</address> - </setreg> - <readback> - <name>REC_FULLNESS</name> - <address>131</address> - </readback> - <setreg> - <name>PLAY_BASE_ADDR</name> - <address>132</address> - </setreg> - <setreg> - <name>PLAY_BUFFER_SIZE</name> - <address>133</address> - </setreg> - <setreg> - <name>RX_CTRL_COMMAND</name> - <address>152</address> - </setreg> - <setreg> - <name>RX_CTRL_HALT</name> - <address>155</address> - </setreg> - <setreg> - <name>RX_CTRL_MAXLEN</name> - <address>156</address> - </setreg> - </registers> - <!-- Args --> - <args> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <source> - <name>out1</name> - <type>sc16</type> - </source> - </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/replay_x4.xml b/host/include/uhd/rfnoc/blocks/replay_x4.xml deleted file mode 100644 index e12b5f0df..000000000 --- a/host/include/uhd/rfnoc/blocks/replay_x4.xml +++ /dev/null @@ -1,87 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Replay</name> - <blockname>Replay</blockname> - <key>Replay</key> - <!--There can be several of these:--> - <ids> - <id revision="0">4E91A00000000004</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>REC_BASE_ADDR</name> - <address>128</address> - </setreg> - <setreg> - <name>REC_BUFFER_SIZE</name> - <address>129</address> - </setreg> - <setreg> - <name>REC_RESTART</name> - <address>130</address> - </setreg> - <readback> - <name>REC_FULLNESS</name> - <address>131</address> - </readback> - <setreg> - <name>PLAY_BASE_ADDR</name> - <address>132</address> - </setreg> - <setreg> - <name>PLAY_BUFFER_SIZE</name> - <address>133</address> - </setreg> - <setreg> - <name>RX_CTRL_COMMAND</name> - <address>152</address> - </setreg> - <setreg> - <name>RX_CTRL_HALT</name> - <address>155</address> - </setreg> - <setreg> - <name>RX_CTRL_MAXLEN</name> - <address>156</address> - </setreg> - </registers> - <!-- Args --> - <args> - </args> - <!--All the connections to the outside world are listed in 'ports':--> - <ports> - <sink> - <name>in0</name> - <type>sc16</type> - </sink> - <sink> - <name>in1</name> - <type>sc16</type> - </sink> - <sink> - <name>in2</name> - <type>sc16</type> - </sink> - <sink> - <name>in3</name> - <type>sc16</type> - </sink> - <source> - <name>out0</name> - <type>sc16</type> - </source> - <source> - <name>out1</name> - <type>sc16</type> - </source> - <source> - <name>out2</name> - <type>sc16</type> - </source> - <source> - <name>out3</name> - <type>sc16</type> - </source> </ports> -</nocblock> - diff --git a/host/include/uhd/rfnoc/blocks/schmidlcox.xml b/host/include/uhd/rfnoc/blocks/schmidlcox.xml deleted file mode 100644 index 917b54ba3..000000000 --- a/host/include/uhd/rfnoc/blocks/schmidlcox.xml +++ /dev/null @@ -1,101 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Schmidl & Cox</name> - <blockname>SchmidlCox</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">5CC0</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>FRAME_LENGTH</name> - <address>129</address> - </setreg> - <setreg> - <name>CP_LENGTH</name> - <address>130</address> - </setreg> - <setreg> - <name>DELAY</name> - <address>131</address> - </setreg> - <setreg> - <name>NUM_SYMBOLS_MAX</name> - <address>132</address> - </setreg> - <setreg> - <name>THRESHOLD</name> - <address>134</address> - </setreg> - <setreg> - <name>AGC_REF_LEVEL</name> - <address>135</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>fftsize</name> - <type>int</type> - <value>64</value> - <!--TODO: Make publisher, when setting this value, check if equal to GET()--> - </arg> - <arg> - <name>frame_len</name> - <type>int</type> - <value>64</value> - <action>SR_WRITE("FRAME_LENGTH", $frame_len)</action> - </arg> - <arg> - <name>cp_len</name> - <type>int</type> - <value>16</value> - <action>SR_WRITE("CP_LENGTH", $cp_len)</action> - </arg> - <arg> - <name>threshold</name> - <type>double</type> - <value>0.8</value> - <check>GE($threshold, 0.0) AND LE($threshold, 1.0)</check> - <check_message>Detection threshold must be in [0, 1].</check_message> - <action>SR_WRITE("THRESHOLD", IROUND(MULT(16384.0, $threshold)))</action> - </arg> - <arg> - <name>delay</name> - <type>int</type> - <value>146</value> - <check>GE($delay, 0) AND LE($delay, 32767)</check> - <check_message>Invalid delay.</check_message> - <action>SR_WRITE("DELAY", $delay)</action> - </arg> - <arg> - <name>max_num_symbols</name> - <type>int</type> - <value>12</value> - <check>GE($max_num_symbols, 0) AND LE($max_num_symbols, 1000)</check> - <check_message>Invalid number of max symbols.</check_message> - <action>SR_WRITE("NUM_SYMBOLS_MAX", $max_num_symbols)</action> - </arg> - <arg> - <name>agc_ref_level</name> - <type>double</type> - <value>0.125</value> - <check>GE($agc_ref_level, 0.0) AND LE($agc_ref_level, 1.0)</check> - <check_message>AGC reference level must be in [0, 1].</check_message> - <action>SR_WRITE("AGC_REF_LEVEL", IROUND(MULT(32768.0, $agc_ref_level)))</action> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - </sink> - <source> - <name>out</name> - <type>sc16</type> - <vlen>$fftsize</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/serialdemod.xml b/host/include/uhd/rfnoc/blocks/serialdemod.xml deleted file mode 100644 index 37f3357c1..000000000 --- a/host/include/uhd/rfnoc/blocks/serialdemod.xml +++ /dev/null @@ -1,109 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>OFDM Constellation Demod</name> - <blockname>OFDMDemap</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">0FCD</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>MOD_ORDER</name> - <address>129</address> - </setreg> - <setreg> - <name>SCALING</name> - <address>130</address> - </setreg> - <setreg> - <name>OUTPUT_SYMBOLS</name> - <address>131</address> - </setreg> - <setreg> - <name>PKT_LEN</name> - <address>132</address> - </setreg> - <setreg> - <name>SET_EOB</name> - <address>133</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>fftsize</name> - <type>int</type> - <value>64</value> - </arg> - <arg> - <name>mod_order</name> - <type>int</type> - <value>4</value> - <check>GE($mod_order, 2) AND LE($mod_order, 64) AND IS_PWR_OF_2($mod_order)</check> - <check_message>Modulation order must be in (2, 4, 16, 64).</check_message> - <action>SR_WRITE("MOD_ORDER", LOG2($mod_order))</action> - </arg> - <arg> - <name>scaling</name> - <type>double</type> - <value>1.4142135623730951</value> - <check>GE($scaling, 0.1) AND LT($scaling, 4.0)</check> - <check_message>Invalid scaling.</check_message> - <action>SR_WRITE("SCALING", IROUND(MULT(16384.0, $scaling)))</action> - </arg> - <arg> - <name>output_symbols</name> - <type>int</type> - <value>1</value> - <check>EQUAL($output_symbols, 0) OR EQUAL($output_symbols, 1)</check> - <check_message>Output symbols can only be true (1) or false (0)</check_message> - <action>SR_WRITE("OUTPUT_SYMBOLS", $output_symbols)</action> - </arg> - <!-- Packet length in bytes --> - <arg> - <name>pkt_len</name> - <type>int</type> - <value>64</value> - <check>GE($pkt_len, 4) AND LE($pkt_len, 4096)</check> - <check_message>Packet length must be greater than or equal to 4 and less than or equal to 4096 bytes</check_message> - <action>SR_WRITE("PKT_LEN", $pkt_len)</action> - </arg> - <arg> - <name>set_eob</name> - <type>int</type> - <value>1</value> - <check>EQUAL($set_eob, 0) OR EQUAL($set_eob, 1)</check> - <check_message>Set end of burst can only be true (1) or false (0)</check_message> - <action>SR_WRITE("SET_EOB", $set_eob)</action> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$fftsize</vlen> - </sink> - <source> - <name>out</name> - <type>u8</type> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/siggen.xml b/host/include/uhd/rfnoc/blocks/siggen.xml deleted file mode 100644 index 2850e6804..000000000 --- a/host/include/uhd/rfnoc/blocks/siggen.xml +++ /dev/null @@ -1,116 +0,0 @@ -<nocblock> - <name>Signal Generator</name> - <blockname>SigGen</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">5166311000000000</id> - </ids> - <!-- Registers --> - <registers> - <!-- Reg 128 used for FREQ --> - <setreg> - <name>FREQ</name> - <address>129</address> - </setreg> - <setreg> - <name>CARTESIAN</name> - <address>130</address> - </setreg> - <setreg> - <name>ENABLE</name> - <address>132</address> - </setreg> - <setreg> - <name>CONSTANT</name> - <address>138</address> - </setreg> - <setreg> - <name>GAIN</name> - <address>139</address> - </setreg> - <setreg> - <name>PKT_SIZE</name> - <address>140</address> - </setreg> - <setreg> - <name>WAVEFORM</name> - <address>142</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>enable</name> - <type>int</type> - <value>0</value> - <check>EQUAL($enable, 0) OR EQUAL($enable, 1)</check> - <check_message>Enable is either 0 or 1.</check_message> - <action>SR_WRITE("ENABLE", $enable)</action> - </arg> - <arg> - <name>spp</name> - <type>int</type> - <value>256</value> - <action>SR_WRITE("PKT_SIZE", $spp)</action> - </arg> - <!-- Overall Gain --> - <arg> - <name>gain</name> - <type>double</type> - <value>1.0</value> - <check>GE($gain, 0.0) AND LE($gain, 1.0)</check> - <check_message>Invalid gain.</check_message> - <action> - SR_WRITE("GAIN", IROUND(MULT(32767.0,$gain))) - </action> - </arg> - <!-- Sine Wave, Constant I / Q --> - <arg> - <name>amplitude_i</name> - <type>double</type> - <value>1.0</value> - <check>GE($amplitude_i, -1.0) AND LE($amplitude_i, 1.0)</check> - <check_message>Invalid amplitude.</check_message> - </arg> - <arg> - <name>amplitude_q</name> - <type>double</type> - <value>1.0</value> - <check>GE($amplitude_q, -1.0) AND LE($amplitude_q, 1.0)</check> - <check_message>Invalid amplitude.</check_message> - <action> - SR_WRITE("CONSTANT", ADD(MULT(65536,IROUND(MULT(32767.0, $amplitude_i))),IROUND(MULT(32767.0, $amplitude_q)))) - </action> - </arg> - <arg> - <name>frequency</name> - <type>double</type> - <value>0.1</value> - <check>GE($frequency, -1.0) AND LE($frequency, 1.0)</check> - <check_message>Invalid frequency.</check_message> - <action>SR_WRITE("FREQ", IROUND(MULT(-8192.0, $frequency)))</action> - </arg> - <arg> - <name>waveform</name> - <type>string</type> - <value>CONSTANT</value> - <check>EQUAL($waveform, "CONSTANT") OR EQUAL($waveform, "SINE_WAVE") OR EQUAL($waveform, "NOISE")</check> - <check_message>Waveform type should be one of: CONSTANT, SINE WAVE, NOISE.</check_message> - <action> - IF(EQUAL($waveform, "CONSTANT"), SR_WRITE("WAVEFORM", 0) AND SR_WRITE("CONSTANT", ADD(MULT(65536,IROUND(MULT(32767.0, $amplitude_i))),IROUND(MULT(32767.0, $amplitude_q))))) OR - IF(EQUAL($waveform, "SINE_WAVE"), SR_WRITE("WAVEFORM", 1) AND SR_WRITE("CARTESIAN", MULT(65536,28000))) OR - IF(EQUAL($waveform, "NOISE"), SR_WRITE("WAVEFORM", 2)) - </action> - </arg> - </args> - <!-- Ports --> - <ports> - <sink> - <name>dump</name> - </sink> - <source> - <name>src</name> - <type>sc16</type> - </source> - </ports> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/splitstream.xml b/host/include/uhd/rfnoc/blocks/splitstream.xml deleted file mode 100644 index 08cbd0457..000000000 --- a/host/include/uhd/rfnoc/blocks/splitstream.xml +++ /dev/null @@ -1,38 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Split Stream</name> - <blockname>SplitStream</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">5757</id> - </ids> - <!-- This block takes any type, hence we skip the <type> tag: --> - <ports> - <sink> - <name>in</name> - </sink> - <source> - <name>out0</name> - </source> - <source> - <name>out1</name> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/vector_iir.xml b/host/include/uhd/rfnoc/blocks/vector_iir.xml deleted file mode 100644 index 98b46e757..000000000 --- a/host/include/uhd/rfnoc/blocks/vector_iir.xml +++ /dev/null @@ -1,84 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Vector IIR</name> - <blockname>VectorIIR</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">1112</id> - </ids> - <!-- Registers --> - <registers> - <setreg> - <name>VECTOR_LEN</name> - <address>129</address> - </setreg> - <setreg> - <name>ALPHA</name> - <address>130</address> - </setreg> - <setreg> - <name>BETA</name> - <address>131</address> - </setreg> - </registers> - <!-- Args --> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>256</value> - <check>GE($spp, 1) AND LE($spp, 4096)</check> - <check_message>Vector length must be in [1, 4096].</check_message> - <action>SR_WRITE("VECTOR_LEN", $spp)</action> - </arg> - <arg> - <name>alpha</name> - <type>double</type> - <value>0.9</value> - <check>GT($alpha, 0.0) AND LT($alpha, 1.0)</check> - <check_message>Alpha must be in (0.0, 1.0).</check_message> - <!--We set the register value to alpha * 2^31 (Q1.31 format)--> - <action>SR_WRITE("ALPHA", IROUND(MULT($alpha, 2147483648.0)))</action> - </arg> - <arg> - <name>beta</name> - <type>double</type> - <value>0.1</value> - <check>GT($beta, 0.0) AND LT($beta, 1.0)</check> - <check_message>Beta must be in (0.0, 1.0).</check_message> - <!--We set the register value to alpha * 2^31 (Q1.31 format)--> - <action>SR_WRITE("BETA", IROUND(MULT($beta, 2147483648.0)))</action> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/blocks/window.xml b/host/include/uhd/rfnoc/blocks/window.xml deleted file mode 100644 index df36f4b4f..000000000 --- a/host/include/uhd/rfnoc/blocks/window.xml +++ /dev/null @@ -1,47 +0,0 @@ -<!--This defines one NoC-Block.--> -<nocblock> - <name>Window</name> - <blockname>Window</blockname> - <!--There can be several of these:--> - <ids> - <id revision="0">D053</id> - </ids> - <args> - <arg> - <name>spp</name> - <type>int</type> - <value>256</value> - </arg> - </args> - <ports> - <sink> - <name>in</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </sink> - <source> - <name>out</name> - <type>sc16</type> - <vlen>$spp</vlen> - <pkt_size>%vlen</pkt_size> - </source> - </ports> - <!--<components>--> - <!--<component>--> - <!--<key revision="1">nocshell</key>--> - <!--</component>--> - <!--<component srbase="0">--> - <!--[>Will look for a component with this key:<]--> - <!--<key revision="1">componentname</key>--> - <!--</component>--> - <!--</components>--> - <!--<connection>--> - <!--<source port="0">nocshell</source>--> - <!--<sink port="0">componentname</sink>--> - <!--</connection>--> - <!--<connection>--> - <!--<source port="0">componentname</source>--> - <!--<sink port="0">nocshell</sink>--> - <!--</connection>--> -</nocblock> diff --git a/host/include/uhd/rfnoc/constants.hpp b/host/include/uhd/rfnoc/constants.hpp index 1a992378c..6aeef1522 100644 --- a/host/include/uhd/rfnoc/constants.hpp +++ b/host/include/uhd/rfnoc/constants.hpp @@ -16,13 +16,6 @@ namespace uhd { namespace rfnoc { -// All these configure the XML reader -//! Where the RFNoC block/component definition files lie, relative to UHD_PKG_DIR -static const std::string XML_DEFAULT_PATH = "share/uhd/rfnoc"; -//! The name of the environment variable storing the bath to the block definition files -static const std::string XML_PATH_ENV = "UHD_RFNOC_DIR"; - -static const uint64_t DEFAULT_NOC_ID_64 = 0xFFFFFFFFFFFFFFFF; static const size_t NOC_SHELL_COMPAT_MAJOR = 5; static const size_t NOC_SHELL_COMPAT_MINOR = 1; diff --git a/host/include/uhd/erfnoc/blocks/CMakeLists.txt b/host/include/uhd/rfnoc/core/CMakeLists.txt index c4b8e678d..2027c208b 100644 --- a/host/include/uhd/erfnoc/blocks/CMakeLists.txt +++ b/host/include/uhd/rfnoc/core/CMakeLists.txt @@ -1,14 +1,15 @@ # -# Copyright 2019 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # file(GLOB yml_files "*.yml") +file(GLOB json_files "*.json") # We always need this, even when RFNoC is 'disabled' UHD_INSTALL( - FILES ${yml_files} - DESTINATION ${PKG_DATA_DIR}/erfnoc/blocks + FILES ${yml_files} ${json_files} + DESTINATION ${PKG_DATA_DIR}/rfnoc/core COMPONENT headers # TODO: Different component -)
\ No newline at end of file +) diff --git a/host/include/uhd/erfnoc/blocks/e310_bsp.yml b/host/include/uhd/rfnoc/core/e310_bsp.yml index 8fabbb55a..8fabbb55a 100644 --- a/host/include/uhd/erfnoc/blocks/e310_bsp.yml +++ b/host/include/uhd/rfnoc/core/e310_bsp.yml diff --git a/host/include/uhd/erfnoc/core/e320_bsp.yml b/host/include/uhd/rfnoc/core/e320_bsp.yml index c8d5b7de0..c8d5b7de0 100644 --- a/host/include/uhd/erfnoc/core/e320_bsp.yml +++ b/host/include/uhd/rfnoc/core/e320_bsp.yml diff --git a/host/include/uhd/erfnoc/core/io_signatures.yml b/host/include/uhd/rfnoc/core/io_signatures.yml index ba7721e3e..ba7721e3e 100644 --- a/host/include/uhd/erfnoc/core/io_signatures.yml +++ b/host/include/uhd/rfnoc/core/io_signatures.yml diff --git a/host/include/uhd/erfnoc/core/n300_bsp.yml b/host/include/uhd/rfnoc/core/n300_bsp.yml index f0c75df4e..f0c75df4e 100644 --- a/host/include/uhd/erfnoc/core/n300_bsp.yml +++ b/host/include/uhd/rfnoc/core/n300_bsp.yml diff --git a/host/include/uhd/erfnoc/core/n310_bsp.yml b/host/include/uhd/rfnoc/core/n310_bsp.yml index 08690ed5a..08690ed5a 100644 --- a/host/include/uhd/erfnoc/core/n310_bsp.yml +++ b/host/include/uhd/rfnoc/core/n310_bsp.yml diff --git a/host/include/uhd/erfnoc/core/n320_bsp.yml b/host/include/uhd/rfnoc/core/n320_bsp.yml index 5d31da947..5d31da947 100644 --- a/host/include/uhd/erfnoc/core/n320_bsp.yml +++ b/host/include/uhd/rfnoc/core/n320_bsp.yml diff --git a/host/include/uhd/erfnoc/core/rfnoc_imagebuilder_args.json b/host/include/uhd/rfnoc/core/rfnoc_imagebuilder_args.json index 65ef2dd76..65ef2dd76 100644 --- a/host/include/uhd/erfnoc/core/rfnoc_imagebuilder_args.json +++ b/host/include/uhd/rfnoc/core/rfnoc_imagebuilder_args.json diff --git a/host/include/uhd/erfnoc/core/x300_bsp.yml b/host/include/uhd/rfnoc/core/x300_bsp.yml index 20a78958f..20a78958f 100644 --- a/host/include/uhd/erfnoc/core/x300_bsp.yml +++ b/host/include/uhd/rfnoc/core/x300_bsp.yml diff --git a/host/include/uhd/erfnoc/core/x310_bsp.yml b/host/include/uhd/rfnoc/core/x310_bsp.yml index 20a78958f..20a78958f 100644 --- a/host/include/uhd/erfnoc/core/x310_bsp.yml +++ b/host/include/uhd/rfnoc/core/x310_bsp.yml diff --git a/host/include/uhd/rfnoc/ddc_block_ctrl.hpp b/host/include/uhd/rfnoc/ddc_block_ctrl.hpp deleted file mode 100644 index 2a261db00..000000000 --- a/host/include/uhd/rfnoc/ddc_block_ctrl.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/scalar_node_ctrl.hpp> -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief DDC block controller - * - * This block provides DSP for Rx operations. - * Its main component is a DDC chain, which can decimate over a wide range - * of decimation rates (using a CIC and halfband filters). - * - * It also includes a CORDIC component to shift signals in frequency. - */ -class UHD_RFNOC_API ddc_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base, - public rate_node_ctrl, - public scalar_node_ctrl -{ -public: - UHD_RFNOC_BLOCK_OBJECT(ddc_block_ctrl) - -}; /* class ddc_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_DDC_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp b/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp deleted file mode 100644 index 093e2ef91..000000000 --- a/host/include/uhd/rfnoc/dma_fifo_block_ctrl.hpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP -#define INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Block controller for a DMA FIFO block. - * - * The DMA FIFO block has the following features: - * - One input- and output-port (type agnostic) - * - Configurable base address and FIFO depth - * - The base storage for the FIFO can be device - * specific. Usually it will be an off-chip SDRAM - * bank. - * - */ -class UHD_RFNOC_API dma_fifo_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - UHD_RFNOC_BLOCK_OBJECT(dma_fifo_block_ctrl) - - //! Configure the base address and depth of the FIFO (in bytes). - virtual void resize( - const uint32_t base_addr, const uint32_t depth, const size_t chan) = 0; - - //! Returns the base address of the FIFO (in bytes). - uint32_t get_base_addr(const size_t chan) const; - - //! Returns the depth of the FIFO (in bytes). - uint32_t get_depth(const size_t chan) const; - -}; /* class dma_fifo_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_DMA_FIFO_BLOCK_HPP */ diff --git a/host/include/uhd/rfnoc/duc_block_ctrl.hpp b/host/include/uhd/rfnoc/duc_block_ctrl.hpp deleted file mode 100644 index b24f7af26..000000000 --- a/host/include/uhd/rfnoc/duc_block_ctrl.hpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/scalar_node_ctrl.hpp> -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief DUC block controller - * - * This block provides DSP for Tx operations. - * Its main component is a DUC chain, which can interpolate over a wide range - * of interpolation rates (using a CIC and halfband filters). - * - * It also includes a CORDIC component to shift signals in frequency. - */ -class UHD_RFNOC_API duc_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base, - public rate_node_ctrl, - public scalar_node_ctrl -{ -public: - UHD_RFNOC_BLOCK_OBJECT(duc_block_ctrl) - -}; /* class duc_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_DUC_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/fir_block_ctrl.hpp b/host/include/uhd/rfnoc/fir_block_ctrl.hpp deleted file mode 100644 index 67a6a958b..000000000 --- a/host/include/uhd/rfnoc/fir_block_ctrl.hpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright 2014-2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_fir_block_ctrl_HPP -#define INCLUDED_LIBUHD_RFNOC_fir_block_ctrl_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Block controller for the standard FIR RFNoC block. - * - * The standard FIR has the following features: - * - One input- and output-port - * - Configurable taps, but fixed number of taps - * - Supports data type sc16 (16-Bit fix-point complex samples) - * - * This block requires packets to be the same size as the FFT length. - * It will perform one FFT operation per incoming packet, treating it - * as a vector of samples. - */ -class UHD_RFNOC_API fir_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - UHD_RFNOC_BLOCK_OBJECT(fir_block_ctrl) - - //! Configure the filter taps. - // - // The length of \p taps must correspond the number of taps - // in this block. If it's shorter, zeros will be padded. - // If it's longer, throws a uhd::value_error. - virtual void set_taps(const std::vector<int>& taps) = 0; - - //! Returns the number of filter taps in this block. - virtual size_t get_n_taps() const = 0; -}; /* class fir_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_fir_block_ctrl_HPP */ diff --git a/host/include/uhd/rfnoc/graph.hpp b/host/include/uhd/rfnoc/graph.hpp deleted file mode 100644 index bdd104620..000000000 --- a/host/include/uhd/rfnoc/graph.hpp +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_GRAPH_HPP -#define INCLUDED_LIBUHD_RFNOC_GRAPH_HPP - -#include <uhd/rfnoc/block_id.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/utils/noncopyable.hpp> - -namespace uhd { namespace rfnoc { - -class graph : uhd::noncopyable -{ -public: - typedef boost::shared_ptr<uhd::rfnoc::graph> sptr; - - /*! Connect a RFNOC block with block ID \p src_block to another with block ID \p - * dst_block. - * - * This will: - * - Check if this connection is valid (IO signatures, see if types match) - * - Configure the flow control for the blocks - * - Configure SID for the upstream block - * - Register the upstream block in the downstream block - */ - virtual void 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 = 0) = 0; - - /*! Shorthand for connect(). - * - * Using default ports for both source and destination. - */ - virtual void connect(const block_id_t& src_block, const block_id_t& dst_block) = 0; - - /*! Anonymous connection. - * - * Danger, danger. You use this, you know what you're doing. - * - * \param src_block Source block ID - * \param src_block_port Source block port - * \param dst_sid SID to route traffic to - * \param buf_size_dst_bytes Destination window buffer in bytes - * \param pkt_size Hint what the packet size over this link will be - */ - virtual void 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) = 0; - - /*! Anonymous connection - * - * Danger, danger. You use this, you know what you're doing. - * - * \param sink_block Sink block ID - * \param dst_block_port Destination (sink) block port - * \param bytes_per_ack Flow control frequency in bytes - */ - virtual void connect_sink(const block_id_t& sink_block, - const size_t dst_block_port, - const size_t bytes_per_ack) = 0; - - virtual std::string get_name() const = 0; -}; - -}}; // namespace uhd::rfnoc - -#endif /* INCLUDED_LIBUHD_RFNOC_GRAPH_HPP */ diff --git a/host/include/uhd/rfnoc/node_ctrl_base.hpp b/host/include/uhd/rfnoc/node_ctrl_base.hpp deleted file mode 100644 index c94507173..000000000 --- a/host/include/uhd/rfnoc/node_ctrl_base.hpp +++ /dev/null @@ -1,309 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/noncopyable.hpp> -#include <stdint.h> -#include <boost/enable_shared_from_this.hpp> -#include <boost/function.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> -#include <map> -#include <set> - -namespace uhd { namespace usrp { -// Forward declaration for friend clause -class device3_impl; -}} // namespace uhd::usrp - -namespace uhd { namespace rfnoc { - -#define UHD_RFNOC_BLOCK_TRACE() UHD_LOGGER_TRACE("RFNOC") - -/*! \brief Abstract base class for streaming nodes. - * - */ -class UHD_RFNOC_API node_ctrl_base; -class node_ctrl_base : uhd::noncopyable, - public boost::enable_shared_from_this<node_ctrl_base> -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<node_ctrl_base> sptr; - typedef boost::weak_ptr<node_ctrl_base> wptr; - typedef std::map<size_t, wptr> node_map_t; - typedef std::pair<size_t, wptr> node_map_pair_t; - typedef boost::function<void(void)> graph_update_cb_t; - - /*********************************************************************** - * Node control - **********************************************************************/ - //! Returns a unique string that identifies this block. - virtual std::string unique_id() const; - - /*********************************************************************** - * Connections - **********************************************************************/ - /*! Clears the list of connected nodes. - */ - virtual void clear(); - - node_map_t list_downstream_nodes() - { - return _downstream_nodes; - }; - node_map_t list_upstream_nodes() - { - return _upstream_nodes; - }; - - /*! Disconnect this node from all neighbouring nodes. - */ - void disconnect(); - - /*! Identify \p output_port as unconnected - */ - void disconnect_output_port(const size_t output_port); - - /*! Identify \p input_port as unconnected - */ - void disconnect_input_port(const size_t input_port); - - // TODO we need a more atomic connect procedure, this is too error-prone. - - /*! For an existing connection, store the remote port number. - * - * \throws uhd::value_error if \p this_port is not connected. - */ - void set_downstream_port(const size_t this_port, const size_t remote_port); - - /*! Return the remote port of a connection on a given port. - * - * \throws uhd::value_error if \p this_port is not connected. - */ - size_t get_downstream_port(const size_t this_port); - - /*! For an existing connection, store the remote port number. - * - * \throws uhd::value_error if \p this_port is not connected. - */ - void set_upstream_port(const size_t this_port, const size_t remote_port); - - /*! Return the remote port of a connection on a given port. - * - * \throws uhd::value_error if \p this_port is not connected. - */ - size_t get_upstream_port(const size_t this_port); - - /*! Find nodes downstream that match a predicate. - * - * Uses a non-recursive breadth-first search algorithm. - * On every branch, the search stops if a block matches. - * See this example: - * <pre> - * A -> B -> C -> C - * </pre> - * Say node A searches for nodes of type C. It will only find the - * first 'C' block, not the second. - * - * Returns blocks that are of type T. - * - * Search only goes downstream. - */ - template <typename T> - UHD_INLINE std::vector<boost::shared_ptr<T> > find_downstream_node( - bool active_only = false) - { - return _find_child_node<T, true>(active_only); - } - - /*! Same as find_downstream_node(), but only search upstream. - */ - template <typename T> - UHD_INLINE std::vector<boost::shared_ptr<T> > find_upstream_node( - bool active_only = false) - { - return _find_child_node<T, false>(active_only); - } - - /*! Checks if downstream nodes share a common, unique property. - * - * This will use find_downstream_node() to find all nodes downstream of - * this that are of type T. Then it will use \p get_property to return a - * property from all of them. If all these properties are identical, it will - * return that property. Otherwise, it will throw a uhd::runtime_error. - * - * \p get_property A functor to return the property from a node - * \p null_value If \p get_property returns this value, that node is skipped. - * \p explored_nodes A list of nodes to exclude from the search. This is typically - * to avoid recursion loops. - */ - template <typename T, typename value_type> - UHD_INLINE value_type find_downstream_unique_property( - boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property, - value_type null_value, - const std::set<boost::shared_ptr<T> >& exclude_nodes = - std::set<boost::shared_ptr<T> >()) - { - return _find_unique_property<T, value_type, true>( - get_property, null_value, exclude_nodes); - } - - /*! Like find_downstream_unique_property(), but searches upstream. - */ - template <typename T, typename value_type> - UHD_INLINE value_type find_upstream_unique_property( - boost::function<value_type(boost::shared_ptr<T> node, size_t port)> get_property, - value_type null_value, - const std::set<boost::shared_ptr<T> >& exclude_nodes = - std::set<boost::shared_ptr<T> >()) - { - return _find_unique_property<T, value_type, false>( - get_property, null_value, exclude_nodes); - } - -protected: - /*********************************************************************** - * Structors - **********************************************************************/ - node_ctrl_base(void) : _num_input_ports(0), _num_output_ports(0) {} - virtual ~node_ctrl_base() - { - disconnect(); - } - - /*********************************************************************** - * Protected members - **********************************************************************/ - - //! Stores default arguments - uhd::device_addr_t _args; - - // TODO make these private - - //! List of upstream nodes - node_map_t _upstream_nodes; - - //! List of downstream nodes - node_map_t _downstream_nodes; - - /*! Number of input ports - */ - size_t _num_input_ports; - - /*! Number of output ports - */ - size_t _num_output_ports; - - /*! For every output port, store rx streamer activity. - * - * If _rx_streamer_active[0] == true, this means that an active rx - * streamer is operating on port 0. If it is false, or if the entry - * does not exist, there is no streamer. - * Values are toggled by set_rx_streamer(). - */ - std::map<size_t, bool> _rx_streamer_active; - - /*! For every input port, store tx streamer activity. - * - * If _tx_streamer_active[0] == true, this means that an active tx - * streamer is operating on port 0. If it is false, or if the entry - * does not exist, there is no streamer. - * Values are toggled by set_tx_streamer(). - */ - std::map<size_t, bool> _tx_streamer_active; - - /*********************************************************************** - * Connections - **********************************************************************/ - /*! Registers another node as downstream of this node, connected to a given port. - * - * This implies that this node is a source node, and the downstream node is - * a sink node. - * See also uhd::rfnoc::source_node_ctrl::_register_downstream_node(). - */ - virtual void _register_downstream_node( - node_ctrl_base::sptr downstream_node, size_t port); - - /*! Registers another node as upstream of this node, connected to a given port. - * - * This implies that this node is a sink node, and the upstream node is - * a source node. - * See also uhd::rfnoc::sink_node_ctrl::_register_upstream_node(). - */ - virtual void _register_upstream_node(node_ctrl_base::sptr upstream_node, size_t port); - - /*! Initiate the update graph callback - * - * Call this from your block when you've changed one of these: - * - sampling rate - * - scaling - * - tick rate - */ - void update_graph() - { - _graph_update_cb(); - } - -private: - friend class uhd::usrp::device3_impl; - - /*! Implements the search algorithm for find_downstream_node() and - * find_upstream_node(). - * - * Depending on \p downstream, "child nodes" are either defined as - * nodes connected downstream or upstream. - * - * \param downstream Set to true if search goes downstream, false for upstream. - */ - template <typename T, bool downstream> - std::vector<boost::shared_ptr<T> > _find_child_node(bool active_only = false); - - /*! Implements the search algorithm for find_downstream_unique_property() and - * find_upstream_unique_property(). - * - * Depending on \p downstream, "child nodes" are either defined as - * nodes connected downstream or upstream. - * - * \param downstream Set to true if search goes downstream, false for upstream. - */ - template <typename T, typename value_type, bool downstream> - value_type _find_unique_property( - boost::function<value_type(boost::shared_ptr<T>, size_t)> get_property, - value_type NULL_VALUE, - const std::set<boost::shared_ptr<T> >& exclude_nodes); - - void set_graph_update_cb(graph_update_cb_t graph_update_cb) - { - _graph_update_cb = graph_update_cb; - } - - /*! Stores the remote port number of a downstream connection. - */ - std::map<size_t, size_t> _upstream_ports; - - /*! Stores the remote port number of a downstream connection. - */ - std::map<size_t, size_t> _downstream_ports; - - graph_update_cb_t _graph_update_cb; - -}; /* class node_ctrl_base */ - -}} /* namespace uhd::rfnoc */ - -#include <uhd/rfnoc/node_ctrl_base.ipp> - -#endif /* INCLUDED_LIBUHD_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/node_ctrl_base.ipp b/host/include/uhd/rfnoc/node_ctrl_base.ipp deleted file mode 100644 index 80dadfcf9..000000000 --- a/host/include/uhd/rfnoc/node_ctrl_base.ipp +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -// Implements templated functions from node_ctrl_base.hpp - -#ifndef INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP -#define INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP - -#include <uhd/exception.hpp> - -#include <boost/shared_ptr.hpp> -#include <vector> - -namespace uhd { - namespace rfnoc { - - template <typename T, bool downstream> - std::vector< boost::shared_ptr<T> > node_ctrl_base::_find_child_node(bool active_only) - { - typedef boost::shared_ptr<T> T_sptr; - static const size_t MAX_ITER = 20; - size_t iters = 0; - // List of return values: - std::set< T_sptr > results_s; - // To avoid cycles: - std::set < sptr > explored; - // Initialize our search queue with ourself: - std::set < node_map_pair_t > search_q; - // FIXME: Port is initialized to ANY_PORT, but it should really be - // passed in by the caller. - search_q.insert(node_map_pair_t(ANY_PORT, shared_from_this())); - std::set < node_map_pair_t > next_q; - - while (iters++ < MAX_ITER) { - next_q.clear(); - BOOST_FOREACH(const node_map_pair_t node_pair, search_q) { - sptr node = node_pair.second.lock(); - if (not node) - { - continue; - } - size_t our_port = node_pair.first; - // Add this node to the list of explored nodes - explored.insert(node); - // Create set of all child nodes of this_node that are not in explored: - std::set< node_map_pair_t > next_nodes; - { - node_map_t all_next_nodes = downstream ? - node->list_downstream_nodes() : - node->list_upstream_nodes(); - for ( - node_map_t::iterator it = all_next_nodes.begin(); - it != all_next_nodes.end(); - ++it - ) { - size_t connected_port = it->first; - // If port is given, limit traversal to only that port. - if (our_port != ANY_PORT and our_port != connected_port) - { - continue; - } - if (active_only - and not (downstream ? - _tx_streamer_active[connected_port] : - _rx_streamer_active[connected_port] )) { - continue; - } - sptr one_next_node = it->second.lock(); - if (not one_next_node or explored.count(one_next_node)) { - continue; - } - T_sptr next_node_sptr = boost::dynamic_pointer_cast<T>(one_next_node); - if (next_node_sptr) { - results_s.insert(next_node_sptr); - } else { - size_t next_port = ANY_PORT; - // FIXME: Need proper mapping from input port - // to output port. - // The code below assumes that blocks with the same - // number of connected upstream and downstream nodes - // map each input port directly to the same output - // port. This limits the graph traversal to prevent - // finding nodes that are not part of this chain. - if (one_next_node->_num_input_ports - and (one_next_node->_num_input_ports == - one_next_node->_num_output_ports)) - { - next_port = (downstream ? - node->get_downstream_port(connected_port) : - node->get_upstream_port(connected_port)); - } - next_nodes.insert(node_map_pair_t(next_port, it->second)); - } - } - } - // Add all of these nodes to the next search queue - next_q.insert(next_nodes.begin(), next_nodes.end()); - } - // If next_q is empty, we've exhausted our graph - if (next_q.empty()) { - break; - } - // Re-init the search queue - search_q = next_q; - } - - std::vector< T_sptr > results(results_s.begin(), results_s.end()); - return results; - } - - template <typename T, typename value_type, bool downstream> - value_type node_ctrl_base::_find_unique_property( - boost::function<value_type(boost::shared_ptr<T>, size_t)> get_property, - value_type NULL_VALUE, - const std::set< boost::shared_ptr<T> > &exclude_nodes - ) { - std::vector< boost::shared_ptr<T> > descendant_rate_nodes = _find_child_node<T, downstream>(); - value_type ret_val = NULL_VALUE; - std::string first_node_id; - BOOST_FOREACH(const boost::shared_ptr<T> &node, descendant_rate_nodes) { - if (exclude_nodes.count(node)) { - continue; - } - // FIXME we need to know the port!!! - size_t port = ANY_PORT; // NOOO! this is wrong!!!! FIXME - value_type this_property = get_property(node, port); - if (this_property == NULL_VALUE) { - continue; - } - // We use the first property we find as reference - if (ret_val == NULL_VALUE) { - ret_val = this_property; - first_node_id = node->unique_id(); - continue; - } - // In all subsequent finds, we make sure the property is equal to the reference - if (this_property != ret_val) { - throw uhd::runtime_error( - str( - boost::format("Node %1% specifies %2%, node %3% specifies %4%") - % first_node_id % ret_val % node->unique_id() % this_property - ) - ); - } - } - return ret_val; - } - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_NODE_CTRL_BASE_IPP */ -// vim: sw=4 et: diff --git a/host/include/uhd/rfnoc/null_block_ctrl.hpp b/host/include/uhd/rfnoc/null_block_ctrl.hpp deleted file mode 100644 index 1406fd219..000000000 --- a/host/include/uhd/rfnoc/null_block_ctrl.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2014-2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_NULL_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_NULL_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Provide access to a 'null block'. - * - * A 'null block' is a specific block, which comes with a couple - * of features useful for testing: - * - It can produce data at a given line rate, with a configurable - * packet size. - * - It can be used to dump packets ("null sink", "bit bucket") - * - * This block also serves as an example of how to create your own - * C++ classes to control your block. - * - * As a true source, it understands the following stream commands: - * - STREAM_MODE_START_CONTINUOUS - * - STREAM_MODE_STOP_CONTINUOUS - * - * Other stream commands are not understood and issue_stream_cmd() - * will throw if it receives them. - */ -class null_block_ctrl : public source_block_ctrl_base, public sink_block_ctrl_base -{ -public: - // This macro must always be at the top of the public section in an RFNoC block class - UHD_RFNOC_BLOCK_OBJECT(null_block_ctrl) - - //! Set this register to number of lines per packet - static const uint32_t SR_LINES_PER_PACKET = 129; - //! Set this register to number of cycles between producing a line - static const uint32_t SR_LINE_RATE = 130; - //! Set this register to non-zero to start producing data - static const uint32_t SR_ENABLE_STREAM = 131; - - static const size_t DEFAULT_LINES_PER_PACKET = 32; - static const size_t BYTES_PER_LINE = 8; - - //! Custom function to set the rate at which data is produced. - // Note: This is 'cycles per line', so the bit rate is actually - // 64 times this value (byte/s is 8*rate etc.) - // - // Equivalent to writing to line_rate/value in the property tree. - // - // \param The rate you want to set this to - // \param The clock rate of this block's clock domain - // \returns the actual line rate (will find closest possible). - virtual double set_line_rate(double rate, double clock_rate = 166.6e6) = 0; - - //! Return the current line rate. Equivalent to reading line_rate/value - // from the property tree. - virtual double get_line_rate(double clock_rate = 166.6e6) const = 0; - -}; /* class null_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_NULL_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/radio_ctrl.hpp b/host/include/uhd/rfnoc/radio_ctrl.hpp deleted file mode 100644 index 4f8f3bb1d..000000000 --- a/host/include/uhd/rfnoc/radio_ctrl.hpp +++ /dev/null @@ -1,521 +0,0 @@ -// -// Copyright 2015-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP - -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/scalar_node_ctrl.hpp> -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> -#include <uhd/rfnoc/terminator_node_ctrl.hpp> -#include <uhd/rfnoc/tick_node_ctrl.hpp> -#include <uhd/types/direction.hpp> -#include <uhd/types/ranges.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Block controller for all RFNoC-based radio blocks - */ -class UHD_RFNOC_API radio_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base, - public rate_node_ctrl, - public tick_node_ctrl, - public terminator_node_ctrl -{ -public: - UHD_RFNOC_BLOCK_OBJECT(radio_ctrl) - - virtual ~radio_ctrl() {} - - - //! A wildcard channel index - static const size_t ALL_CHANS = size_t(~0); - - //! A wildcard gain element name - static const std::string ALL_GAINS; - - //! A wildcard local oscillator element name - static const std::string ALL_LOS; - - /************************************************************************ - * API calls - ***********************************************************************/ - /*! Return the tick rate on all channels (rx and tx). - * - * \return The tick rate. - */ - virtual double get_rate() const = 0; - - /*! Set the tick/sample rate on all channels (rx and tx). - * - * Will coerce to the nearest possible rate and return the actual value. - */ - virtual double set_rate(double rate) = 0; - - /*! Return the selected TX antenna for channel \p chan. - * - * \return The selected antenna. - */ - virtual std::string get_tx_antenna(const size_t chan) /* const */ = 0; - - /*! Select RX antenna \p for channel \p chan. - * - * \throws uhd::value_error if \p ant is not a valid value. - */ - virtual void set_tx_antenna(const std::string& ant, const size_t chan) = 0; - - /*! Return the selected RX antenna for channel \p chan. - * - * \return The selected antenna. - */ - virtual std::string get_rx_antenna(const size_t chan) /* const */ = 0; - - /*! Select RX antenna \p for channel \p chan. - * - * \throws uhd::value_error if \p ant is not a valid value. - */ - virtual void set_rx_antenna(const std::string& ant, const size_t chan) = 0; - - /*! Return the current transmit LO frequency on channel \p chan. - * - * Note that the AD9361 only has one LO for all TX channels, and the - * \p chan parameter is thus only for API compatibility. - * - * \return The current LO frequency. - */ - virtual double get_tx_frequency(const size_t chan) /* const */ = 0; - - /*! Tune the TX LO for channel \p chan. - * - * This function will attempt to tune as close as possible, and return a - * coerced value of the actual tuning result. - * - * \param freq Frequency in Hz - * \param chan Channel to tune - * - * \return The actual LO frequency. - */ - virtual double set_tx_frequency(const double freq, size_t chan) = 0; - - /*! Return the current receive LO frequency on channel \p chan. - * - * \return The current LO frequency. - */ - virtual double get_rx_frequency(const size_t chan) /* const */ = 0; - - /*! Tune the RX LO for channel \p chan. - * - * This function will attempt to tune as close as possible, and return a - * coerced value of the actual tuning result. - * - * \param freq Requested LO frequency - * \param chan Channel number. - * \return The actual LO frequency. - */ - virtual double set_rx_frequency(const double freq, const size_t chan) = 0; - - /*! Return the transmit gain on channel \p chan - * - * \return The actual gain value - */ - virtual double get_tx_gain(const size_t chan) = 0; - - /*! Set the transmit gain on channel \p chan - * - * This function will attempt to set the gain as close as possible, - * and return a coerced value of the actual gain value. - * - * \return The actual gain value - */ - virtual double set_tx_gain(const double gain, const size_t chan) = 0; - - /*! Return the transmit gain on channel \p chan - * - * \return The actual gain value - */ - virtual double get_rx_gain(const size_t chan) = 0; - - /*! Set the transmit gain on channel \p chan - * - * This function will attempt to set the gain as close as possible, - * and return a coerced value of the actual gain value. - * - * \return The actual gain value - */ - virtual double set_rx_gain(const double gain, const size_t chan) = 0; - - /*! Return the analog filter bandwidth channel \p chan - * - * \return The actual bandwidth value - */ - virtual double get_tx_bandwidth(const size_t chan) = 0; - - /*! Set the analog filter bandwidth channel \p chan - * - * This function will attempt to set the analog bandwidth. - * - * \return The actual bandwidth value - */ - virtual double set_tx_bandwidth(const double bandwidth, const size_t chan) = 0; - - /*! Return the analog filter bandwidth channel \p chan - * - * \return The actual bandwidth value - */ - virtual double get_rx_bandwidth(const size_t chan) = 0; - - /*! Set the analog filter bandwidth channel \p chan - * - * This function will attempt to set the analog bandwidth. - * - * \return The actual bandwidth value - */ - virtual double set_rx_bandwidth(const double bandwidth, const size_t chan) = 0; - - /*! Sets the time in the radio's timekeeper to the given value. - * - * Note that there is a non-deterministic delay between calling this - * function and the valung written to the register. For setting the - * time in alignment with a certain reference time, use - * set_time_next_pps(). - */ - virtual void set_time_now(const time_spec_t& time_spec) = 0; - - /*! Set the time registers at the next pps tick. - * - * The values will not be latched in until the pulse occurs. - * It is recommended that the user sleep(1) after calling to ensure - * that the time registers will be in a known state prior to use. - * - * Note: Because this call sets the time on the "next" pps, - * the seconds in the time spec should be current seconds + 1. - * - * \param time_spec the time to latch into the timekeeper - */ - virtual void set_time_next_pps(const time_spec_t& time_spec) = 0; - - /*! Get the current time in the timekeeper registers. - * - * Note that there is a non-deterministic delay between the time the - * register is read and the time the function value is returned. - * To get the time with respect to a tick edge, use get_time_last_pps(). - * - * \return A timespec representing current radio time - */ - virtual time_spec_t get_time_now() = 0; - - /*! Get the time when the last PPS pulse occurred. - * - * \return A timespec representing the last PPS - */ - virtual time_spec_t get_time_last_pps() = 0; - - /*! Returns the list of GPIO banks that are associated with this radio. - * - * \returns list of GPIO bank names - */ - virtual std::vector<std::string> get_gpio_banks() const = 0; - - /*! - * Set a GPIO attribute on a particular GPIO bank. - * Possible attribute names: - * - CTRL - 1 for ATR mode 0 for GPIO mode - * - DDR - 1 for output 0 for input - * - OUT - GPIO output level (not ATR mode) - * - ATR_0X - ATR idle state - * - ATR_RX - ATR receive only state - * - ATR_TX - ATR transmit only state - * - ATR_XX - ATR full duplex state - * \param bank the name of a GPIO bank (e.g., FP0) - * \param attr the name of a GPIO attribute (e.g., CTRL) - * \param value the new value for this GPIO bank - * \param mask the bit mask to effect which pins are changed - */ - virtual void set_gpio_attr(const std::string& bank, - const std::string& attr, - const uint32_t value, - const uint32_t mask) = 0; - - /*! - * Get a GPIO attribute on a particular GPIO bank. - * Possible attribute names: - * - CTRL - 1 for ATR mode 0 for GPIO mode - * - DDR - 1 for output 0 for input - * - OUT - GPIO output level (not ATR mode) - * - ATR_0X - ATR idle state - * - ATR_RX - ATR receive only state - * - ATR_TX - ATR transmit only state - * - ATR_XX - ATR full duplex state - * - READBACK - readback input GPIOs - * \param bank the name of a GPIO bank - * \param attr the name of a GPIO attribute - * \return the value set for this attribute - */ - virtual uint32_t get_gpio_attr(const std::string& bank, const std::string& attr) = 0; - - /************************************************************************** - * LO Controls - *************************************************************************/ - /*! Get a list of possible LO stage names - * - * \param chan the channel index 0 to N-1 - * \return a vector of strings for possible LO names - */ - virtual std::vector<std::string> get_rx_lo_names(const size_t chan) = 0; - - /*! Get a list of possible LO sources. - * - * Channels which do not have controllable LO sources - * will return "internal". - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_rx_lo_sources( - const std::string& name, const size_t chan) = 0; - - /*! - * Get the LO frequency range of the RX LO. - * If the channel does not have independently configurable LOs - * the rf frequency range will be returned. - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return a frequency range object - */ - virtual freq_range_t get_rx_lo_freq_range( - const std::string& name, const size_t chan) = 0; - - /*! - * Set the LO source for a channel. - * For usrps that support selectable LOs, this function - * allows switching between them. - * Typical options for source: internal, external. - * \param src a string representing the LO source - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 - */ - virtual void set_rx_lo_source( - const std::string& src, const std::string& name, const size_t chan) = 0; - - /*! - * Get the currently set LO source. - * Channels without controllable LO sources will return - * "internal" - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return the configured LO source - */ - virtual const std::string get_rx_lo_source( - const std::string& name, const size_t chan) = 0; - - /*! - * Set whether the LO used by the usrp device is exported - * For usrps that support exportable LOs, this function - * configures if the LO used by chan is exported or not. - * \param enabled if true then export the LO - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 for the source channel - */ - virtual void set_rx_lo_export_enabled( - bool enabled, const std::string& name, const size_t chan) = 0; - - /*! - * Returns true if the currently selected LO is being exported. - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - */ - virtual bool get_rx_lo_export_enabled(const std::string& name, const size_t chan) = 0; - - /*! - * Set the RX LO frequency (Advanced). - * \param freq the frequency to set the LO to - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 - * \return a coerced LO frequency - */ - virtual double set_rx_lo_freq( - double freq, const std::string& name, const size_t chan) = 0; - - /*! - * Get the current RX LO frequency (Advanced). - * If the channel does not have independently configurable LOs - * the current rf frequency will be returned. - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return the configured LO frequency - */ - virtual double get_rx_lo_freq(const std::string& name, const size_t chan) = 0; - - /*! Get a list of possible LO stage names - * - * \param chan the channel index 0 to N-1 - * \return a vector of strings for possible LO names - */ - virtual std::vector<std::string> get_tx_lo_names(const size_t chan) = 0; - - /*! Get a list of possible LO sources. - * - * Channels which do not have controllable LO sources - * will return "internal". - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_tx_lo_sources( - const std::string& name, const size_t chan) = 0; - - /*! - * Get the LO frequency range of the tx LO. - * If the channel does not have independently configurable LOs - * the rf frequency range will be returned. - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return a frequency range object - */ - virtual freq_range_t get_tx_lo_freq_range( - const std::string& name, const size_t chan) = 0; - - /*! - * Set the LO source for a channel. - * For usrps that support selectable LOs, this function - * allows switching between them. - * Typical options for source: internal, external. - * \param src a string representing the LO source - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 - */ - virtual void set_tx_lo_source( - const std::string& src, const std::string& name, const size_t chan) = 0; - - /*! - * Get the currently set LO source. - * Channels without controllable LO sources will return - * "internal" - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return the configured LO source - */ - virtual const std::string get_tx_lo_source( - const std::string& name, const size_t chan) = 0; - - /*! - * Set whether the LO used by the usrp device is exported - * For usrps that support exportable LOs, this function - * configures if the LO used by chan is exported or not. - * \param enabled if true then export the LO - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 for the source channel - */ - virtual void set_tx_lo_export_enabled( - const bool enabled, const std::string& name, const size_t chan) = 0; - - /*! - * Returns true if the currently selected LO is being exported. - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - */ - virtual bool get_tx_lo_export_enabled(const std::string& name, const size_t chan) = 0; - - /*! Set the tx LO frequency (Advanced). - * - * See also multi_usrp::set_tx_lo_freq(). - * - * \param freq the frequency to set the LO to - * \param name the name of the LO stage to update - * \param chan the channel index 0 to N-1 - * \return a coerced LO frequency - */ - virtual double set_tx_lo_freq( - const double freq, const std::string& name, const size_t chan) = 0; - - /*! Get the current TX LO frequency (Advanced). - * - * See also multi_usrp::get_tx_lo_freq() - * - * If the channel does not have independently configurable LOs - * the current RF frequency will be returned. - * - * \param name the name of the LO stage to query - * \param chan the channel index 0 to N-1 - * \return the configured LO frequency - */ - virtual double get_tx_lo_freq(const std::string& name, const size_t chan) = 0; - - /************************************************************************** - * Time and clock control - *************************************************************************/ - - /*! - * Set the time source for this radio. - * - * May affect other radio blocks. - * - * \param source A string representing the time source - * \throws uhd::value_error if the value can't be applied - */ - virtual void set_time_source(const std::string& source) = 0; - - /*! - * Get the currently set time source. - * - * \return the string representing the time source - */ - virtual std::string get_time_source() = 0; - - /*! - * Get a list of possible time sources. - * - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_time_sources() = 0; - - /*! - * Set the clock source for the usrp device (for reference clock). - * - * Typical options for source: internal, external. - * - * \param source a string representing the clock source - */ - virtual void set_clock_source(const std::string& source) = 0; - - /*! - * Get the currently set clock source. - * - * \return the string representing the clock source - */ - virtual std::string get_clock_source() = 0; - - /*! - * Get a list of possible clock sources. - * - * \return a vector of strings for possible settings - */ - virtual std::vector<std::string> get_clock_sources() = 0; - - /*! Given a frontend name, return the channel mapping. - * - * E.g.: For a TwinRX board, there's two frontends, '0' and '1', which - * map to channels 0 and 1 respectively. A BasicRX boards has alphabetical - * frontends (A, B) which map to channels differently. - */ - virtual size_t get_chan_from_dboard_fe( - const std::string& fe, const uhd::direction_t dir) = 0; - - /*! The inverse function to get_chan_from_dboard_fe() - */ - virtual std::string get_dboard_fe_from_chan( - const size_t chan, const uhd::direction_t dir) = 0; - - /*! Enable or disable the setting of timestamps on Rx. - */ - virtual void enable_rx_timestamps(const bool enable, const size_t chan) = 0; -}; /* class radio_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/rate_node_ctrl.hpp b/host/include/uhd/rfnoc/rate_node_ctrl.hpp deleted file mode 100644 index f04af11f4..000000000 --- a/host/include/uhd/rfnoc/rate_node_ctrl.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Sampling-rate-aware node control - * - * A "rate" node is a streaming node is a point in the flow graph - * that is aware of sampling rates. Such nodes include: - * - Radio Controls (these actually set a sampling rate) - * - Decimating FIR filters (their output rates depend on both - * incoming rates and their own settings, i.e. the decimation) - * - Streaming terminators (these need to know the sampling rates - * to configure the connected streamers) - */ -class UHD_RFNOC_API rate_node_ctrl; -class rate_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<rate_node_ctrl> sptr; - //! This value is used by rate nodes that don't actually set a rate themselves - static const double RATE_UNDEFINED; - - /*********************************************************************** - * Rate controls - **********************************************************************/ - /*! Returns the sampling rate this block expects at its input. - * - * A radio will simply return the sampling rate it is set to. - * A decimating FIR filter will ask downstream for the input sampling rate - * and then return that value multiplied by the decimation factor. - * - */ - virtual double get_input_samp_rate(size_t port = ANY_PORT); - virtual double get_output_samp_rate(size_t port = ANY_PORT); - -}; /* class rate_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RATE_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/replay_block_ctrl.hpp b/host/include/uhd/rfnoc/replay_block_ctrl.hpp deleted file mode 100644 index 639d31595..000000000 --- a/host/include/uhd/rfnoc/replay_block_ctrl.hpp +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_REPLAY_BLOCK_HPP -#define INCLUDED_LIBUHD_RFNOC_REPLAY_BLOCK_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Replay block controller - * - * The replay block has the following features: - * - One input and one output - * - The ability to record and playback data - * - Configurable base addresses and buffer sizes - * - Independent record and playback controls - * - Radio-like playback interface - * - The storage for the replay data can be any - * memory, usually an off-chip DRAM. - * - */ -class UHD_RFNOC_API replay_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - UHD_RFNOC_BLOCK_OBJECT(replay_block_ctrl) - - //! Configure the base address and size of the record buffer region (in bytes). - virtual void config_record( - const uint32_t base_addr, const uint32_t size, const size_t chan) = 0; - - //! Configure the base address and size of the playback buffer region (in bytes). - virtual void config_play( - const uint32_t base_addr, const uint32_t size, const size_t chan) = 0; - - //! Restarts recording at the beginning of the record buffer - virtual void record_restart(const size_t chan) = 0; - - //! Returns the base address of the record buffer (in bytes). - virtual uint32_t get_record_addr(const size_t chan) = 0; - - //! Returns the base address of the playback buffer (in bytes). - virtual uint32_t get_play_addr(const size_t chan) = 0; - - //! Returns the size of the record buffer (in bytes). - virtual uint32_t get_record_size(const size_t chan) = 0; - - //! Returns the current fullness of the record buffer (in bytes). - virtual uint32_t get_record_fullness(const size_t chan) = 0; - - //! Returns the size of the playback buffer (in bytes). - virtual uint32_t get_play_size(const size_t chan) = 0; - - //! Sets the size of the packets played by the Replay block (in 64-bit words) - virtual void set_words_per_packet(const uint32_t num_words, const size_t chan) = 0; - - //! Returns the size of the packets played by the Replay block (in 64-bit words) - virtual uint32_t get_words_per_packet(const size_t chan) = 0; - - //! Halts playback and clears the playback command FIFO - virtual void play_halt(const size_t chan) = 0; - -}; /* class replay_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_REPLAY_BLOCK_HPP */ diff --git a/host/include/uhd/rfnoc/scalar_node_ctrl.hpp b/host/include/uhd/rfnoc/scalar_node_ctrl.hpp deleted file mode 100644 index 910a94b0c..000000000 --- a/host/include/uhd/rfnoc/scalar_node_ctrl.hpp +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Scaling node control - * - * A "scalar" node is a streaming node in which a scaling takes - * place, usually for the conversion between fixed point and floating - * point (the latter usually being normalized between -1 and 1). - * - * Such blocks include: - * - Radio Controls - * - Potentially FFTs or FIRs, if they affect scaling - */ -class UHD_RFNOC_API scalar_node_ctrl; -class scalar_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<scalar_node_ctrl> sptr; - //! Undefined scaling - static const double SCALE_UNDEFINED; - - /*********************************************************************** - * Scaling controls - **********************************************************************/ - /*! Returns the scaling factor for this block on input. - * - * A DUC block will return the scaling factor as determined by the duc - * stage. - * - * \param port Port Number - */ - virtual double get_input_scale_factor(size_t port = ANY_PORT); - - /*! Returns the scaling factor for this block on output. - * - * A DDC block will return the scaling factor as determined by the ddc - * stage. - * - * \param port Port Number - */ - virtual double get_output_scale_factor(size_t port = ANY_PORT); - -}; /* class scalar_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_SCALAR_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/siggen_block_ctrl.hpp b/host/include/uhd/rfnoc/siggen_block_ctrl.hpp deleted file mode 100644 index c58d3490d..000000000 --- a/host/include/uhd/rfnoc/siggen_block_ctrl.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright 2014-2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_SIGGEN_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_SIGGEN_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -class UHD_RFNOC_API siggen_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - UHD_RFNOC_BLOCK_OBJECT(siggen_block_ctrl) - -}; /* class siggen_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_SIGGEN_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp b/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp deleted file mode 100644 index 5267612e6..000000000 --- a/host/include/uhd/rfnoc/sink_block_ctrl_base.hpp +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP - -#include <uhd/rfnoc/block_ctrl_base.hpp> -#include <uhd/rfnoc/sink_node_ctrl.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Extends block_ctrl_base with input capabilities. - * - * A sink block is an RFNoC block that can receive data at an input. - * We can use this block to transmit data (In RFNoC nomenclature, a - * transmit operation means streaming data to the device from the host). - * - * Every input is defined by a port definition (port_t). - */ -class UHD_RFNOC_API sink_block_ctrl_base; -class sink_block_ctrl_base : virtual public block_ctrl_base, virtual public sink_node_ctrl -{ -public: - typedef boost::shared_ptr<sink_block_ctrl_base> sptr; - - /*********************************************************************** - * Stream signatures - **********************************************************************/ - /*! Return the input stream signature for a given block port. - * - * The actual signature is determined by the current configuration - * and the block definition file. The value returned here is calculated - * on-the-fly and is only valid as long as the configuration does not - * change. - * - * \returns The stream signature for port \p block_port - * \throws uhd::runtime_error if \p block_port is not a valid port - */ - stream_sig_t get_input_signature(size_t block_port = 0) const; - - /*! Return a list of valid input ports. - */ - std::vector<size_t> get_input_ports() const; - - /*********************************************************************** - * FPGA Configuration - **********************************************************************/ - /*! Return the size of input buffer on a given block port. - * - * This is necessary for setting up flow control, among other things. - * Note: This does not query the block's settings register. The FIFO size - * is queried once during construction and cached. - * - * If the block port is not defined, it will return 0, and not throw. - * - * \param block_port The block port (0 through 15). - * - * Returns the size of the buffer in bytes. - */ - size_t get_fifo_size(size_t block_port = 0) const; - - /*! Return the MTU size on a given block port. - * - * This is necessary for setting up transports, among other things. - * - * If the block port is not defined, it will return 0, and not throw. - * - * \param block_port The block port (0 through 15). - * - * Returns the MTU in bytes. - */ - size_t get_mtu(size_t block_port = 0) const; - - /*! Configure flow control for incoming streams. - * - * If flow control is enabled for incoming streams, this block will periodically - * send out ACKs, telling the upstream block which packets have been consumed, - * so the upstream block can increase his flow control credit. - * - * In the default implementation, this just sets register SR_FLOW_CTRL_PKTS_PER_ACK - * accordingly. - * - * Override this function if your block has port-specific flow control settings. - * - * \param bytes Send an ACK after this many bytes have been consumed. - * Setting this to zero disables flow control acknowledgement. - * \param block_port Set up flow control for a stream coming in on this particular - * block port. - */ - virtual void configure_flow_control_in( - const size_t bytes, const size_t block_port = 0); - - /*! Configure the behaviour for errors on incoming packets - * (e.g. sequence errors). - * - * - */ - virtual void set_error_policy(const std::string& policy); - -protected: - /*********************************************************************** - * Hooks - **********************************************************************/ - /*! Like sink_node_ctrl::_request_input_port(), but also checks - * the port has an input signature. - */ - virtual size_t _request_input_port( - const size_t suggested_port, const uhd::device_addr_t& args) const; - -}; /* class sink_block_ctrl_base */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_TX_BLOCK_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/sink_node_ctrl.hpp b/host/include/uhd/rfnoc/sink_node_ctrl.hpp deleted file mode 100644 index 22100f4c5..000000000 --- a/host/include/uhd/rfnoc/sink_node_ctrl.hpp +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/rfnoc/sink_node_ctrl.hpp> -#include <boost/thread.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Abstract class for sink nodes. - * - * Sink nodes can have upstream blocks. - */ -class UHD_RFNOC_API sink_node_ctrl; -class sink_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<sink_node_ctrl> sptr; - typedef std::map<size_t, boost::weak_ptr<sink_node_ctrl> > node_map_t; - typedef std::pair<size_t, boost::weak_ptr<sink_node_ctrl> > node_map_pair_t; - - /*********************************************************************** - * Sink block controls - **********************************************************************/ - /*! Connect another node upstream of this node. - * - * *Note:* If additional settings are required to make this connection work, - * e.g. configure flow control, these need to be done separately. - * - * If the requested connection is not possible, this function will throw. - * - * \p upstream_node Pointer to the node class to connect - * \p port Suggested port number on this block to connect the upstream - * block to. - * \p args Any arguments that can be useful for determining the port number. - * - * \returns The actual port number used. - */ - size_t connect_upstream(node_ctrl_base::sptr upstream_node, - size_t port = ANY_PORT, - const uhd::device_addr_t& args = uhd::device_addr_t()); - - /*! Call this function to notify a node about its streamer activity. - * - * When \p active is set to true, this means this block is now part of - * an active tx streamer chain. Conversely, when set to false, this means - * the node has been removed from an tx streamer chain. - */ - virtual void set_tx_streamer(bool active, const size_t port); - - -protected: - /*! Ask for a port number to connect an upstream block to. - * - * Typically, this will be overridden for custom behaviour. - * The default is to return the suggested port, disregarding - * \p args, unless \p port == ANY_PORT, in which case the first - * unused input port is returned. - * - * When deriving this function for custom behaviour, consider: - * - The result is used to call register_upstream_node(), which - * has its own checks in place. - * - This function may throw if the arguments can't be resolved. - * The exception will propagate to the user space. - * - Alternatively, the function may return ANY_PORT to signify - * failure. - * - \p args and \p suggested_port should be treated as strong - * suggestions, but there's no reason to just return any valid - * port. - * - * *Note:* For reasons of thread safety, it is recommended to - * never, ever call this function directly. It will be used by - * connect_upstream() which will handle the connection process - * in a thread-safe manner. - * - * \param suggested_port Try and connect here. - * \param args When deciding on a port number, these arguments may be used. - * - * \returns A valid input port, or ANY_PORT on failure. - */ - virtual size_t _request_input_port( - const size_t suggested_port, const uhd::device_addr_t& args) const; - -private: - /*! Makes connecting something to the input thread-safe. - */ - boost::mutex _input_mutex; - - /*! Register a node upstream of this one (i.e., a node that can send data to this - * node). - * - * By definition, the upstream node must of type source_node_ctrl. - * - * This saves a *weak pointer* to the upstream node and checks the port is - * available. Will throw otherwise. - * - * \param upstream_node A pointer to the node instantiation - * \param port Port number the upstream node is connected to - */ - void _register_upstream_node(node_ctrl_base::sptr upstream_node, size_t port); - -}; /* class sink_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_SINK_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/source_block_ctrl_base.hpp b/host/include/uhd/rfnoc/source_block_ctrl_base.hpp deleted file mode 100644 index e79b7ef69..000000000 --- a/host/include/uhd/rfnoc/source_block_ctrl_base.hpp +++ /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 -// - -#ifndef INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP - -#include <uhd/rfnoc/block_ctrl_base.hpp> -#include <uhd/rfnoc/source_node_ctrl.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Extends block_ctrl_base with receive capabilities. - * - * In RFNoC nomenclature, a receive operation means streaming - * data from the device (the crossbar) to the host. - * If a block has receive capabilities, this means we can receive - * data *from* this block. - */ -class UHD_RFNOC_API source_block_ctrl_base; -class source_block_ctrl_base : virtual public block_ctrl_base, - virtual public source_node_ctrl -{ -public: - typedef boost::shared_ptr<source_block_ctrl_base> sptr; - - /*********************************************************************** - * Streaming operations - **********************************************************************/ - /*! Issue a stream command for this block. - * - * There is no guaranteed action for this command. The default implementation - * is to send this command to the next upstream block, or issue a warning if - * there is no upstream block registered. - * - * However, implementations of block_ctrl_base might choose to do whatever seems - * appropriate, including throwing exceptions. This may also be true for some - * stream commands and not for others (i.e. STREAM_MODE_START_CONTINUOUS may be - * implemented, and STREAM_MODE_NUM_SAMPS_AND_DONE may be not). - * - * This function does not check for infinite loops. Example: Say you have two blocks, - * which are both registered as upstream from one another. If they both use - * block_ctrl_base::issue_stream_cmd(), then the stream command will be passed from - * one block to another indefinitely. This will not happen if one the block's - * controller classes overrides this function and actually handles it. - * - * See also register_upstream_block(). - * - * \param stream_cmd The stream command. - * \param chan Channel for which this command is meant (data shall be produced on this - * channel). - */ - virtual void issue_stream_cmd( - const uhd::stream_cmd_t& stream_cmd, const size_t chan = 0); - - /*********************************************************************** - * Stream signatures - **********************************************************************/ - /*! Return the output stream signature for a given block port. - * - * The actual signature is determined by the current configuration - * and the block definition file. The value returned here is calculated - * on-the-fly and is only valid as long as the configuration does not - * change. - * - * \returns The stream signature for port \p block_port - * \throws uhd::runtime_error if \p block_port is not a valid port - */ - stream_sig_t get_output_signature(size_t block_port = 0) const; - - /*! Return a list of valid output ports. - */ - std::vector<size_t> get_output_ports() const; - - /*********************************************************************** - * FPGA Configuration - **********************************************************************/ - /*! Configures data flowing from port \p output_block_port to go to \p next_address - * - * \param next_address Address of the downstream block - * \param output_block_port Port for which this is valid - * - * In the default implementation, this will write the value in \p next_address - * to register SR_NEXT_DST of this blocks settings bus. The value will also - * have bit 16 set to 1, since some blocks require this to respect this value. - */ - virtual void set_destination(uint32_t next_address, size_t output_block_port = 0); - - /*! Configure flow control for outgoing streams. - * - * In the default implementation, this just sets registers SR_FLOW_CTRL_BUF_SIZE - * and SR_FLOW_CTRL_ENABLE accordingly; \b block_port and \p sid are ignored. - * - * Override this function if your block has port-specific flow control settings. - * - * \param enable_output Enable flow control module's output. If disabled, no packets - * will be output regardless of flow control state. \param buf_size_bytes The size of - * the downstream block's input FIFO size in number of bytes. Setting this to zero - * disables byte based flow control. If both byte based flow control and the packet - * limit are set to zero, the block will then produce data as fast as it can. \b - * Warning: This can cause head-of-line blocking, and potentially lock up your device! - * \param lossless_link The link for the connection is lossless. Periodic sync - * packets will be disabled. \param pkt_limit Limit the maximum number of packets in - * flight. Setting this to zero disables packet limiting. Usually kept disabled except - * for special case connections (such as DMA) that support only a finite number of - * packets in flight. \param block_port Specify on which outgoing port this setting is - * valid. \param sid The SID for which this is valid. This is meant for cases where - * the outgoing block port is not sufficient to set the flow control, and as such is - * rarely used. - */ - virtual void configure_flow_control_out(const bool enable_output, - const bool lossless_link, - const size_t buf_size_bytes, - const size_t pkt_limit = 0, - const size_t block_port = 0, - const uhd::sid_t& sid = uhd::sid_t()); - - /*! Return the MTU size on a given block port. - * - * This is necessary for setting up transports, among other things. - * - * If the block port is not defined, it will return 0, and not throw. - * - * \param block_port The block port (0 through 15). - * - * Returns the MTU in bytes. - */ - size_t get_mtu(size_t block_port = 0) const; - - -protected: - /*********************************************************************** - * Hooks - **********************************************************************/ - /*! Like source_node_ctrl::_request_output_port(), but also checks if - * the port has an output signature. - */ - virtual size_t _request_output_port( - const size_t suggested_port, const uhd::device_addr_t& args) const; - -}; /* class source_block_ctrl_base */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RX_BLOCK_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/source_node_ctrl.hpp b/host/include/uhd/rfnoc/source_node_ctrl.hpp deleted file mode 100644 index 1dcc1ecfb..000000000 --- a/host/include/uhd/rfnoc/source_node_ctrl.hpp +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/types/stream_cmd.hpp> -#include <boost/thread.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Abstract class for source nodes. - * - * Source nodes can have downstream blocks. - */ -class UHD_RFNOC_API source_node_ctrl; -class source_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<source_node_ctrl> sptr; - typedef std::map<size_t, boost::weak_ptr<source_node_ctrl> > node_map_t; - typedef std::pair<size_t, boost::weak_ptr<source_node_ctrl> > node_map_pair_t; - - /*********************************************************************** - * Source block controls - **********************************************************************/ - /*! Issue a stream command for this block. - * \param stream_cmd The stream command. - * \param chan Channel Index - */ - virtual void issue_stream_cmd( - const uhd::stream_cmd_t& stream_cmd, const size_t chan = 0) = 0; - - /*! Connect another node downstream of this node. - * - * *Note:* If additional settings are required to make this connection work, - * e.g. configure flow control, these need to be done separately. - * - * If the requested connection is not possible, this function will throw. - * - * \p downstream_node Pointer to the node class to connect - * \p port Suggested port number on this block to connect the downstream - * block to. - * \p args Any arguments that can be useful for determining the port number. - * - * \returns The actual port number used. - */ - size_t connect_downstream(node_ctrl_base::sptr downstream_node, - size_t port = ANY_PORT, - const uhd::device_addr_t& args = uhd::device_addr_t()); - - /*! Call this function to notify a node about its streamer activity. - * - * When \p active is set to true, this means this block is now part of - * an active rx streamer chain. Conversely, when set to false, this means - * the node has been removed from an rx streamer chain. - */ - virtual void set_rx_streamer(bool active, const size_t port); - -protected: - /*! Ask for a port number to connect a downstream block to. - * - * See sink_node_ctrl::_request_input_port(). This is the same - * for output. - * - * \param suggested_port Try and connect here. - * \param args When deciding on a port number, these arguments may be used. - * - * \returns A valid input port, or ANY_PORT on failure. - */ - virtual size_t _request_output_port( - const size_t suggested_port, const uhd::device_addr_t& args) const; - - -private: - /*! Makes connecting something to the output thread-safe. - */ - boost::mutex _output_mutex; - - /*! Register a node downstream of this one (i.e., a node that receives data from this - * node). - * - * By definition, the upstream node must of type sink_node_ctrl. - * - * This saves a *weak pointer* to the downstream node and checks - * the port is available. Will throw otherwise. - * - * \param downstream_node A pointer to the node instantiation - * \param port Port number the downstream node is connected to - */ - void _register_downstream_node(node_ctrl_base::sptr downstream_node, size_t port); - -}; /* class source_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_SOURCE_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/stream_sig.hpp b/host/include/uhd/rfnoc/stream_sig.hpp deleted file mode 100644 index 3b8482781..000000000 --- a/host/include/uhd/rfnoc/stream_sig.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright 2014-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP -#define INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP - -#include <uhd/config.hpp> -#include <iostream> - -namespace uhd { namespace rfnoc { - -/*! Describes a stream signature for data going to or coming from - * RFNoC ports. - * - * The stream signature may depend on a block's configuration. Even - * so, some attributes may be left undefined (e.g., a FIFO block - * works for any item type, so it doesn't need to set it). - */ -class UHD_RFNOC_API stream_sig_t -{ -public: - /*********************************************************************** - * Structors - ***********************************************************************/ - stream_sig_t(); - - /*********************************************************************** - * The stream signature attributes - ***********************************************************************/ - //! The data type of the individual items (e.g. 'sc16'). If undefined, set - // to empty. - std::string item_type; - - //! The vector length in multiples of items. If undefined, set to zero. - size_t vlen; - - //! Packet size in bytes. If undefined, set to zero. - size_t packet_size; - - bool is_bursty; - - /*********************************************************************** - * Helpers - ***********************************************************************/ - //! Compact string representation - std::string to_string(); - //! Pretty-print string representation - std::string to_pp_string(); - - //! Returns the number of bytes necessary to store one item. - // Note: The vector length is *not* considered here. - // - // \returns Number of bytes per item or 0 if the item type is - // undefined. - // \throws uhd::key_error if the item type is invalid. - size_t get_bytes_per_item() const; - - /*! Check if an output with signature \p output_sig could - * stream to an input signature \p input_sig. - * - * \return true if streams are compatible - */ - static bool is_compatible( - const stream_sig_t& output_sig, const stream_sig_t& input_sig); -}; - -//! Shortcut for << stream_sig.to_string() -UHD_INLINE std::ostream& operator<<(std::ostream& out, stream_sig_t stream_sig) -{ - out << stream_sig.to_string().c_str(); - return out; -} - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_STREAMSIG_HPP */ diff --git a/host/include/uhd/rfnoc/terminator_node_ctrl.hpp b/host/include/uhd/rfnoc/terminator_node_ctrl.hpp deleted file mode 100644 index 5909a6367..000000000 --- a/host/include/uhd/rfnoc/terminator_node_ctrl.hpp +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/node_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Abstract class for terminator nodes (i.e. nodes that terminate - * the flow graph). - * - * Terminator nodes have the following properties: - * - Data flowing into such a node is not propagated to any other node, and - * data coming out of this node originates in this node. - * - Chain commands are not propagated past this node. - * - * A block may be a terminator node, but have both upstream and downstream - * nodes. An example is the radio block, which can be used for Rx and Tx. - * Even if it's used for both, the data going into the radio block is not - * the data coming out. - */ -class UHD_RFNOC_API terminator_node_ctrl; -class terminator_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<terminator_node_ctrl> sptr; - -}; /* class terminator_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_TERMINATOR_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/tick_node_ctrl.hpp b/host/include/uhd/rfnoc/tick_node_ctrl.hpp deleted file mode 100644 index da75a209f..000000000 --- a/host/include/uhd/rfnoc/tick_node_ctrl.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP -#define INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP - -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Tick-rate-aware node control - * - * A "rate" node is a streaming node is a point in the flow graph - * that is aware of tick rates (time base). Such nodes include: - * - Radio Controls - * - Data generating blocks that add time stamps - */ -class UHD_RFNOC_API tick_node_ctrl; -class tick_node_ctrl : virtual public node_ctrl_base -{ -public: - /*********************************************************************** - * Types - **********************************************************************/ - typedef boost::shared_ptr<tick_node_ctrl> sptr; - - /*********************************************************************** - * Constants - **********************************************************************/ - //! This value is used by rate nodes that don't actually set a rate themselves - static const double RATE_UNDEFINED; - - /*********************************************************************** - * Rate controls - **********************************************************************/ - /*! Return a tick rate. - * - * This might be either a tick rate defined by this block (see also _get_tick_rate()) - * or it's a tick rate defined by an adjacent block. - * In that case, performs a graph search to figure out the tick rate. - */ - double get_tick_rate(const std::set<node_ctrl_base::sptr>& _explored_nodes = - std::set<node_ctrl_base::sptr>()); - -protected: - virtual double _get_tick_rate() - { - return RATE_UNDEFINED; - }; - -}; /* class tick_node_ctrl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_TICK_NODE_CTRL_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/window_block_ctrl.hpp b/host/include/uhd/rfnoc/window_block_ctrl.hpp deleted file mode 100644 index ee5439b40..000000000 --- a/host/include/uhd/rfnoc/window_block_ctrl.hpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright 2014-2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_WINDOW_BLOCK_CTRL_HPP -#define INCLUDED_LIBUHD_RFNOC_WINDOW_BLOCK_CTRL_HPP - -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> - -namespace uhd { namespace rfnoc { - -/*! \brief Block controller for the standard windowing RFNoC block. - * - * The standard windowing block has the following features: - * - One input- and output-port - * - Configurable window length and coefficients - * - Supports data type sc16 (16-Bit fix-point complex samples) - * - * This block requires packets to be the same size as the downstream FFT length. - * It will perform one window operation per incoming packet, treating it - * as a vector of samples. - */ -class UHD_RFNOC_API window_block_ctrl : public source_block_ctrl_base, - public sink_block_ctrl_base -{ -public: - UHD_RFNOC_BLOCK_OBJECT(window_block_ctrl) - - static const size_t MAX_COEFF_VAL = 32767; - static const uint32_t SR_WINDOW_LEN = 131; // Note: AXI config bus uses 129 & 130 - static const uint32_t RB_MAX_WINDOW_LEN = 0; - static const uint32_t AXIS_WINDOW_LOAD = AXIS_CONFIG_BUS + 0; // 2*0+0 - static const uint32_t AXIS_WINDOW_LOAD_TLAST = AXIS_CONFIG_BUS + 1; // 2*0+1 - - //! Configure the window coefficients - // - // \p coeffs size determines the window length. If it longer than - // the maximum window length, throws a uhd::value_error. - virtual void set_window(const std::vector<int>& coeffs) = 0; - - //! Returns the maximum window length. - virtual size_t get_max_len() const = 0; - - //! Returns the current window length. - virtual size_t get_window_len() const = 0; - -}; /* class window_block_ctrl*/ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_WINDOW_BLOCK_CTRL_HPP */ diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 400b3db0b..a74f025bf 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -6,6 +6,7 @@ # UHD_INSTALL(FILES + adapter_id.hpp bounded_buffer.hpp bounded_buffer.ipp buffer_pool.hpp diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 09b39f454..c59213e92 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -23,11 +23,6 @@ class UHD_API managed_buffer public: managed_buffer(void) : _ref_count(0), _buffer(NULL), _length(0) { -#ifdef UHD_TXRX_DEBUG_PRINTS - _mb_num = s_buffer_count; - // From Boost website: atomic_count seems only to have precrement operator. - ++s_buffer_count; -#endif } virtual ~managed_buffer(void) {} @@ -83,24 +78,11 @@ public: return (int)_ref_count; } -#ifdef UHD_TXRX_DEBUG_PRINTS - int num() const - { - return _mb_num; - } -#endif - protected: void* _buffer; size_t _length; -#ifdef UHD_TXRX_DEBUG_PRINTS - int _mb_num; -#endif private: -#ifdef UHD_TXRX_DEBUG_PRINTS - static boost::detail::atomic_count s_buffer_count; -#endif }; UHD_INLINE void intrusive_ptr_add_ref(managed_buffer* p) diff --git a/host/include/uhd/transport/zero_copy_recv_offload.hpp b/host/include/uhd/transport/zero_copy_recv_offload.hpp deleted file mode 100644 index 04878f72d..000000000 --- a/host/include/uhd/transport/zero_copy_recv_offload.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_UHD_ZERO_COPY_RECV_OFFLOAD_HPP -#define INCLUDED_UHD_ZERO_COPY_RECV_OFFLOAD_HPP - -#include <uhd/config.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <boost/shared_ptr.hpp> - -namespace uhd { namespace transport { - -/*! - * A threaded transport offload that is meant to relieve the main thread of - * the responsibility of making receive calls. - */ -class UHD_API zero_copy_recv_offload : public virtual zero_copy_if -{ -public: - typedef boost::shared_ptr<zero_copy_recv_offload> sptr; - - /*! - * This transport offload adds a receive thread in order to - * communicate with the underlying transport. It is meant to be - * used in cases where the main thread needs to be relieved of the burden - * of the underlying transport receive calls. - * - * \param transport a shared pointer to the transport interface - * \param timeout a general timeout for pushing and pulling on the bounded buffer - */ - static sptr make(zero_copy_if::sptr transport, const double timeout); -}; - -}} // namespace uhd::transport - -#endif /* INCLUDED_ZERO_COPY_OFFLOAD_HPP */ diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index a0eccc3f0..47f68315d 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -1,17 +1,18 @@ # # Copyright 2010-2011,2015-2016 Ettus Research LLC # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # - UHD_INSTALL(FILES byte_vector.hpp device_addr.hpp dict.ipp dict.hpp direction.hpp + eeprom.hpp endianness.hpp io_type.hpp mac_addr.hpp @@ -20,7 +21,6 @@ UHD_INSTALL(FILES ref_vector.hpp sensors.hpp serial.hpp - sid.hpp stream_cmd.hpp time_spec.hpp tune_request.hpp diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp deleted file mode 100644 index c552bdeb3..000000000 --- a/host/include/uhd/types/sid.hpp +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_UHD_TYPES_SID_HPP -#define INCLUDED_UHD_TYPES_SID_HPP - -#include <uhd/config.hpp> -#include <stdint.h> -#include <iostream> - -namespace uhd { -/*! - * \brief Represents a stream ID (SID). - * - * A stream ID (SID) is an identifier for data. - * It is a 32-Bit value which consists of 16 Bits - * for the source address and 16 Bits for the destination - * address. - * Every address is split into two parts: The _address_, which - * identifies the device used, and the _endpoint_, which identifies - * a specific object inside the given device (e.g., a block). - * *Note:* In the case where there are several crossbars on a single - * device, each crossbar gets its own address. - * Both address and endpoint are 8 bits in length. If a 16-bit address - * is required, we use the combination of the 8-bit address and the 8-bit - * endpoint. - * - * <pre> - * +-------------+--------------+-------------+--------------+ - * | SRC address | SRC endpoint | DST address | DST endpoint | - * +-------------+--------------+-------------+--------------+ - * </pre> - * - * \section sid_str_repr String Representation (pretty printing) - * - * The string representation of a SID is of the form - * - * 2.3>0.6 - * - * The '>' symbol shows the direction, so in this case, - * data is flowing from address 2.3 to 0.6. - * - * As a convention, ':' is used instead of '.' when giving the - * SID in hexadecimal numbers, and two characters are used for each - * address part. As an example, the following two SIDs are identical: - * - * 2.3>0.16 (decimal) - * 02:03>00:10 (hexadecimal) - * - * The format is: - * SRC_ADDRESS.SRC_ENDPOINT>DST_ADDRESS.DST_ENDPOINT - * - * - * \section sid_block_ports Block Ports - * - * In the special case where a block on a crossbar is addressed, the - * endpoint is further split up into two parts of four bits each: The - * first four bits specify the port number on the crossbar, whereas the - * lower four bits represent the *block port*. As an example, consider - * the following SID, given in hexadecimal: - * - * 00:10>02:A1 - * - * In this example, assume data is flowing from the host computer to an - * X300. The crossbar address is 02. The endpoint is A1, which means we - * are accessing a block on crossbar port A (the tenth port), and are addressing - * block port 1. - * - */ -class UHD_API sid_t -{ -public: - //! Create an unset SID - sid_t(); - //! Create a sid_t object from a 32-Bit SID value - sid_t(uint32_t sid); - //! Create a sid_t object from its four components - sid_t(uint8_t src_addr, uint8_t src_ep, uint8_t dst_addr, uint8_t dst_ep); - //! Convert a string representation of a SID into its numerical representation - sid_t(const std::string&); - - //! Copy a sid - sid_t(const sid_t& sid) { - set_sid(sid.get_sid()); - } - - //! Return a decimal string representation of the SID. - std::string to_pp_string() const; - //! Return a hexadecimal string representation of the SID. - std::string to_pp_string_hex() const; - - //! Returns true if this actually holds a valid SID - bool is_set() const - { - return _set; - }; - - // Getters - // - //! Alias for get_sid() - inline uint32_t get() const - { - return get_sid(); - }; - //! Returns a 32-Bit representation of the SID if set, or zero otherwise. - inline uint32_t get_sid() const - { - return _set ? _sid : 0; - }; - //! Return the 16-bit source address of this SID - inline uint32_t get_src() const - { - return (_sid >> 16) & 0xFFFF; - } - //! Return the 16-bit destination address of this SID - inline uint32_t get_dst() const - { - return _sid & 0xFFFF; - } - //! Return 8-bit address of the source - inline uint32_t get_src_addr() const - { - return (get_src() >> 8) & 0xFF; - } - //! Return endpoint of the source - inline uint32_t get_src_endpoint() const - { - return get_src() & 0xFF; - } - //! Return crossbar port of the source - inline uint32_t get_src_xbarport() const - { - return (get_src_endpoint() >> 4) & 0xF; - } - //! Return block port of the source - inline uint32_t get_src_blockport() const - { - return (get_src_endpoint()) & 0xF; - } - //! Return 8-bit address of the destination - inline uint32_t get_dst_addr() const - { - return (get_dst() >> 8) & 0xFF; - } - //! Return endpoint of the destination - inline uint32_t get_dst_endpoint() const - { - return get_dst() & 0xFF; - } - //! Return crossbar port of the source - inline uint32_t get_dst_xbarport() const - { - return (get_dst_endpoint() >> 4) & 0xF; - } - //! Return block port of the source - inline uint32_t get_dst_blockport() const - { - return (get_dst_endpoint()) & 0xF; - } - - // Setters - - //! Alias for set_sid() - void set(uint32_t new_sid) - { - set_sid(new_sid); - }; - //! Convert a string representation of a SID into a numerical one - // Throws uhd::value_error if the string is not a valid SID - // representation. - void set_from_str(const std::string&); - void set_sid(uint32_t new_sid); - //! Set the source address of this SID - // (the first 16 Bits) - void set_src(uint32_t new_addr); - //! Set the destination address of this SID - // (the last 16 Bits) - void set_dst(uint32_t new_addr); - void set_src_addr(uint32_t new_addr); - void set_src_endpoint(uint32_t new_addr); - void set_dst_addr(uint32_t new_addr); - void set_dst_endpoint(uint32_t new_addr); - void set_dst_xbarport(uint32_t new_xbarport); - void set_dst_blockport(uint32_t new_blockport); - - // Manipulators - - //! Swaps dst and src address and returns the new SID. - sid_t reversed() const; - - //! Swaps dst and src in-place. This modifies the current SID. - void reverse(); - - // Overloaded operators - - sid_t operator=(const uint32_t new_sid) - { - set_sid(new_sid); - return *this; - } - - sid_t operator=(const sid_t& sid) - { - set_sid(sid.get_sid()); - return *this; - } - - sid_t operator=(const std::string& sid_str) - { - set_from_str(sid_str); - return *this; - } - - bool operator==(const sid_t& sid) const - { - return (not _set and not sid.is_set()) or (_sid == sid.get_sid()); - } - - bool operator==(uint32_t sid) const - { - return _set and _sid == sid; - } - - bool operator==(const std::string& sid_str) const - { - sid_t rhs(sid_str); - return *this == rhs; - } - - // overloaded type casts are tricky, but for now we'll need them - // for backward compatibility. consider them deprecated. - - //! If the SID is not set, always returns zero. - // Use is_set() to check if the return value is valid. - operator uint32_t() const - { - return get(); - } - - operator bool() const - { - return _set; - } - -private: - uint32_t _sid; - bool _set; -}; - -//! Stream output operator. Honors std::ios::hex. -inline std::ostream& operator<<(std::ostream& out, const sid_t& sid) -{ - std::ios_base::fmtflags ff = out.flags(); - if (ff & std::ios::hex) { - out << sid.to_pp_string_hex(); - } else { - out << sid.to_pp_string(); - } - return out; -} - -} // namespace uhd - -#endif /* INCLUDED_UHD_TYPES_SID_HPP */ diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt index 767e56c44..bf367f63d 100644 --- a/host/include/uhd/utils/CMakeLists.txt +++ b/host/include/uhd/utils/CMakeLists.txt @@ -13,6 +13,7 @@ UHD_INSTALL(FILES byteswap.ipp cast.hpp csv.hpp + dirty_tracked.hpp fp_compare_delta.ipp fp_compare_epsilon.ipp gain_group.hpp diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index d15c8b264..4e2cf9022 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -116,7 +116,6 @@ configure_file( LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_BINARY_DIR}/build_info.cpp ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/device3.cpp ${CMAKE_CURRENT_SOURCE_DIR}/image_loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/stream.cpp ${CMAKE_CURRENT_SOURCE_DIR}/exception.cpp diff --git a/host/lib/device3.cpp b/host/lib/device3.cpp deleted file mode 100644 index 90fb1c7fe..000000000 --- a/host/lib/device3.cpp +++ /dev/null @@ -1,67 +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/device3.hpp> -#include <uhd/utils/log.hpp> -#include <boost/format.hpp> -#include <boost/thread/lock_guard.hpp> - -using namespace uhd; -using namespace uhd::rfnoc; - -device3::sptr device3::make(const device_addr_t &hint, const size_t which) -{ - device3::sptr device3_sptr = - boost::dynamic_pointer_cast< device3 >(device::make(hint, device::USRP, which)); - if (not device3_sptr) { - throw uhd::key_error(str( - boost::format("No gen-3 devices found for ----->\n%s") % hint.to_pp_string() - )); - } - - return device3_sptr; -} - -bool device3::has_block(const rfnoc::block_id_t &block_id) const -{ - for (size_t i = 0; i < _rfnoc_block_ctrl.size(); i++) { - if (_rfnoc_block_ctrl[i]->get_block_id() == block_id) { - return true; - } - } - return false; -} - -block_ctrl_base::sptr device3::get_block_ctrl(const block_id_t &block_id) const -{ - for (size_t i = 0; i < _rfnoc_block_ctrl.size(); i++) { - if (_rfnoc_block_ctrl[i]->get_block_id() == block_id) { - return _rfnoc_block_ctrl[i]; - } - } - throw uhd::lookup_error(str(boost::format("This device does not have a block with ID: %s") % block_id.to_string())); -} - -std::vector<rfnoc::block_id_t> device3::find_blocks(const std::string &block_id_hint) const -{ - std::vector<rfnoc::block_id_t> block_ids; - for (size_t i = 0; i < _rfnoc_block_ctrl.size(); i++) { - if (_rfnoc_block_ctrl[i]->get_block_id().match(block_id_hint)) { - block_ids.push_back(_rfnoc_block_ctrl[i]->get_block_id()); - } - } - return block_ids; -} - -void device3::clear() -{ - boost::lock_guard<boost::mutex> lock(_block_ctrl_mutex); - for(const block_ctrl_base::sptr &block: _rfnoc_block_ctrl) { - block->clear(); - } -} -// vim: sw=4 et: diff --git a/host/lib/include/uhdlib/rfnoc/async_msg_handler.hpp b/host/lib/include/uhdlib/rfnoc/async_msg_handler.hpp deleted file mode 100644 index cd1aed37d..000000000 --- a/host/lib/include/uhdlib/rfnoc/async_msg_handler.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_AYNC_MSG_HANDLER_HPP -#define INCLUDED_LIBUHD_RFNOC_AYNC_MSG_HANDLER_HPP - -#include <uhd/rfnoc/graph.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/types/endianness.hpp> -#include <uhdlib/rfnoc/async_msg.hpp> -#include <uhd/utils/noncopyable.hpp> -#include <functional> - -namespace uhd { namespace rfnoc { - -/*! Async message handler for a uhd::rfnoc::graph - * - */ -class async_msg_handler : uhd::noncopyable -{ -public: - typedef boost::shared_ptr<async_msg_handler> sptr; - typedef std::function<void(const async_msg_t&)> async_handler_type; - - /*! - * \param recv A transport on which async messages are received - * \param send A transport on which to send response messages - * \param sid The source part of this is taken as the local address of the - * transports. The remote part is ignored. - */ - static sptr make( - uhd::transport::zero_copy_if::sptr recv, - uhd::transport::zero_copy_if::sptr send, - uhd::sid_t sid, - uhd::endianness_t endianness - ); - - /*! Register an event handler. - * - * When any message is received with the given event code, - * \p handler is called with the async message data as an argument. - * - * Note that \p handler is called if a message includes a certain event - * code, but it does not have to be exclusive. Example: If there are two - * event handlers registered, one for EVENT_CODE_OVERRUN and one for - * EVENT_CODE_BAD_PACKET, and a message includes both those event codes, - * then both event handlers are called. - * - * Multiple handlers per event code may be registered. The order they are - * called in is non-deterministic. - * - * \returns The number of event handlers registered for this event code. - * Should never return anything less than 1. - */ - virtual int register_event_handler( - const async_msg_t::event_code_t event_code, - async_handler_type handler - ) = 0; - - /*! Post async messages into this message handler. - * - * This is the entry point for all async messages. When a message - * is posted here, the following actions take place: - * - If applicable, an event handler is called with \p metadata as the - * argument - * - Some messages print error codes (e.g. O, U, L, S) - */ - virtual void post_async_msg( - const async_msg_t &metadata - ) = 0; - - /*! Return the 16-bit address of this async message - */ - virtual uint32_t get_local_addr() const = 0; -}; - - -}}; /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_AYNC_MSG_HANDLER_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp b/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp deleted file mode 100644 index 29b2e73c0..000000000 --- a/host/lib/include/uhdlib/rfnoc/ctrl_iface.hpp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright 2012-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_CTRL_IFACE_HPP -#define INCLUDED_LIBUHD_RFNOC_CTRL_IFACE_HPP - -#include "xports.hpp" -#include <boost/shared_ptr.hpp> -#include <string> - -namespace uhd { namespace rfnoc { - -/*! - * Provide read/write access to registers on an RFNoC block via Noc-Shell. - */ -class ctrl_iface -{ -public: - typedef boost::shared_ptr<ctrl_iface> sptr; - virtual ~ctrl_iface(void) {} - - /*! Make a new control object - * - * \param xports Bidirectional transport object to the RFNoC block port. - * \param name Optional name for better identification in error messages. - */ - static sptr make( - const both_xports_t &xports, - const std::string &name="0" - ); - - /*! Send a command packet. - * - * \param addr Register address. This is the value that gets put into the - * command packet, its interpretation is defined on the FPGA. - * \param data Register value to write. - * \param readback If true, assume the command packet is for a readback, - * and wait for a response packet to return. The return - * value will then be the 64-bit payload of that response - * packet. If false, the return value is the payload of - * any outstanding ACK packet. - * \param timestamp Optional timestamp. The command packet will include this - * timestamp. Depending on the block configuration, this - * can trigger timed commands. - * A value of zero indicates that no timestamp will be - * applied. It is not possible to request anything to - * happen at time zero. - * - * \throws uhd::io_error if the response is malformed; uhd::runtime_error if - * no packet could be sent. - */ - virtual uint64_t send_cmd_pkt( - const size_t addr, - const size_t data, - const bool readback=false, - const uint64_t timestamp=0 - ) = 0; - - /*! Set the depth of the command FIFO size - * - * Note: This is not safe to call during operations. Call this during - * initialization. - * - * \param num_lines The number of lines of depth in the command FIFO. The - * function will calculate the number of packets that will - * fit into the command FIFO. - */ - virtual void set_cmd_fifo_size(const size_t num_lines) = 0; -}; - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_CTRL_IFACE_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/graph_impl.hpp b/host/lib/include/uhdlib/rfnoc/graph_impl.hpp deleted file mode 100644 index 4147acedf..000000000 --- a/host/lib/include/uhdlib/rfnoc/graph_impl.hpp +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_GRAPH_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_GRAPH_IMPL_HPP - -#include "async_msg_handler.hpp" -#include <uhd/device3.hpp> -#include <uhd/rfnoc/graph.hpp> - -namespace uhd { namespace rfnoc { - -class graph_impl : public graph -{ -public: - /************************************************************************ - * Structors - ***********************************************************************/ - /*! - * \param name An optional name to describe this graph - * \param device_ptr Weak pointer to the originating device3 - * \param msg_handler Pointer to the async message handler - */ - graph_impl(const std::string& name, - boost::weak_ptr<uhd::device3> device_ptr, - async_msg_handler::sptr msg_handler); - virtual ~graph_impl() {} - - /************************************************************************ - * Connection API - ***********************************************************************/ - void 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 = 0); - - void connect(const block_id_t& src_block, const block_id_t& dst_block); - - void 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_); - - void connect_sink(const block_id_t& sink_block, - const size_t dst_block_port, - const size_t bytes_per_ack); - - /************************************************************************ - * Utilities - ***********************************************************************/ - std::string get_name() const - { - return _name; - } - - -private: - void handle_overruns(const async_msg_t& async_msg); - - //! Maps 16-bit addresses to block IDs - std::map<uint32_t, block_id_t> _block_id_map; - - //! For any given block, look up the MIMO group - std::map<uint32_t, size_t> _mimo_group_map; - - //! For any MIMO group, store the list of blocks in that group - std::map<size_t, std::set<block_id_t>> _mimo_groups; - - //! Optional: A string to describe this graph - const std::string _name; - - //! Reference to the generating device object - const boost::weak_ptr<uhd::device3> _device_ptr; - - //! Reference to the async message handler - async_msg_handler::sptr _msg_handler; -}; - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_GRAPH_IMPL_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/legacy_compat.hpp b/host/lib/include/uhdlib/rfnoc/legacy_compat.hpp deleted file mode 100644 index 185b89f82..000000000 --- a/host/lib/include/uhdlib/rfnoc/legacy_compat.hpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_RFNOC_LEGACY_COMPAT_HPP -#define INCLUDED_RFNOC_LEGACY_COMPAT_HPP - -#include <uhd/device3.hpp> -#include <uhd/stream.hpp> - -namespace uhd { namespace rfnoc { - - /*! Legacy compatibility layer class. - */ - class legacy_compat - { - public: - typedef boost::shared_ptr<legacy_compat> sptr; - - virtual uhd::fs_path rx_dsp_root(const size_t mboard_idx, const size_t chan) = 0; - - virtual uhd::fs_path tx_dsp_root(const size_t mboard_idx, const size_t chan) = 0; - - virtual uhd::fs_path rx_fe_root(const size_t mboard_idx, const size_t chan) = 0; - - virtual uhd::fs_path tx_fe_root(const size_t mboard_idx, const size_t chan) = 0; - - virtual void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, size_t mboard, size_t chan) = 0; - - virtual uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args) = 0; - - virtual uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args) = 0; - - virtual void set_rx_rate(const double rate, const size_t chan) = 0; - - virtual void set_tx_rate(const double rate, const size_t chan) = 0; - - static sptr make( - uhd::device3::sptr device, - const uhd::device_addr_t &args - ); - }; - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_RFNOC_LEGACY_COMPAT_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/radio_ctrl_impl.hpp b/host/lib/include/uhdlib/rfnoc/radio_ctrl_impl.hpp deleted file mode 100644 index af4168d8b..000000000 --- a/host/lib/include/uhdlib/rfnoc/radio_ctrl_impl.hpp +++ /dev/null @@ -1,249 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP - -#include <uhd/rfnoc/radio_ctrl.hpp> -#include <uhd/types/direction.hpp> -#include <uhdlib/usrp/cores/rx_vita_core_3000.hpp> -#include <uhdlib/usrp/cores/tx_vita_core_3000.hpp> -#include <uhdlib/usrp/cores/time_core_3000.hpp> -#include <uhdlib/usrp/cores/gpio_atr_3000.hpp> -#include <boost/thread.hpp> -#include <mutex> - -//! Shorthand for radio block constructor -#define UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(CLASS_NAME) \ - CLASS_NAME##_impl(const make_args_t &make_args); - -#define UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(CLASS_NAME) \ - CLASS_NAME##_impl::CLASS_NAME##_impl( \ - const make_args_t &make_args \ - ) : block_ctrl_base(make_args), radio_ctrl_impl() - -namespace uhd { - namespace rfnoc { - -/*! \brief Provide access to a radio. - * - */ -class radio_ctrl_impl : public radio_ctrl -{ -public: - /************************************************************************ - * Structors - ***********************************************************************/ - radio_ctrl_impl(); - virtual ~radio_ctrl_impl() {}; - - /************************************************************************ - * Public Radio API calls - ***********************************************************************/ - virtual double set_rate(double rate); - virtual void set_tx_antenna(const std::string &ant, const size_t chan); - virtual void set_rx_antenna(const std::string &ant, const size_t chan); - virtual double set_tx_frequency(const double freq, const size_t chan); - virtual double set_rx_frequency(const double freq, const size_t chan); - virtual double set_tx_gain(const double gain, const size_t chan); - virtual double set_rx_gain(const double gain, const size_t chan); - virtual double set_tx_bandwidth(const double bandwidth, const size_t chan); - virtual double set_rx_bandwidth(const double bandwidth, const size_t chan); - - virtual double get_rate() const; - virtual std::string get_tx_antenna(const size_t chan) /* const */; - virtual std::string get_rx_antenna(const size_t chan) /* const */; - virtual double get_tx_frequency(const size_t) /* const */; - virtual double get_rx_frequency(const size_t) /* const */; - virtual double get_tx_gain(const size_t) /* const */; - virtual double get_rx_gain(const size_t) /* const */; - virtual double get_tx_bandwidth(const size_t) /* const */; - virtual double get_rx_bandwidth(const size_t) /* const */; - - virtual std::vector<std::string> get_rx_lo_names(const size_t chan); - virtual std::vector<std::string> get_rx_lo_sources(const std::string &name, const size_t chan); - virtual freq_range_t get_rx_lo_freq_range(const std::string &name, const size_t chan); - - virtual void set_rx_lo_source(const std::string &src, const std::string &name, const size_t chan); - virtual const std::string get_rx_lo_source(const std::string &name, const size_t chan); - - virtual void set_rx_lo_export_enabled(bool enabled, const std::string &name, const size_t chan); - virtual bool get_rx_lo_export_enabled(const std::string &name, const size_t chan); - - virtual double set_rx_lo_freq(const double freq, const std::string &name, const size_t chan); - virtual double get_rx_lo_freq(const std::string &name, const size_t chan); - - virtual std::vector<std::string> get_tx_lo_names(const size_t chan); - virtual std::vector<std::string> get_tx_lo_sources(const std::string &name, const size_t chan); - virtual freq_range_t get_tx_lo_freq_range(const std::string &name, const size_t chan); - - virtual void set_tx_lo_source(const std::string &src, const std::string &name, const size_t chan); - virtual const std::string get_tx_lo_source(const std::string &name, const size_t chan); - - virtual void set_tx_lo_export_enabled(const bool enabled, const std::string &name, const size_t chan); - virtual bool get_tx_lo_export_enabled(const std::string &name, const size_t chan); - - virtual double set_tx_lo_freq(const double freq, const std::string &name, const size_t chan); - virtual double get_tx_lo_freq(const std::string &name, const size_t chan); - - void set_time_now(const time_spec_t &time_spec); - void set_time_next_pps(const time_spec_t &time_spec); - void set_time_sync(const uhd::time_spec_t &time); - time_spec_t get_time_now(); - time_spec_t get_time_last_pps(); - virtual void set_time_source(const std::string &source); - virtual std::string get_time_source(); - virtual std::vector<std::string> get_time_sources(); - virtual void set_clock_source(const std::string &source); - virtual std::string get_clock_source(); - virtual std::vector<std::string> get_clock_sources(); - - virtual std::vector<std::string> get_gpio_banks() const; - virtual void set_gpio_attr( - const std::string &bank, - const std::string &attr, - const uint32_t value, - const uint32_t mask - ); - virtual uint32_t get_gpio_attr(const std::string &bank, const std::string &attr); - void enable_rx_timestamps(const bool, const size_t); - - /*********************************************************************** - * Block control API calls - **********************************************************************/ - void set_rx_streamer(bool active, const size_t port); - void set_tx_streamer(bool active, const size_t port); - - void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t port); - - virtual double get_input_samp_rate(size_t /* port */) { return get_rate(); } - virtual double get_output_samp_rate(size_t /* port */) { return get_rate(); } - double _get_tick_rate() { return get_rate(); } - - std::vector<size_t> get_active_rx_ports(); - bool in_continuous_streaming_mode(const size_t chan) { return _continuous_streaming.at(chan); } - void rx_ctrl_clear_cmds(const size_t port) { sr_write(regs::RX_CTRL_CLEAR_CMDS, 0, port); } - -protected: // TODO see what's protected and what's private - void _register_loopback_self_test(size_t chan); - - /*********************************************************************** - * Registers - **********************************************************************/ - struct regs { - static inline uint32_t sr_addr(const uint32_t offset) { return offset * 4; } - static inline uint32_t rb_addr(const uint32_t offset) { return offset * 8; } - - static const uint32_t BASE = 128; - - // defined in radio_core_regs.vh - static const uint32_t TIME = 128; // time hi - 128, time lo - 129, ctrl - 130 - static const uint32_t CLEAR_CMDS = 131; // Any write to this reg clears the command FIFO - static const uint32_t LOOPBACK = 132; - static const uint32_t TEST = 133; - static const uint32_t CODEC_IDLE = 134; - static const uint32_t TX_CTRL_ERROR_POLICY = 144; - static const uint32_t RX_CTRL_CMD = 152; - static const uint32_t RX_CTRL_TIME_HI = 153; - static const uint32_t RX_CTRL_TIME_LO = 154; - static const uint32_t RX_CTRL_HALT = 155; - static const uint32_t RX_CTRL_MAXLEN = 156; - static const uint32_t RX_CTRL_CLEAR_CMDS = 157; - static const uint32_t RX_CTRL_OUTPUT_FORMAT= 158; - static const uint32_t MISC_OUTS = 160; - static const uint32_t DACSYNC = 161; - static const uint32_t SPI = 168; - static const uint32_t LEDS = 176; - static const uint32_t FP_GPIO = 184; - static const uint32_t GPIO = 192; - // NOTE: Upper 32 registers (224-255) are reserved for the output settings bus for use with - // device specific front end control - - // frontend control: needs rethinking TODO - //static const uint32_t TX_FRONT = BASE + 96; - //static const uint32_t RX_FRONT = BASE + 112; - //static const uint32_t READBACK = BASE + 127; - - static const uint32_t RB_TIME_NOW = 0; - static const uint32_t RB_TIME_PPS = 1; - static const uint32_t RB_TEST = 2; - static const uint32_t RB_CODEC_READBACK = 3; - static const uint32_t RB_RADIO_NUM = 4; - static const uint32_t RB_MISC_IO = 16; - static const uint32_t RB_SPI = 17; - static const uint32_t RB_LEDS = 18; - static const uint32_t RB_DB_GPIO = 19; - static const uint32_t RB_FP_GPIO = 20; - }; - - /*********************************************************************** - * Block control API calls - **********************************************************************/ - void _update_spp(int spp); - - inline size_t _get_num_radios() const { - return std::max(_num_rx_channels, _num_tx_channels); - } - - inline timed_wb_iface::sptr _get_ctrl(size_t radio_num) const { - return _perifs.at(radio_num).ctrl; - } - - inline bool _is_streamer_active(uhd::direction_t dir, const size_t chan) const { - switch (dir) { - case uhd::TX_DIRECTION: - return _tx_streamer_active.count(chan) ? _tx_streamer_active.at(chan) : false; - case uhd::RX_DIRECTION: - return _rx_streamer_active.count(chan) ? _rx_streamer_active.at(chan) : false; - case uhd::DX_DIRECTION: - return (_tx_streamer_active.count(chan) and _rx_streamer_active.count(chan)) ? - _rx_streamer_active.at(chan) and _tx_streamer_active.at(chan) : false; - default: - return false; - } - } - - virtual bool check_radio_config() { return true; }; - - //! There is always only one time core per radio - time_core_3000::sptr _time64; - - std::mutex _mutex; - - size_t _num_tx_channels; - size_t _num_rx_channels; - std::vector<bool> _continuous_streaming; - -private: - /************************************************************************ - * Peripherals - ***********************************************************************/ - //! Stores pointers to all streaming-related radio cores - struct radio_perifs_t - { - timed_wb_iface::sptr ctrl; - }; - std::map<size_t, radio_perifs_t> _perifs; - - - - // Cached values - double _tick_rate; - std::map<size_t, std::string> _tx_antenna; - std::map<size_t, std::string> _rx_antenna; - std::map<size_t, double> _tx_freq; - std::map<size_t, double> _rx_freq; - std::map<size_t, double> _tx_gain; - std::map<size_t, double> _rx_gain; - std::map<size_t, double> _tx_bandwidth; - std::map<size_t, double> _rx_bandwidth; - -}; /* class radio_ctrl_impl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/rx_stream_terminator.hpp b/host/lib/include/uhdlib/rfnoc/rx_stream_terminator.hpp deleted file mode 100644 index 2ac65bb25..000000000 --- a/host/lib/include/uhdlib/rfnoc/rx_stream_terminator.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_TERMINATOR_RECV_HPP -#define INCLUDED_LIBUHD_RFNOC_TERMINATOR_RECV_HPP - -#include <uhd/rfnoc/sink_node_ctrl.hpp> -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/tick_node_ctrl.hpp> -#include <uhd/rfnoc/scalar_node_ctrl.hpp> -#include <uhd/rfnoc/terminator_node_ctrl.hpp> -#include <uhd/rfnoc/block_ctrl_base.hpp> // For the block macros -#include <mutex> - -namespace uhd { - namespace rfnoc { - -/*! \brief Terminator node for Rx streamers. - * - * This node is only used by rx_streamers. It terminates the flow graph - * inside the streamer and does not have a counterpart on the FPGA. - */ -class rx_stream_terminator : - public sink_node_ctrl, - public rate_node_ctrl, - public tick_node_ctrl, - public scalar_node_ctrl, - public terminator_node_ctrl -{ -public: - UHD_RFNOC_BLOCK_OBJECT(rx_stream_terminator) - - static sptr make() - { - return sptr(new rx_stream_terminator); - } - - // If this is called, then by a send terminator at the other end - // of a flow graph. - double get_input_samp_rate(size_t) { return _samp_rate; }; - - // Same for the scaling factor - double get_input_scale_factor(size_t) { return scalar_node_ctrl::SCALE_UNDEFINED; }; - - std::string unique_id() const; - - void set_rx_streamer(bool active, const size_t port); - - void set_tx_streamer(bool active, const size_t port); - - virtual ~rx_stream_terminator(); - - void handle_overrun(boost::weak_ptr<uhd::rx_streamer>, const size_t); - -protected: - rx_stream_terminator(); - - virtual double _get_tick_rate() { return _tick_rate; }; - -private: - //! Every terminator has a unique index - const size_t _term_index; - static size_t _count; - - double _samp_rate; - double _tick_rate; - - std::mutex _overrun_handler_mutex; - -}; /* class rx_stream_terminator */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_TERMINATOR_RECV_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/tx_stream_terminator.hpp b/host/lib/include/uhdlib/rfnoc/tx_stream_terminator.hpp deleted file mode 100644 index e4d509dc5..000000000 --- a/host/lib/include/uhdlib/rfnoc/tx_stream_terminator.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_TERMINATOR_SEND_HPP -#define INCLUDED_LIBUHD_RFNOC_TERMINATOR_SEND_HPP - -#include <uhd/rfnoc/source_node_ctrl.hpp> -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/tick_node_ctrl.hpp> -#include <uhd/rfnoc/scalar_node_ctrl.hpp> -#include <uhd/rfnoc/terminator_node_ctrl.hpp> -#include <uhd/rfnoc/block_ctrl_base.hpp> // For the block macros -#include <uhd/utils/log.hpp> - -namespace uhd { - namespace rfnoc { - -/*! \brief Terminator node for Tx streamers. - * - * This node is only used by tx_streamers. It terminates the flow graph - * inside the streamer and does not have a counterpart on the FPGA. - */ -class tx_stream_terminator : - public source_node_ctrl, - public rate_node_ctrl, - public tick_node_ctrl, - public scalar_node_ctrl, - public terminator_node_ctrl -{ -public: - UHD_RFNOC_BLOCK_OBJECT(tx_stream_terminator) - - static sptr make() - { - return sptr(new tx_stream_terminator); - } - - void issue_stream_cmd(const uhd::stream_cmd_t &, const size_t) - { - UHD_RFNOC_BLOCK_TRACE() << "tx_stream_terminator::issue_stream_cmd()" ; - } - - // If this is called, then by a send terminator at the other end - // of a flow graph. - double get_output_samp_rate(size_t) { return _samp_rate; }; - - // Same for the scaling factor - double get_output_scale_factor(size_t) { return scalar_node_ctrl::SCALE_UNDEFINED; }; - - std::string unique_id() const; - - void set_rx_streamer(bool active, const size_t port); - - void set_tx_streamer(bool active, const size_t port); - - virtual ~tx_stream_terminator(); - -protected: - tx_stream_terminator(); - - virtual double _get_tick_rate() { return _tick_rate; }; - -private: - //! Every terminator has a unique index - const size_t _term_index; - static size_t _count; - - double _samp_rate; - double _tick_rate; - -}; /* class tx_stream_terminator */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_TERMINATOR_SEND_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/utils.hpp b/host/lib/include/uhdlib/rfnoc/utils.hpp deleted file mode 100644 index 7c3c1bb5f..000000000 --- a/host/lib/include/uhdlib/rfnoc/utils.hpp +++ /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 -// - -#ifndef INCLUDED_LIBUHD_RFNOC_UTILS_HPP -#define INCLUDED_LIBUHD_RFNOC_UTILS_HPP - -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <boost/lexical_cast.hpp> -#include <set> - -namespace uhd { namespace rfnoc { namespace utils { - - /*! If \p suggested_port equals ANY_PORT, return the first available - * port number on \p nodes. Otherwise, return \p suggested_port. - * - * If \p allowed_ports is given, another condition is that the port - * number must be listed in here. - * If \p allowed_ports is not specified or empty, the assumption is - * that all ports are valid. - * - * On failure, ANY_PORT is returned. - */ - static size_t node_map_find_first_free( - node_ctrl_base::node_map_t nodes, - const size_t suggested_port, - const std::set<size_t> allowed_ports=std::set<size_t>() - ) { - size_t port = suggested_port; - if (port == ANY_PORT) { - if (allowed_ports.empty()) { - port = 0; - while (nodes.count(port) and (port != ANY_PORT)) { - port++; - } - } else { - for(const size_t allowed_port: allowed_ports) { - if (not nodes.count(port)) { - return allowed_port; - } - return ANY_PORT; - } - } - } else { - if (not (allowed_ports.empty() or allowed_ports.count(port))) { - return ANY_PORT; - } - } - return port; - } - - template <typename T> - static std::set<T> str_list_to_set(const std::vector<std::string> &list) { - std::set<T> return_set; - for(const std::string &S: list) { - return_set.insert(boost::lexical_cast<T>(S)); - } - return return_set; - } - -}}}; /* namespace uhd::rfnoc::utils */ - -#endif /* INCLUDED_LIBUHD_RFNOC_UTILS_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp b/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp deleted file mode 100644 index 1ed8cf69b..000000000 --- a/host/lib/include/uhdlib/rfnoc/wb_iface_adapter.hpp +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_RFNOC_WB_IFACE_ADAPTER_HPP -#define INCLUDED_RFNOC_WB_IFACE_ADAPTER_HPP - -#include <uhd/config.hpp> -#include "ctrl_iface.hpp" -#include <uhd/types/wb_iface.hpp> -#include <boost/function.hpp> - -namespace uhd { - namespace rfnoc { - -/*! wb_iface control into RFNoC block registers. - * - * This is specifically for mimicking a wb_iface that talks to an RFNoC block. - * It assumes an underlying ctrl_iface is talking to an RFNoC block. - */ -class UHD_API wb_iface_adapter : public uhd::timed_wb_iface -{ -public: - typedef boost::function<double()> gettickrate_type; - typedef boost::function<uhd::time_spec_t()> gettime_type; - typedef boost::function<void(const uhd::time_spec_t &)> settime_type; - - wb_iface_adapter( - ctrl_iface::sptr iface, - const gettickrate_type &, - const settime_type &, - const gettime_type & - ); - - virtual ~wb_iface_adapter(void) {} - - void poke32(const wb_addr_type addr, const uint32_t data); - uint32_t peek32(const wb_addr_type addr); - uint64_t peek64(const wb_addr_type addr); - time_spec_t get_time() { return gettime_functor(); } - void set_time(const uhd::time_spec_t& t) { settime_functor(t); } - -private: - ctrl_iface::sptr _iface; - const gettickrate_type gettickrate_functor; - const settime_type settime_functor; - const gettime_type gettime_functor; - - inline uint64_t get_timestamp() { return gettime_functor().to_ticks(gettickrate_functor()); } -}; - -}} // namespace uhd::rfnoc - -#endif /* INCLUDED_RFNOC_WB_IFACE_ADAPTER_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/xports.hpp b/host/lib/include/uhdlib/rfnoc/xports.hpp deleted file mode 100644 index 6b30fe5b1..000000000 --- a/host/lib/include/uhdlib/rfnoc/xports.hpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright 2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_XPORTS_HPP -#define INCLUDED_LIBUHD_XPORTS_HPP - -#include <uhd/types/sid.hpp> -#include <uhd/types/endianness.hpp> -#include <uhd/transport/zero_copy.hpp> - -namespace uhd { - - /*! Holds all necessary items for a bidirectional link - */ - struct both_xports_t - { - both_xports_t(): recv_buff_size(0), send_buff_size(0), lossless(false) - {} - uhd::transport::zero_copy_if::sptr recv; - uhd::transport::zero_copy_if::sptr send; - size_t recv_buff_size; - size_t send_buff_size; - uhd::sid_t send_sid; - uhd::sid_t recv_sid; - uhd::endianness_t endianness; - bool lossless; - }; - -}; - -#endif /* INCLUDED_LIBUHD_XPORTS_HPP */ 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"); diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index e899cfba0..d21644f01 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -115,7 +115,6 @@ LIBUHD_PYTHON_GEN_SOURCE( LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy_flow_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy_recv_offload.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tcp_zero_copy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp @@ -130,7 +129,6 @@ LIBUHD_APPEND_SOURCES( if(ENABLE_X300) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/nirio_link.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp ) endif(ENABLE_X300) @@ -150,11 +148,3 @@ if(ENABLE_DPDK) ) endif(ENABLE_DPDK) -# Verbose Debug output for send/recv -set( UHD_TXRX_DEBUG_PRINTS OFF CACHE BOOL "Use verbose debug output for send/recv" ) -option( UHD_TXRX_DEBUG_PRINTS "Use verbose debug output for send/recv" "" ) -if(UHD_TXRX_DEBUG_PRINTS) - message(STATUS "Using verbose debug output for send/recv") - add_definitions(-DUHD_TXRX_DEBUG_PRINTS) -endif() - diff --git a/host/lib/transport/buffer_pool.cpp b/host/lib/transport/buffer_pool.cpp index c481b9d02..0dd4a8d7f 100644 --- a/host/lib/transport/buffer_pool.cpp +++ b/host/lib/transport/buffer_pool.cpp @@ -12,15 +12,6 @@ using namespace uhd::transport; -#ifdef UHD_TXRX_DEBUG_PRINTS -/* - * This is the implementation for the static variable 's_buffer_count' - * located in uhd/transport/zero_copy.hpp. - * It is used in the managed_buffer class. - */ -boost::detail::atomic_count managed_buffer::s_buffer_count(0); -#endif // UHD_TXRX_DEBUG_PRINTS - //! pad the byte count to a multiple of alignment static size_t pad_to_boundary(const size_t bytes, const size_t alignment) { diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index f5693b198..9a1b74fb2 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -21,12 +21,6 @@ #include <boost/thread/mutex.hpp> #include <list> -#ifdef UHD_TXRX_DEBUG_PRINTS -# include <boost/format.hpp> -# include <fstream> -# include <vector> -#endif - using namespace uhd; using namespace uhd::transport; diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 85d00bad1..950da4c8a 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -18,7 +18,6 @@ #include <uhd/utils/byteswap.hpp> #include <uhd/utils/log.hpp> #include <uhd/utils/tasks.hpp> -#include <uhdlib/rfnoc/rx_stream_terminator.hpp> #include <boost/dynamic_bitset.hpp> #include <boost/format.hpp> #include <boost/function.hpp> @@ -26,13 +25,6 @@ #include <iostream> #include <vector> -// Included for debugging -#ifdef UHD_TXRX_DEBUG_PRINTS -# include "boost/date_time/posix_time/posix_time.hpp" -# include <boost/format.hpp> -# include <boost/thread/thread.hpp> -#endif - namespace uhd { namespace transport { namespace sph { UHD_INLINE uint32_t get_context_code( @@ -250,10 +242,6 @@ public: recv_one_packet(buffs, nsamps_per_buff, metadata, timeout); if (one_packet or metadata.end_of_burst) { -#ifdef UHD_TXRX_DEBUG_PRINTS - dbg_gather_data( - nsamps_per_buff, accum_num_samps, metadata, timeout, one_packet); -#endif return accum_num_samps; } @@ -285,9 +273,6 @@ public: break; } } -#ifdef UHD_TXRX_DEBUG_PRINTS - dbg_gather_data(nsamps_per_buff, accum_num_samps, metadata, timeout, one_packet); -#endif return accum_num_samps; } @@ -813,84 +798,6 @@ private: size_t _convert_buffer_offset_bytes; size_t _convert_bytes_to_copy; - /* - * This last section is only for debugging purposes. - * It causes a lot of prints to stderr which can be piped to a file. - * Gathered data can be used to post process it with external tools. - */ -#ifdef UHD_TXRX_DEBUG_PRINTS - struct dbg_recv_stat_t - { - dbg_recv_stat_t(long wc, - size_t nspb, - size_t nsr, - uhd::rx_metadata_t md, - double to, - bool op, - double rate) - : wallclock(wc) - , nsamps_per_buff(nspb) - , nsamps_recv(nsr) - , metadata(md) - , timeout(to) - , one_packet(op) - , samp_rate(rate) - { - } - long wallclock; - size_t nsamps_per_buff; - size_t nsamps_recv; - uhd::rx_metadata_t metadata; - double timeout; - bool one_packet; - double samp_rate; - // Create a formatted print line for all the info gathered in this struct. - std::string print_line() - { - boost::format fmt("recv,%ld,%f,%i,%i,%s,%i,%s,%s,%s,%i,%s,%ld"); - fmt % wallclock; - fmt % timeout % (int)nsamps_per_buff % (int)nsamps_recv; - fmt % (one_packet ? "true" : "false"); - fmt % metadata.error_code; - fmt % (metadata.start_of_burst ? "true" : "false") - % (metadata.end_of_burst ? "true" : "false"); - fmt % (metadata.more_fragments ? "true" : "false") - % (int)metadata.fragment_offset; - fmt % (metadata.has_time_spec ? "true" : "false") - % metadata.time_spec.to_ticks(samp_rate); - return fmt.str(); - } - }; - - void dbg_gather_data(const size_t nsamps_per_buff, - const size_t nsamps_recv, - uhd::rx_metadata_t& metadata, - const double timeout, - const bool one_packet, - bool dbg_print_directly = true) - { - // Initialize a struct with all available data. It can return a formatted string - // with all infos if wanted. - dbg_recv_stat_t data(boost::get_system_time().time_of_day().total_microseconds(), - nsamps_per_buff, - nsamps_recv, - metadata, - timeout, - one_packet, - _samp_rate); - if (dbg_print_directly) { - dbg_print_err(data.print_line()); - } - } - - - void dbg_print_err(std::string msg) - { - std::string dbg_prefix("super_recv_packet_handler,"); - msg = dbg_prefix + msg; - fprintf(stderr, "%s\n", msg.c_str()); - } -#endif }; class recv_packet_streamer : public recv_packet_handler, public rx_streamer diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp index af6ecaa5e..cd707cb89 100644 --- a/host/lib/transport/super_send_packet_handler.hpp +++ b/host/lib/transport/super_send_packet_handler.hpp @@ -18,22 +18,12 @@ #include <uhd/utils/byteswap.hpp> #include <uhd/utils/tasks.hpp> #include <uhd/utils/thread.hpp> -#include <uhdlib/rfnoc/tx_stream_terminator.hpp> #include <boost/function.hpp> #include <chrono> #include <iostream> #include <thread> #include <vector> -#ifdef UHD_TXRX_DEBUG_PRINTS -// Included for debugging -# include "boost/date_time/posix_time/posix_time.hpp" -# include <boost/format.hpp> -# include <boost/thread/thread.hpp> -# include <fstream> -# include <map> -#endif - namespace uhd { namespace transport { namespace sph { /*********************************************************************** @@ -240,9 +230,6 @@ public: size_t nsamps_sent = send_one_packet(buffs, nsamps_per_buff, if_packet_info, timeout); -#ifdef UHD_TXRX_DEBUG_PRINTS - dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); -#endif return nsamps_sent; } size_t total_num_samps_sent = 0; @@ -281,10 +268,6 @@ public: if_packet_info, timeout, total_num_samps_sent * _bytes_per_cpu_item); -#ifdef UHD_TXRX_DEBUG_PRINTS - dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); - -#endif return nsamps_sent; } @@ -314,67 +297,6 @@ private: bool _cached_metadata; uhd::tx_metadata_t _metadata_cache; -#ifdef UHD_TXRX_DEBUG_PRINTS - struct dbg_send_stat_t - { - dbg_send_stat_t(long wc, - size_t nspb, - size_t nss, - uhd::tx_metadata_t md, - double to, - double rate) - : wallclock(wc) - , nsamps_per_buff(nspb) - , nsamps_sent(nss) - , metadata(md) - , timeout(to) - , samp_rate(rate) - { - } - long wallclock; - size_t nsamps_per_buff; - size_t nsamps_sent; - uhd::tx_metadata_t metadata; - double timeout; - double samp_rate; - // Create a formatted print line for all the info gathered in this struct. - std::string print_line() - { - boost::format fmt("send,%ld,%f,%i,%i,%s,%s,%s,%ld"); - fmt % wallclock; - fmt % timeout % (int)nsamps_per_buff % (int)nsamps_sent; - fmt % (metadata.start_of_burst ? "true" : "false") - % (metadata.end_of_burst ? "true" : "false"); - fmt % (metadata.has_time_spec ? "true" : "false") - % metadata.time_spec.to_ticks(samp_rate); - return fmt.str(); - } - }; - - void dbg_print_send(size_t nsamps_per_buff, - size_t nsamps_sent, - const uhd::tx_metadata_t& metadata, - const double timeout, - bool dbg_print_directly = true) - { - dbg_send_stat_t data(boost::get_system_time().time_of_day().total_microseconds(), - nsamps_per_buff, - nsamps_sent, - metadata, - timeout, - _samp_rate); - if (dbg_print_directly) { - dbg_print_err(data.print_line()); - } - } - void dbg_print_err(std::string msg) - { - msg = "super_send_packet_handler," + msg; - fprintf(stderr, "%s\n", msg.c_str()); - } - - -#endif /******************************************************************* * Send a single packet: diff --git a/host/lib/transport/xport_benchmarker.cpp b/host/lib/transport/xport_benchmarker.cpp deleted file mode 100644 index 67582ff2c..000000000 --- a/host/lib/transport/xport_benchmarker.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// Copyright 2010-2013 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "xport_benchmarker.hpp" -#include <chrono> -#include <thread> - -namespace uhd { namespace transport { - -const device_addr_t& xport_benchmarker::benchmark_throughput_chdr( - zero_copy_if::sptr tx_transport, - zero_copy_if::sptr rx_transport, - uint32_t sid, - bool big_endian, - uint32_t duration_ms) -{ - vrt::if_packet_info_t pkt_info; - _initialize_chdr(tx_transport, rx_transport, sid, pkt_info); - _reset_counters(); - boost::posix_time::ptime start_time(boost::posix_time::microsec_clock::local_time()); - - _tx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_tx, - this, - tx_transport.get(), - &pkt_info, - big_endian))); - _rx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_rx, - this, - rx_transport.get(), - &pkt_info, - big_endian))); - - std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms)); - - _tx_thread->interrupt(); - _rx_thread->interrupt(); - _tx_thread->join(); - _rx_thread->join(); - - boost::posix_time::ptime stop_time(boost::posix_time::microsec_clock::local_time()); - double duration_s = ((double)(stop_time - start_time).total_microseconds()) / 1e6; - - uint64_t tx_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t) * _num_tx_packets; - uint64_t rx_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t) * _num_rx_packets; - double tx_rate = (((double)tx_bytes) / duration_s); - double rx_rate = (((double)rx_bytes) / duration_s); - - _results["TX-Bytes"] = (boost::format("%.2fMB") % (tx_bytes / (1024 * 1024))).str(); - _results["RX-Bytes"] = (boost::format("%.2fMB") % (rx_bytes / (1024 * 1024))).str(); - _results["TX-Throughput"] = - (boost::format("%.2fMB/s") % (tx_rate / (1024 * 1024))).str(); - _results["RX-Throughput"] = - (boost::format("%.2fMB/s") % (rx_rate / (1024 * 1024))).str(); - _results["TX-Timeouts"] = std::to_string(_num_tx_timeouts); - _results["RX-Timeouts"] = std::to_string(_num_rx_timeouts); - _results["Data-Errors"] = std::to_string(_num_data_errors); - - return _results; -} - -void xport_benchmarker::_stream_tx( - zero_copy_if* transport, vrt::if_packet_info_t* pkt_info, bool big_endian) -{ - while (not boost::this_thread::interruption_requested()) { - managed_send_buffer::sptr buff = transport->get_send_buff(_tx_timeout); - if (buff) { - uint32_t* packet_buff = buff->cast<uint32_t*>(); - // Populate packet - if (big_endian) { - vrt::if_hdr_pack_be(packet_buff, *pkt_info); - } else { - vrt::if_hdr_pack_le(packet_buff, *pkt_info); - } - // send the buffer over the interface - buff->commit(sizeof(uint32_t) * (pkt_info->num_packet_words32)); - _num_tx_packets++; - } else { - _num_tx_timeouts++; - } - } -} - -void xport_benchmarker::_stream_rx( - zero_copy_if* transport, const vrt::if_packet_info_t* exp_pkt_info, bool big_endian) -{ - while (not boost::this_thread::interruption_requested()) { - managed_recv_buffer::sptr buff = transport->get_recv_buff(_rx_timeout); - if (buff) { - // Extract packet info - vrt::if_packet_info_t pkt_info; - pkt_info.link_type = exp_pkt_info->link_type; - pkt_info.num_packet_words32 = buff->size() / sizeof(uint32_t); - const uint32_t* packet_buff = buff->cast<const uint32_t*>(); - - _num_rx_packets++; - - // unpacking can fail - try { - if (big_endian) { - vrt::if_hdr_unpack_be(packet_buff, pkt_info); - } else { - vrt::if_hdr_unpack_le(packet_buff, pkt_info); - } - - if (exp_pkt_info->packet_type != pkt_info.packet_type - || exp_pkt_info->num_payload_bytes != pkt_info.num_payload_bytes) { - _num_data_errors++; - } - } catch (const std::exception& ex) { - _num_data_errors++; - } - } else { - _num_rx_timeouts++; - } - } -} - -void xport_benchmarker::_reset_counters(void) -{ - _num_tx_packets = 0; - _num_rx_packets = 0; - _num_tx_timeouts = 0; - _num_rx_timeouts = 0; - _num_data_errors = 0; -} - -void xport_benchmarker::_initialize_chdr(zero_copy_if::sptr tx_transport, - zero_copy_if::sptr rx_transport, - uint32_t sid, - vrt::if_packet_info_t& pkt_info) -{ - _tx_timeout = 0.5; - _rx_timeout = 0.5; - - size_t frame_size = std::min( - tx_transport->get_send_frame_size(), rx_transport->get_recv_frame_size()); - - pkt_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - pkt_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; - pkt_info.num_packet_words32 = (frame_size / sizeof(uint32_t)); - pkt_info.num_payload_words32 = pkt_info.num_packet_words32 - 2; - pkt_info.num_payload_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t); - pkt_info.packet_count = 0; - pkt_info.sob = false; - pkt_info.eob = false; - pkt_info.sid = sid; - pkt_info.has_sid = true; - pkt_info.has_cid = false; - pkt_info.has_tsi = false; - pkt_info.has_tsf = false; - pkt_info.has_tlr = false; -} - -}} // namespace uhd::transport diff --git a/host/lib/transport/xport_benchmarker.hpp b/host/lib/transport/xport_benchmarker.hpp deleted file mode 100644 index 3843540e0..000000000 --- a/host/lib/transport/xport_benchmarker.hpp +++ /dev/null @@ -1,63 +0,0 @@ -// -// Copyright 2010-2013 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP -#define INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP - -#include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/device_addr.hpp> -#include <uhd/utils/log.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/thread/thread.hpp> - -namespace uhd { namespace transport { - -// Test class to benchmark a low-level transport object with a VITA/C-VITA data stream -class xport_benchmarker : uhd::noncopyable -{ -public: - const device_addr_t& benchmark_throughput_chdr(zero_copy_if::sptr tx_transport, - zero_copy_if::sptr rx_transport, - uint32_t sid, - bool big_endian, - uint32_t duration_ms); - -private: - void _stream_tx( - zero_copy_if* transport, vrt::if_packet_info_t* pkt_info, bool big_endian); - - void _stream_rx(zero_copy_if* transport, - const vrt::if_packet_info_t* exp_pkt_info, - bool big_endian); - - void _initialize_chdr(zero_copy_if::sptr tx_transport, - zero_copy_if::sptr rx_transport, - uint32_t sid, - vrt::if_packet_info_t& pkt_info); - - void _reset_counters(void); - - boost::shared_ptr<boost::thread> _tx_thread; - boost::shared_ptr<boost::thread> _rx_thread; - - uint64_t _num_tx_packets; - uint64_t _num_rx_packets; - uint64_t _num_tx_timeouts; - uint64_t _num_rx_timeouts; - uint64_t _num_data_errors; - - double _tx_timeout; - double _rx_timeout; - - device_addr_t _results; -}; - - -}} // namespace uhd::transport - -#endif /* INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP */ diff --git a/host/lib/transport/zero_copy_recv_offload.cpp b/host/lib/transport/zero_copy_recv_offload.cpp deleted file mode 100644 index 7329dbdf3..000000000 --- a/host/lib/transport/zero_copy_recv_offload.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// Copyright 2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include <uhd/transport/bounded_buffer.hpp> -#include <uhd/transport/buffer_pool.hpp> -#include <uhd/transport/zero_copy_recv_offload.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhd/utils/thread.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <boost/make_shared.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/thread/thread.hpp> - -using namespace uhd; -using namespace uhd::transport; - -typedef bounded_buffer<managed_recv_buffer::sptr> bounded_buffer_t; - -/*********************************************************************** - * Zero copy offload transport: - * An intermediate transport that utilizes threading to free - * the main thread from any receive work. - **********************************************************************/ -class zero_copy_recv_offload_impl : public zero_copy_recv_offload -{ -public: - typedef boost::shared_ptr<zero_copy_recv_offload_impl> sptr; - - zero_copy_recv_offload_impl(zero_copy_if::sptr transport, const double timeout) - : _transport(transport) - , _timeout(timeout) - , _inbox(transport->get_num_recv_frames()) - , _recv_done(false) - { - UHD_LOGGER_TRACE("XPORT") << "Created threaded transport"; - - // Create the receive and send threads to offload - // the system calls onto other threads - _recv_thread = - boost::thread(boost::bind(&zero_copy_recv_offload_impl::enqueue_recv, this)); - set_thread_name(&_recv_thread, "zero_copy_recv"); - } - - // Receive thread flags - void set_recv_done() - { - boost::lock_guard<boost::mutex> guard(_recv_mutex); - _recv_done = true; - } - - bool is_recv_done() - { - boost::lock_guard<boost::mutex> guard(_recv_mutex); - return _recv_done; - } - - ~zero_copy_recv_offload_impl() - { - // Signal the threads we're finished - set_recv_done(); - - // Wait for them to join - UHD_SAFE_CALL(_recv_thread.join();) - } - - // The receive thread function is responsible for - // pulling pointers to managed receiver buffers quickly - void enqueue_recv() - { - while (not is_recv_done()) { - managed_recv_buffer::sptr buff = _transport->get_recv_buff(_timeout); - if (not buff) - continue; - _inbox.push_with_timed_wait(buff, _timeout); - } - } - - /******************************************************************* - * Receive implementation: - * Pop the receive buffer pointer from the underlying transport - ******************************************************************/ - managed_recv_buffer::sptr get_recv_buff(double timeout) - { - managed_recv_buffer::sptr ptr; - _inbox.pop_with_timed_wait(ptr, timeout); - return ptr; - } - - size_t get_num_recv_frames() const - { - return _transport->get_num_recv_frames(); - } - - size_t get_recv_frame_size() const - { - return _transport->get_recv_frame_size(); - } - - /******************************************************************* - * Send implementation: - * Pass the send buffer pointer from the underlying transport - ******************************************************************/ - managed_send_buffer::sptr get_send_buff(double timeout) - { - return _transport->get_send_buff(timeout); - } - - size_t get_num_send_frames() const - { - return _transport->get_num_send_frames(); - } - - size_t get_send_frame_size() const - { - return _transport->get_send_frame_size(); - } - -private: - // The linked transport - zero_copy_if::sptr _transport; - - const double _timeout; - - // Shared buffers - bounded_buffer_t _inbox; - - // Threading - bool _recv_done; - boost::thread _recv_thread; - boost::mutex _recv_mutex; -}; - -zero_copy_recv_offload::sptr zero_copy_recv_offload::make( - zero_copy_if::sptr transport, const double timeout) -{ - zero_copy_recv_offload_impl::sptr zero_copy_recv_offload( - new zero_copy_recv_offload_impl(transport, timeout)); - - return zero_copy_recv_offload; -} diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index 3265c654f..f731adf20 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -1,6 +1,7 @@ # # Copyright 2011-2013,2015 Ettus Research LLC # Copyright 2018 Ettus Research, a National Instruments Company +# Copyright 2019 Ettus Research, a National Instruments Brand # # SPDX-License-Identifier: GPL-3.0-or-later # @@ -15,7 +16,6 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/sid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp deleted file mode 100644 index 1f7aa0227..000000000 --- a/host/lib/types/sid.cpp +++ /dev/null @@ -1,143 +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/types/sid.hpp> -#include <uhd/exception.hpp> -#include <uhd/utils/cast.hpp> -#include <boost/format.hpp> -#include <boost/regex.hpp> -#include <boost/lexical_cast.hpp> - -using namespace uhd; - -sid_t::sid_t() - : _sid(0x0000), _set(false) -{ -} - -sid_t::sid_t(uint32_t sid) - : _sid(sid), _set(true) -{ -} - -sid_t::sid_t(uint8_t src_addr, uint8_t src_ep, uint8_t dst_addr, uint8_t dst_ep) - : _sid(0x0000), _set(true) -{ - set_src_addr(src_addr); - set_src_endpoint(src_ep); - set_dst_addr(dst_addr); - set_dst_endpoint(dst_ep); -} - -sid_t::sid_t(const std::string &sid_str) - : _sid(0x0000), _set(false) -{ - set_from_str(sid_str); -} - -std::string sid_t::to_pp_string() const -{ - if (not _set) { - return "x.x>x.x"; - } - return str(boost::format("%d.%d>%d.%d") - % get_src_addr() - % get_src_endpoint() - % get_dst_addr() - % get_dst_endpoint() - ); -} - -std::string sid_t::to_pp_string_hex() const -{ - if (not _set) { - return "xx:xx>xx:xx"; - } - return str(boost::format("%02x:%02x>%02x:%02x") - % get_src_addr() - % get_src_endpoint() - % get_dst_addr() - % get_dst_endpoint() - ); -} - - -void sid_t::set_sid(uint32_t new_sid) -{ - _set = true; - _sid = new_sid; -} - -void sid_t::set_from_str(const std::string &sid_str) -{ - const std::string dec_regex = "(\\d{1,3})\\.(\\d{1,3})[.:/><](\\d{1,3})\\.(\\d{1,3})"; - const std::string hex_regex = "([[:xdigit:]]{2}):([[:xdigit:]]{2})[.:/><]([[:xdigit:]]{2}):([[:xdigit:]]{2})"; - - boost::cmatch matches; - if (boost::regex_match(sid_str.c_str(), matches, boost::regex(dec_regex))) { - set_src_addr(boost::lexical_cast<size_t>(matches[1])); - set_src_endpoint(boost::lexical_cast<size_t>(matches[2])); - set_dst_addr(boost::lexical_cast<size_t>(matches[3])); - set_dst_endpoint(boost::lexical_cast<size_t>(matches[4])); - return; - } - - if (boost::regex_match(sid_str.c_str(), matches, boost::regex(hex_regex))) { - set_src_addr(uhd::cast::hexstr_cast<size_t>(matches[1])); - set_src_endpoint(uhd::cast::hexstr_cast<size_t>(matches[2])); - set_dst_addr(uhd::cast::hexstr_cast<size_t>(matches[3])); - set_dst_endpoint(uhd::cast::hexstr_cast<size_t>(matches[4])); - return; - } - - throw uhd::value_error(str(boost::format("Invalid SID representation: %s") % sid_str)); -} - -void sid_t::set_src(uint32_t new_addr) { - set_sid((_sid & 0x0000FFFF) | ((new_addr & 0xFFFF) << 16)); -} - -void sid_t::set_dst(uint32_t new_addr) { - set_sid((_sid & 0xFFFF0000) | (new_addr & 0xFFFF)); -} - -void sid_t::set_src_addr(uint32_t new_addr) { - set_sid((_sid & 0x00FFFFFF) | ((new_addr & 0xFF) << 24)); -} - -void sid_t::set_src_endpoint(uint32_t new_addr) { - set_sid((_sid & 0xFF00FFFF) | ((new_addr & 0xFF) << 16)); -} - -void sid_t::set_dst_addr(uint32_t new_addr) { - set_sid((_sid & 0xFFFF00FF) | ((new_addr & 0xFF) << 8)); -} - -void sid_t::set_dst_endpoint(uint32_t new_addr) { - set_sid((_sid & 0xFFFFFF00) | ((new_addr & 0xFF) << 0)); -} - -void sid_t::set_dst_xbarport(uint32_t new_xbarport) -{ - set_sid((_sid & 0xFFFFFF0F) | ((new_xbarport & 0xF) << 4)); -} - -void sid_t::set_dst_blockport(uint32_t new_blockport) -{ - set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0)); -} - -sid_t sid_t::reversed() const -{ - return sid_t((get_dst() << 16) | get_src()); -} - -void sid_t::reverse() -{ - set_sid((get_dst() << 16) | get_src()); -} - diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 0b839a835..f15324608 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -35,7 +35,6 @@ endif(ENABLE_C_API) INCLUDE_SUBDIRECTORY(cores) INCLUDE_SUBDIRECTORY(dboard) INCLUDE_SUBDIRECTORY(common) -INCLUDE_SUBDIRECTORY(device3) INCLUDE_SUBDIRECTORY(mpmd) INCLUDE_SUBDIRECTORY(usrp1) INCLUDE_SUBDIRECTORY(usrp2) diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 8ee79103f..2dd4e7e26 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -49,6 +49,3 @@ endif(ENABLE_N300) if(ENABLE_N320) INCLUDE_SUBDIRECTORY(rhodium) endif(ENABLE_N320) -if(ENABLE_MPMD AND ENABLE_EISCAT) - INCLUDE_SUBDIRECTORY(eiscat) -endif(ENABLE_MPMD AND ENABLE_EISCAT) diff --git a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp index 29381a53c..bc9ed9169 100644 --- a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_impl.cpp @@ -7,7 +7,6 @@ #include "e3xx_radio_control_impl.hpp" #include "e3xx_constants.hpp" -#include <uhd/transport/chdr.hpp> #include <uhd/types/direction.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/utils/algorithm.hpp> diff --git a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp index f97feeb68..6ecf4ff2a 100644 --- a/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_control_init.cpp @@ -6,7 +6,6 @@ #include "e3xx_constants.hpp" #include "e3xx_radio_control_impl.hpp" -#include <uhd/transport/chdr.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/log.hpp> #include <uhdlib/rfnoc/reg_iface_adapter.hpp> diff --git a/host/lib/usrp/dboard/eiscat/CMakeLists.txt b/host/lib/usrp/dboard/eiscat/CMakeLists.txt deleted file mode 100644 index 076d26916..000000000 --- a/host/lib/usrp/dboard/eiscat/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -# -# Copyright 2017 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -# This file is conditionally included if ENABLE_MPMD and ENABLE_EISCAT are -# set to true. - -list(APPEND EISCAT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/eiscat_radio_ctrl_impl.cpp -) -LIBUHD_APPEND_SOURCES(${EISCAT_SOURCES}) - diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp deleted file mode 100644 index 73851656b..000000000 --- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.cpp +++ /dev/null @@ -1,950 +0,0 @@ -// -// Copyright 2017 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "eiscat_radio_ctrl_impl.hpp" - -#include <uhd/utils/log.hpp> -#include <uhd/utils/math.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/types/ranges.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/make_shared.hpp> -#include <boost/date_time/posix_time/posix_time_io.hpp> -#include <boost/format.hpp> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::rfnoc; - -namespace { - const size_t SR_ANTENNA_GAIN_BASE = 204; - const size_t SR_ANTENNA_SELECT_BASE = 192; // Note: On other dboards, 192 is DB_GPIO address space - const size_t RB_CHOOSE_BEAMS = 11; - - const double EISCAT_TICK_RATE = 208e6; // Hz - const double EISCAT_RADIO_RATE = 104e6; // Hz - const double EISCAT_CENTER_FREQ = 208e6; // Hz - const double EISCAT_DEFAULT_NULL_GAIN = 0.0; // dB. This is not the digital antenna gain, this a fake stub value. - const double EISCAT_DEFAULT_BANDWIDTH = 104e6; // Hz - const char* EISCAT_DEFAULT_ANTENNA = "BF"; - const size_t EISCAT_NUM_ANTENNAS = 16; - const size_t EISCAT_NUM_BEAMS = 10; - const size_t EISCAT_NUM_PORTS = 5; - const size_t EISCAT_MAX_GAIN_RANGE = 18; // Bits, *signed*. - const size_t EISCAT_UNIT_GAIN_RANGE = 14; // Bits, *signed*. - const int32_t EISCAT_MAX_GAIN = (1<<(EISCAT_MAX_GAIN_RANGE-1))-1; - const int32_t EISCAT_UNIT_GAIN = (1<<(EISCAT_UNIT_GAIN_RANGE-1))-1; - const int32_t EISCAT_MIN_GAIN = -(1<<(EISCAT_MAX_GAIN_RANGE-1)); - const double EISCAT_DEFAULT_NORM_GAIN = 1.0; // Normalized. This is the actual digital gain value. - const size_t EISCAT_BITS_PER_TAP = 18; - const eiscat_radio_ctrl_impl::fir_tap_t EISCAT_MAX_TAP_VALUE = (1<<(EISCAT_BITS_PER_TAP-1))-1; - const eiscat_radio_ctrl_impl::fir_tap_t EISCAT_MIN_TAP_VALUE = -(1<<(EISCAT_BITS_PER_TAP-1)); - const size_t EISCAT_NUM_FIR_TAPS = 10; - const size_t EISCAT_NUM_FIR_SETS = 1024; // BRAM must be at least EISCAT_NUM_FIR_TAPS * EISCAT_NUM_FIR_SETS - const size_t EISCAT_FIR_INDEX_IMPULSE = 1002; - const size_t EISCAT_FIR_INDEX_ZEROS = 1003; - - const uint32_t EISCAT_CONTRIB_LOWER = 0<<0; - const uint32_t EISCAT_CONTRIB_UPPER = 1<<0; - const uint32_t EISCAT_SKIP_NEIGHBOURS = 1<<1; - const uint32_t EISCAT_BYPASS_MATRIX = 1<<2; - const uint32_t EISCAT_OUTPUT_COUNTER = 1<<3; -}; - - -UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(eiscat_radio_ctrl) -{ - UHD_LOG_TRACE("EISCAT", "eiscat_radio_ctrl_impl::ctor() "); - _num_ports = get_output_ports().size(); - UHD_LOG_TRACE("EISCAT", "Number of channels: " << _num_ports); - UHD_LOG_TRACE("EISCAT", - "Tick rate is " << EISCAT_TICK_RATE/1e6 << " MHz" - ); - - /**** Configure the radio_ctrl itself ***********************************/ - // This also sets the command tick rate: - radio_ctrl_impl::set_rate(EISCAT_TICK_RATE); - for (size_t chan = 0; chan < _num_ports; chan++) { - radio_ctrl_impl::set_rx_frequency(EISCAT_CENTER_FREQ, chan); - radio_ctrl_impl::set_rx_gain(EISCAT_DEFAULT_NULL_GAIN, chan); - radio_ctrl_impl::set_rx_antenna(EISCAT_DEFAULT_ANTENNA, chan); - radio_ctrl_impl::set_rx_bandwidth(EISCAT_DEFAULT_BANDWIDTH, chan); - // We might get tx async messages from upstream radios, we send them to the - // nevernever by default or they interfere with our streamers or ctrl_iface - // objects. The assumption is that FF:FF is never a valid SID. - this->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, 0xFFFF, chan); - } - - /**** Set up arg-based control API **************************************/ - // None of these properties are defined in the XML file. Some of them have - // non-Noc-Script-compatible types. - _tree->create<bool>(get_arg_path("sysref", 0) / "value") - .set(true) - .add_coerced_subscriber([this](bool){ - try { - this->send_sysref(); - } catch (const uhd::exception &ex) { - UHD_LOGGER_WARNING("EISCAT") - << "Failed to send SYSREF: " << ex.what(); - throw uhd::runtime_error(str( - boost::format("Failed to send SYSREF: %s") - % ex.what() - )); - } - }) - .set_publisher([](){ return true; }) - ; - _tree->create<bool>(get_arg_path("assert_adcs_deframers", 0) / "value") - .set(true) - .set_publisher([this](){ return this->assert_adcs_deframers(); }) - ; - _tree->create<bool>(get_arg_path("assert_deframer_status", 0) / "value") - .set(true) - .set_publisher([this](){ return this->assert_adcs_deframers(); }) - ; - _tree->create<time_spec_t>(get_arg_path("fir_ctrl_time", 0) / "value") - .add_coerced_subscriber([this](time_spec_t switch_time){ - this->set_fir_ctrl_time(switch_time); - }) - .set(time_spec_t(0.0)) - ; - for (size_t beam = 0; beam < EISCAT_NUM_BEAMS; beam++) { - for (size_t ant = 0; ant < EISCAT_NUM_ANTENNAS; ant++) { - const size_t fir_index = beam * EISCAT_NUM_ANTENNAS + ant; - // These are not in the XML file - _tree->create<int>(get_arg_path("fir_select", fir_index) / "value") - .add_coerced_subscriber([beam, ant, this](const size_t ram_idx){ - UHD_ASSERT_THROW(ram_idx < EISCAT_NUM_FIR_SETS); - this->select_filter( - beam, - ant, - ram_idx, - this->get_arg<time_spec_t>("fir_ctrl_time", 0), - false - ); - }) - ; - } - } - for (size_t fir_set = 0; fir_set < EISCAT_NUM_FIR_SETS; fir_set++) { - _tree->create<std::vector<fir_tap_t>>( - get_arg_path("fir_taps", fir_set) / "value") - .add_coerced_subscriber( - [this, fir_set](const std::vector<fir_tap_t> &taps){ - this->write_fir_taps(fir_set, taps); - } - ) - ; - } - - - /**** Add subscribers for our special properties ************************/ - // The difference between this block and the previous that these *are* - // defined in the XML file, and can have defaults set there. - _tree->access<int>(get_arg_path("choose_beams", 0) / "value") - .add_coerced_subscriber([this](int choose_beams){ - this->set_beam_selection(choose_beams); - }) - .update() - ; - _tree->access<bool>(get_arg_path("enable_firs", 0) / "value") - .add_coerced_subscriber([this](int enable){ - this->enable_firs(bool(enable)); - }) - .update() - ; - _tree->access<bool>(get_arg_path("enable_counter", 0) / "value") - .add_coerced_subscriber([this](int enable){ - this->enable_counter(bool(enable)); - }) - .update() - ; - _tree->access<int>(get_arg_path("configure_beams", 0) / "value") - .add_coerced_subscriber([this](int reg_value){ - this->configure_beams(uint32_t(reg_value)); - }) // No update! This would override the previous settings. - .set_publisher([this](){ - return this->user_reg_read32(RB_CHOOSE_BEAMS); - }) - ; - - /**** Configure the digital gain controls *******************************/ - for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) { - _tree->access<double>(get_arg_path("gain", i) / "value") - .set_coercer([](double gain){ - return std::max(-16.0, std::min(16.0, gain)); - }) - .add_coerced_subscriber([this, i](double gain){ - this->set_antenna_gain(i, gain); - }) - .update() - ; - } - - /**** Set up legacy compatible properties *******************************/ - // For use with multi_usrp APIs etc. - // For legacy prop tree init: - fs_path fe_path = fs_path("dboards") / "A" / "rx_frontends"; - - // The EISCAT dboards have 16 frontends total, but they map to 10 beams - // each through a matrix of FIR filters and summations, and then only 5 of - // those channels go out through the Noc-Shell. - // UHD will thus get much less confused if we create 5 fake frontends (i.e., - // number of Noc-Block-ports). Since we have no control over the frontends, - // nothing is lost here. - for (size_t fe_idx = 0; fe_idx < _num_ports; fe_idx++) { - _tree->create<std::string>(fe_path / fe_idx / "name") - .set(str(boost::format("EISCAT Beam Contributions %d") % fe_idx)) - ; - _tree->create<std::string>(fe_path / fe_idx / "connection") - .set("I") - ; - _tree->create<double>(fe_path / fe_idx / "freq" / "value") - .set_coercer([this](const double freq){ - return this->set_rx_frequency(freq, 0); - }) - .set_publisher([this](){ - return this->get_rx_frequency(0); - }) - ; - _tree->create<meta_range_t>(fe_path / fe_idx / "freq" / "range") - .set(meta_range_t(EISCAT_CENTER_FREQ, EISCAT_CENTER_FREQ)) - ; - _tree->create<double>(fe_path / fe_idx / "gains" / "null" / "value") - .set_coercer([this](const double gain){ - return this->set_rx_gain(gain, 0); - }) - .set_publisher([this](){ - return this->get_rx_gain(0); - }) - ; - _tree->create<meta_range_t>(fe_path / fe_idx / "gains" / "null" / "range") - .set(meta_range_t(EISCAT_DEFAULT_NULL_GAIN, EISCAT_DEFAULT_NULL_GAIN)) - ; - _tree->create<double>(fe_path / fe_idx / "bandwidth" / "value") - .set_coercer([this](const double bw){ - return this->set_rx_bandwidth(bw, 0); - }) - .set_publisher([this](){ - return this->get_rx_bandwidth(0); - }) - ; - _tree->create<meta_range_t>(fe_path / fe_idx / "bandwidth" / "range") - .set(meta_range_t(EISCAT_DEFAULT_BANDWIDTH, EISCAT_DEFAULT_BANDWIDTH)) - ; - _tree->create<bool>(fe_path / fe_idx / "use_lo_offset") - .set(false) - ; - } - - auto antenna_options = std::vector<std::string>{"BF"}; - for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) { - antenna_options.push_back(str(boost::format("Rx%d") % i)); - antenna_options.push_back(str(boost::format("BF%d") % i)); - } - antenna_options.push_back("FI0"); - antenna_options.push_back("FI250"); - antenna_options.push_back("FI500"); - antenna_options.push_back("FI750"); - for (size_t beam_idx = 0; beam_idx < _num_ports; beam_idx++) { - _tree->create<std::string>(fe_path / beam_idx / "antenna" / "value") - .set(EISCAT_DEFAULT_ANTENNA) - .add_coerced_subscriber([this, beam_idx](const std::string &name){ - this->set_rx_antenna(name, beam_idx); - }) - .set_publisher([this, beam_idx](){ - return this->get_rx_antenna(beam_idx); - }) - ; - _tree->create<std::vector<std::string>>( - fe_path / beam_idx / "antenna" / "options") - .set(antenna_options) - ; - } - - // We can actually stream data to an EISCAT board, so it needs some tx - // frontends too: - fe_path = fs_path("dboards") / "A" / "tx_frontends"; - for (size_t fe_idx = 0; fe_idx < _num_ports; fe_idx++) { - _tree->create<std::string>(fe_path / fe_idx / "name") - .set(str(boost::format("EISCAT Uplink %d") % fe_idx)) - ; - } - - for (size_t i = 0; i < EISCAT_NUM_PORTS; i++) { - _tree->create<uhd::time_spec_t>(get_arg_path("pseudo_stream_cmd", i) / "value") - .add_coerced_subscriber([this, i](uhd::time_spec_t stream_time){ - if (stream_time != uhd::time_spec_t(0.0)) { - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - cmd.stream_now = false; - cmd.time_spec = stream_time; - this->issue_stream_cmd(cmd, i); - } else { - this->issue_stream_cmd( - uhd::stream_cmd_t(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS), - i - ); - } - }) - ; - } - //FIXME elaborate this more, but for now it works. - _tree->create<int>("rx_codecs/A/gains"); - _tree->create<std::string>("rx_codecs/A/name").set("ADS54J66"); - - - // There is only ever one EISCAT radio per mboard, so this should be unset - // when we reach this line: - UHD_ASSERT_THROW(not _tree->exists("tick_rate")); - _tree->create<double>("tick_rate") - .set(EISCAT_TICK_RATE) - .set_coercer(boost::bind(&eiscat_radio_ctrl_impl::set_rate, this, _1)) - ; -} - -eiscat_radio_ctrl_impl::~eiscat_radio_ctrl_impl() -{ - UHD_LOG_TRACE("EISCAT", "eiscat_radio_ctrl_impl::dtor() "); -} - - -/**************************************************************************** - * Public API calls - ***************************************************************************/ -void eiscat_radio_ctrl_impl::set_tx_antenna(const std::string &, const size_t) -{ - throw uhd::runtime_error("Cannot set Tx antenna on EISCAT daughterboard"); -} - -void eiscat_radio_ctrl_impl::set_rx_antenna( - const std::string &ant, - const size_t port -) { - UHD_ASSERT_THROW(port < EISCAT_NUM_BEAMS); - if (ant == "BF") { - UHD_LOG_TRACE("EISCAT", "Setting antenna to 'BF' (which is a no-op)"); - return; - } - if (ant.size() < 3) { - throw uhd::value_error(str( - boost::format("EISCAT: Invalid antenna selection: %s") - % ant - )); - } - - const std::string ant_mode = ant.substr(0, 2); - const size_t antenna_idx = [&ant](){ - try { - return boost::lexical_cast<size_t>(ant.substr(2)); - } catch (const boost::bad_lexical_cast&) { - throw uhd::value_error(str( - boost::format("EISCAT: Invalid antenna selection: %s") - % ant - )); - } - }(); - - if (ant_mode == "BF") { - int new_choose_beams = - get_arg<int>("choose_beams") | EISCAT_SKIP_NEIGHBOURS; - set_arg<int>("choose_beams", new_choose_beams); - size_t beam_select_offset = - (get_arg<int>("choose_beams") & EISCAT_CONTRIB_UPPER) ? - EISCAT_NUM_PORTS : 0; - const size_t beam_index = port + beam_select_offset; - uhd::time_spec_t send_now(0.0); - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting block port %d to only receive from beam %d " - "connected to antenna %d via FIR matrix") - % port - % beam_index - % antenna_idx - )); - for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) { - select_filter( - beam_index, - i, - (i == antenna_idx) ? - EISCAT_FIR_INDEX_IMPULSE : EISCAT_FIR_INDEX_ZEROS, - send_now - ); - } - enable_firs(true); - } else if (ant_mode == "RX" or ant_mode == "Rx") { - int new_choose_beams = - get_arg<int>("choose_beams") | EISCAT_SKIP_NEIGHBOURS; - set_arg<int>("choose_beams", new_choose_beams); - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting port %d to only receive on antenna %d " - "directly, bypassing neighbours and FIR matrix") - % port % antenna_idx - )); - sr_write(SR_ANTENNA_SELECT_BASE + port, antenna_idx); - enable_firs(false); - } else if (ant_mode == "FI") { - size_t beam_index = port % EISCAT_NUM_PORTS; - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting port %d to filter index %d on all antennas " - "using beam indices %d and %d.") - % port - % antenna_idx - % beam_index % (beam_index + EISCAT_NUM_PORTS) - )); - // Note: antenna_idx is not indexing a physical antenna in this scenario. - uhd::time_spec_t send_now(0.0); - for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i++) { - select_filter( - beam_index, - i, - antenna_idx, - send_now - ); - select_filter( - beam_index + EISCAT_NUM_PORTS, - i, - antenna_idx, - send_now - ); - } - enable_firs(true); - } else if (ant_mode == "CN") { - const size_t beam_index = port % EISCAT_NUM_PORTS; - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting port %d to filter index %d on all antennas " - "using beam indices %d and %d.") - % port - % antenna_idx - % beam_index % (beam_index + EISCAT_NUM_PORTS) - )); - // Note: antenna_idx is not indexing a physical antenna in this scenario. - uhd::time_spec_t send_now(0.0); - for (size_t i = 0; i < EISCAT_NUM_ANTENNAS; i+=2) { - select_filter( - beam_index, - i, - 0, - send_now - ); - select_filter( - beam_index + EISCAT_NUM_PORTS, - i, - 0, - send_now - ); - select_filter( - beam_index, - i+1, - antenna_idx, - send_now - ); - select_filter( - beam_index + EISCAT_NUM_PORTS, - i+1, - antenna_idx, - send_now - ); - } - enable_firs(true); - } else { - throw uhd::value_error(str( - boost::format("EISCAT: Invalid antenna selection: %s") - % ant - )); - } -} - -double eiscat_radio_ctrl_impl::get_tx_frequency(const size_t /* chan */) -{ - UHD_LOG_WARNING("EISCAT", "Ignoring attempt to read Tx frequency"); - return 0.0; -} - -double eiscat_radio_ctrl_impl::set_tx_frequency(const double /* freq */, const size_t /* chan */) -{ - throw uhd::runtime_error("Cannot set Tx frequency on EISCAT daughterboard"); -} - -double eiscat_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) -{ - if (freq != get_rx_frequency(chan)) { - UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx frequency"); - } - return get_rx_frequency(chan); -} - -double eiscat_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) -{ - if (bandwidth != get_rx_bandwidth(chan)) { - UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx bandwidth"); - } - return get_rx_bandwidth(chan); -} - - -double eiscat_radio_ctrl_impl::set_tx_gain(const double /* gain */, const size_t /* chan */) -{ - throw uhd::runtime_error("Cannot set Tx gain on EISCAT daughterboard"); -} - -double eiscat_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) -{ - // TODO: Add ability to set digital gain or make it explicit this function is not supported. - if (gain != get_rx_gain(chan)) { - UHD_LOG_WARNING("EISCAT", "Ignoring attempt to set Rx gain."); - } - return get_rx_gain(chan); -} - -double eiscat_radio_ctrl_impl::set_rate(double rate) -{ - if (rate != get_rate()) { - UHD_LOG_WARNING("EISCAT", "Attempting to set sampling rate to invalid value " << rate); - } - return get_rate(); -} - -size_t eiscat_radio_ctrl_impl::get_chan_from_dboard_fe( - const std::string &fe, - const uhd::direction_t /* dir */ -) { - return boost::lexical_cast<size_t>(fe); -} - -std::string eiscat_radio_ctrl_impl::get_dboard_fe_from_chan( - const size_t chan, - const uhd::direction_t /* dir */ -) { - return std::to_string(chan); -} - -double eiscat_radio_ctrl_impl::get_output_samp_rate(size_t /* port */) -{ - return EISCAT_RADIO_RATE; -} - -void eiscat_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 > EISCAT_NUM_PORTS) { - 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() - )); - } - - if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) { - UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on set_rx_streamer"); - } else { - UHD_LOG_DEBUG(unique_id(), "set_rx_streamer(): We have prevs, so passing on set_rx_streamer"); - source_node_ctrl::sptr this_upstream_block_ctrl = - boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock()); - if (this_upstream_block_ctrl) { - this_upstream_block_ctrl->set_rx_streamer(active, port); - } else { - UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!"); - } - } -} - -void eiscat_radio_ctrl_impl::issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t chan) -{ - std::lock_guard<std::mutex> lock(_mutex); - - // Turn on/off top ones - if (list_upstream_nodes().empty() or not bool(get_arg<int>("use_prev"))) { - UHD_LOG_DEBUG(unique_id(), "No prevs found, or prevs disabled, not passing on stream cmd"); - } else { - UHD_LOG_DEBUG(unique_id(), "issue_stream_cmd(): We have prevs, so passing on stream command"); - source_node_ctrl::sptr this_upstream_block_ctrl = - boost::dynamic_pointer_cast<source_node_ctrl>(list_upstream_nodes().at(0).lock()); - if (this_upstream_block_ctrl) { - this_upstream_block_ctrl->issue_stream_cmd( - stream_cmd, - chan - ); - } else { - UHD_LOG_WARNING(unique_id(), "Oh noes, couldn't lock sptr!"); - } - } - - // Turn on/off this one - UHD_LOGGER_DEBUG(unique_id()) << "eiscat_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; - } - UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff); - _continuous_streaming[chan] = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS && - stream_cmd.stream_now == false) { - UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!"); - set_command_time(stream_cmd.time_spec, chan); - } - - //setup the mode to instruction flags - typedef boost::tuple<bool, bool, bool, bool> inst_t; - static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of - //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; - boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode]; - - //calculate the word from flags and length - uint32_t cmd_word = 0; - cmd_word |= uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; - cmd_word |= uint32_t((inst_chain)? 1 : 0) << 30; - cmd_word |= uint32_t((inst_reload)? 1 : 0) << 29; - cmd_word |= uint32_t((inst_stop)? 1 : 0) << 28; - cmd_word |= (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 - UHD_LOG_INFO(unique_id(), "issued stream command."); - if (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS && - stream_cmd.stream_now == false) { - UHD_LOG_TRACE("EISCAT", "Stop cmd timed, setting cmd time!"); - set_command_time(uhd::time_spec_t(0.0), chan); - } - -} - -bool eiscat_radio_ctrl_impl::check_radio_config() -{ - const uint32_t config_beams = get_arg<int>("configure_beams"); - bool skipping_neighbours = config_beams & EISCAT_SKIP_NEIGHBOURS; - bool upper_contrib = config_beams & EISCAT_CONTRIB_UPPER; - const fs_path rx_fe_path = fs_path("dboards/A/rx_frontends"); - uint32_t chan_enables = 0; - for (const auto &enb: _rx_streamer_active) { - if (enb.second) { - chan_enables |= (1<<enb.first); - } - } - if (not skipping_neighbours) { - chan_enables = chan_enables | (chan_enables << EISCAT_NUM_PORTS); - } else if (upper_contrib) { - chan_enables <<= EISCAT_NUM_PORTS; - } - UHD_LOG_TRACE("EISCAT", str( - boost::format("check_radio_config(): Setting channel enables to 0x%02X" - " Using %s beams, %saccepting neighbour contributions") - % chan_enables - % (upper_contrib ? "upper" : "lower") - % (skipping_neighbours ? "not " : "") - )); - sr_write("SR_RX_STREAM_ENABLE", chan_enables); - - return true; -} - -void eiscat_radio_ctrl_impl::set_rpc_client( - uhd::rpc_client::sptr rpcc, - const uhd::device_addr_t &block_args -) { - _rpcc = rpcc; - _block_args = block_args; - auto dboard_info = - _rpcc->request<std::vector<std::map<std::string, std::string>>>( - "get_dboard_info" - ); - _num_dboards = dboard_info.size(); - UHD_LOG_DEBUG("EISCAT", "Using " << _num_dboards << " daughterboards."); - if (_num_dboards == 1) { - UHD_LOG_WARNING("EISCAT", - "Found 1 dboard, expected 2 for optimal operation." - ); - } else if (_num_dboards > 2) { - UHD_LOG_ERROR("EISCAT", "Detected too many dboards: " << _num_dboards); - throw uhd::runtime_error("Too many dboards detected."); - } - - UHD_LOG_INFO( - "EISCAT", - "Finalizing dboard initialization; initializing JESD cores and ADCs." - ); - - /* Start of the ADC synchronization operation. - * These steps must be repeated if any ADC fails its deframer check - * Changing the sync line from SyncbAB to SyncnCD usually resolves the error - */ - const size_t possible_sync_combinations = 16; // 2 sync lines ^ (2 ADCs * 2 Daughtercards) - for (size_t iteration = 0; iteration < possible_sync_combinations; iteration++) { - UHD_LOG_INFO( - "EISCAT", - "looping to initialize JESD cores and ADCs." - ); - if (not assert_jesd_cores_initialized()) { - throw uhd::runtime_error("Failed to initialize JESD cores and reset ADCs!"); - } - send_sysref(); - - if (not assert_adcs_deframers()) { - throw uhd::runtime_error("Failed to initialize ADCs and JESD deframers!"); - } - send_sysref(); - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - - if (assert_deframer_status()) { - return; - } - } - - // Unable to find a sync line combination which works - throw uhd::runtime_error("Failed to finalize JESD core setup!"); -} - -/**************************************************************************** - * Internal methods - ***************************************************************************/ -void eiscat_radio_ctrl_impl::write_fir_taps( - const size_t fir_idx, - const std::vector<eiscat_radio_ctrl_impl::fir_tap_t> &taps -) { - if (taps.size() > EISCAT_NUM_FIR_TAPS) { - throw uhd::value_error(str( - boost::format("Too many FIR taps for EISCAT filters (%d)") - % taps.size() - )); - } - for (const auto &tap: taps) { - if (tap > EISCAT_MAX_TAP_VALUE or tap < EISCAT_MIN_TAP_VALUE) { - throw uhd::value_error(str( - boost::format("Filter tap for filter_idx %d exceeds dynamic range (%d bits are allowed)") - % fir_idx % EISCAT_BITS_PER_TAP - )); - } - } - - UHD_LOG_TRACE("EISCAT", str( - boost::format("Writing %d filter taps for filter index %d") - % taps.size() % fir_idx - )); - for (size_t i = 0; i < EISCAT_NUM_FIR_TAPS; i++) { - // Payload: - // - bottom 14 bits address, fir_idx * 16 + tap_index - // - top 18 bits are value - uint32_t reg_value = (fir_idx * 16) + i;; - if (taps.size() > i) { - reg_value |= (taps[i] & 0x3FFFF) << 14; - } - sr_write("SR_FIR_BRAM_WRITE_TAPS", reg_value); - } -} - -void eiscat_radio_ctrl_impl::select_filter( - const size_t beam_index, - const size_t antenna_index, - const size_t fir_index, - const uhd::time_spec_t &time_spec, - const bool write_time -) { - if (antenna_index >= EISCAT_NUM_ANTENNAS) { - throw uhd::value_error(str( - boost::format("Antenna index %d out of range. There are %d antennas in EISCAT.") - % antenna_index % EISCAT_NUM_ANTENNAS - )); - } - if (beam_index >= EISCAT_NUM_BEAMS) { - throw uhd::value_error(str( - boost::format("Beam index %d out of range. " - "There are %d beam channels in EISCAT.") - % beam_index - % EISCAT_NUM_BEAMS - )); - } - - UHD_LOGGER_TRACE("EISCAT") - << "Selecting filter " << fir_index - << " for beam " << beam_index - << " and antenna " << antenna_index - ; - bool send_now = (time_spec == uhd::time_spec_t(0.0)); - uint32_t reg_value = 0 - | (fir_index * 16) - | (antenna_index & 0xF) << 14 - | (beam_index & 0xF) << 18 - | send_now << 22 - ; - if (not send_now) { - UHD_LOG_TRACE("EISCAT", str( - boost::format("Filter selection will be applied at " - "time %f (0x%016X == %u). %s") - % time_spec.get_full_secs() - % time_spec.to_ticks(EISCAT_TICK_RATE) - % time_spec.to_ticks(EISCAT_TICK_RATE) - % (write_time ? "Writing time regs now." - : "Assuming time regs already up-to-date.") - )); - if (write_time) { - set_fir_ctrl_time(time_spec); - } - } - sr_write("SR_FIR_COMMANDS_RELOAD", reg_value); -} - -void eiscat_radio_ctrl_impl::set_fir_ctrl_time( - const uhd::time_spec_t &time_spec -) { - const uint64_t cmd_time_ticks = time_spec.to_ticks(EISCAT_TICK_RATE); - sr_write( - "SR_FIR_COMMANDS_CTRL_TIME_LO", - uint32_t(cmd_time_ticks & 0xFFFFFFFF) - ); - sr_write( - "SR_FIR_COMMANDS_CTRL_TIME_HI", - uint32_t((cmd_time_ticks >> 32) & 0xFFFFFFFF) - ); -} - -void eiscat_radio_ctrl_impl::set_antenna_gain( - const size_t antenna_idx, - const double normalized_gain -) { - if (normalized_gain < -16.0 or normalized_gain > 16.0) { - throw uhd::value_error(str( - boost::format("Invalid digital gain value for antenna %d: %f") - % antenna_idx % normalized_gain - )); - } - - const auto fixpoint_gain = std::max<int32_t>( - EISCAT_MIN_GAIN, - std::min( - EISCAT_MAX_GAIN, - int32_t(normalized_gain * EISCAT_UNIT_GAIN) - ) - ); - - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting digital gain value for antenna %d to %f (%d)") - % antenna_idx % normalized_gain % fixpoint_gain - )); - sr_write(SR_ANTENNA_GAIN_BASE + antenna_idx, fixpoint_gain); -} - -void eiscat_radio_ctrl_impl::configure_beams(uint32_t reg_value) -{ - UHD_LOGGER_TRACE("EISCAT") - << "Selecting " << - ((reg_value & EISCAT_CONTRIB_UPPER) ? "upper" : "lower") << " beams."; - UHD_LOGGER_TRACE("EISCAT") - << ((reg_value & EISCAT_SKIP_NEIGHBOURS) ? "Disabling" : "Enabling") - << " neighbour contributions."; - UHD_LOGGER_TRACE("EISCAT") - << ((reg_value & EISCAT_BYPASS_MATRIX) ? "Disabling" : "Enabling") - << " FIR matrix."; - UHD_LOGGER_TRACE("EISCAT") - << ((reg_value & EISCAT_OUTPUT_COUNTER) ? "Enabling" : "Disabling") - << " counter."; - UHD_LOG_TRACE("EISCAT", str( - boost::format("Setting SR_BEAMS_TO_NEIGHBOR to 0x%08X.") - % reg_value - )); - sr_write("SR_BEAMS_TO_NEIGHBOR", reg_value); -} - -void eiscat_radio_ctrl_impl::set_beam_selection(int beam_selection) -{ - UHD_ASSERT_THROW(beam_selection < 4 and beam_selection >= 0); - const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS); - const uint32_t new_value = - (old_value & (~uint32_t(EISCAT_CONTRIB_UPPER|EISCAT_SKIP_NEIGHBOURS))) - | (uint32_t(beam_selection) - & uint32_t(EISCAT_CONTRIB_UPPER|EISCAT_SKIP_NEIGHBOURS)) - ; - configure_beams(new_value); -} - -void eiscat_radio_ctrl_impl::enable_firs(bool enable) -{ - const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS); - const uint32_t new_value = enable ? - (old_value & ~EISCAT_BYPASS_MATRIX) - : old_value | EISCAT_BYPASS_MATRIX - ; - configure_beams(new_value); -} - -void eiscat_radio_ctrl_impl::send_sysref() -{ - if (_block_args.has_key("use_mpm_sysref")) { - _rpcc->notify_with_token("db_0_send_sysref"); - } else { - // This value needs to be big enough that we actually hit it between - // reading back the time, and applying the command: - const int CMD_DELAY_MS = 100; - auto sysref_time = get_time_now() - + uhd::time_spec_t(double(CMD_DELAY_MS * 1000)); - uint64_t sysref_time_ticks = sysref_time.to_ticks(EISCAT_TICK_RATE); - // The tick value must be even, or we'd still have the 180 degree phase - // ambiguity! The actual value doesn't matter. - sysref_time_ticks += sysref_time_ticks % 2; - set_command_time(uhd::time_spec_t::from_ticks( - sysref_time_ticks, EISCAT_TICK_RATE - )); - this->sr_write("SR_SYSREF", 1); - std::this_thread::sleep_for(std::chrono::milliseconds(CMD_DELAY_MS)); - } -} - -void eiscat_radio_ctrl_impl::enable_counter(bool enable) -{ - const uint32_t old_value = user_reg_read32(RB_CHOOSE_BEAMS); - const uint32_t new_value = enable ? - old_value | EISCAT_OUTPUT_COUNTER - : (old_value & ~EISCAT_OUTPUT_COUNTER) - ; - configure_beams(new_value); -} - -bool eiscat_radio_ctrl_impl::assert_jesd_cores_initialized() -{ - if (_num_dboards == 1) { - return _rpcc->request_with_token<bool>("db_0_init_jesd_core_reset_adcs"); - } - return _rpcc->request_with_token<bool>("db_0_init_jesd_core_reset_adcs") - and _rpcc->request_with_token<bool>("db_1_init_jesd_core_reset_adcs"); -} - -bool eiscat_radio_ctrl_impl::assert_adcs_deframers() -{ - if (_num_dboards == 1) { - return _rpcc->request_with_token<bool>("db_0_init_adcs_and_deframers"); - } - return _rpcc->request_with_token<bool>("db_0_init_adcs_and_deframers") - and _rpcc->request_with_token<bool>("db_1_init_adcs_and_deframers"); -} - -bool eiscat_radio_ctrl_impl::assert_deframer_status() -{ - if (_num_dboards == 1) { - return _rpcc->request_with_token<bool>("db_0_check_deframer_status"); - } - return _rpcc->request_with_token<bool>("db_0_check_deframer_status") - and _rpcc->request_with_token<bool>("db_1_check_deframer_status"); -} - -/**************************************************************************** - * Registry - ***************************************************************************/ -UHD_RFNOC_BLOCK_REGISTER(eiscat_radio_ctrl, "EISCATRadio"); diff --git a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp deleted file mode 100644 index 3ce0b48fd..000000000 --- a/host/lib/usrp/dboard/eiscat/eiscat_radio_ctrl_impl.hpp +++ /dev/null @@ -1,295 +0,0 @@ -// -// Copyright 2017 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP - -#include <uhd/types/direction.hpp> -#include <uhdlib/rfnoc/rpc_block_ctrl.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> - -namespace uhd { - namespace rfnoc { - -/*! \brief Provide access to an EISCAT radio, including beamformer. - * - * Note: This will control both daughterboards. Since we have a single RFNoC - * block, we only have one of these per motherboard. - * - * EISCAT radios have a whole bunch of features which don't have APIs provided - * by radio_ctrl. This means the most interesting features are controlled by - * set_arg() and get_arg(). Notable exception is set_rx_antenna(), which is - * heavily abused for all sorts of things. - * - * List of relevant args: - * - sysref (bool): Write to this to trigger a SYSREF pulse to *both* - * daughterboards. Will honor command time. Will always return - * true when read. - * - gain (double): Set the gain for antenna X, where X is the set_arg() `port` - * value. The gain is normalized in [0,1]. Can be read to get - * the current value. Example: `set_arg("gain", 0.5, 5)` will - * set the digital gain for antenna 5 to mid-point. - * - fir_ctrl_time (time_spec_t): This time will be used for following - * fir_select writes. Will return the last value - * that was written. - * - fir_select (int): Will queue a filter for manipulating a specific - * contribution. The value is the filter index in the BRAM. - * The port parameter specifies which filter; filters are - * indexed 0...159 using the equation beam_index * 16 + - * antenna_idx. Example: `set_arg("fir_select", 357, 16)` - * will apply filter number 357 to the zeroth antenna for - * beam number 1 (i.e. the second beam). Returns the last - * value that was written. May be incorrect before written - * for the first time. - * - fir_taps (vector<int32_t>): Updates FIR tap values in the BRAM. Port is - * the filter index. Will always return an impulse - * response, not the actual filter value. - * - assert_adcs_deframers (bool): Writing this does nothing. Reading it back - * will run the initialization of ADCs and - * deframers. Return value is success. - * - assert_deframer_status (bool): Writing this does nothing. Reading it will - * run the final step of the JESD deframer - * initialization routine. Returns success. - * - choose_beams (int): Configures beam selection (upper, lower, are neighbour - * contributions included). See set_beam_selection() for - * details. - * - enable_firs (int): Can be used to disable fir FIR matrix. This routes the - * JESD output directly to the noc_shell. - * - enable_counter (int): If the feature is available in the given FPGA image, - * setting this to true will disable the JESD core - * output and will input a counter signal (ramp) - * instead. - * - configure_beams (int): Danger, danger: Directly writes the - * SR_BEAMS_TO_NEIGHBOR register. Writing this can put - * some of the other properties out of sync, because - * writing to those will also write to this, but not - * vice versa. - * - * - * ## Time-aligned synchronization sequence: - * - * 0. Make sure all devices are getting the same ref clock and PPS! - * 1. Call set_command_time() with the same time on all blocks (make it far - * enough in the future) - * 2. Call set_arg<bool>("sysref") on all blocks. This should SYSREF all dboards - * synchronously. - * 3. On all blocks, call get_arg<bool>("assert_adcs_deframers") and verify it - * returns true. - * 4. Repeat steps 1 and 2 with, obviously, another time that's in the future. - * 5. On all blocks, call get_arg<bool>("assert_deframer_status") and make sure - * it returned true. - */ -class eiscat_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl -{ -public: - using sptr = boost::shared_ptr<eiscat_radio_ctrl_impl>; - using fir_tap_t = int32_t; // See also EISCAT_BITS_PER_TAP - - /************************************************************************ - * Structors - ***********************************************************************/ - UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(eiscat_radio_ctrl) - virtual ~eiscat_radio_ctrl_impl(); - - /************************************************************************ - * API calls - * Note: Tx calls are here mostly to throw errors. - ***********************************************************************/ - //! Returns the actual tick rate. Will display a warning if rate is not that - // value. - double set_rate(double rate); - - //! \throws uhd::runtime_error - void set_tx_antenna(const std::string &ant, const size_t chan); - - /*! Configures FPGA switching for antenna selection - * - * Valid antenna values: - * - BF: This is the default. Will apply the beamforming matrix in whatever - * state it currently is. - * - RX0...RX15: Will mux the antenna signal 0...15 straight to this - * channel. Note that this will disable the FIR matrix entirely, and will - * also disable contributions from other USRPs globally. - * - BF0...BF15: Will configure the FIR filter matrix such that only the - * contributions from antenna 0...15 are passed to this channel. This - * should produce the same signal as RX0..RX15, reduced by 12 dB (because - * the FIR matri needs to account for bit growth from adding 16 channels). - * Will also disable contributions from other channels globally. - * - FI$idx: Here, $idx is a number (the filter index, hence the name). - * This will apply filter index $idx to all input channels. Useful for - * testing actual beamforming applications, when the same signal is - * applied to all inputs. - * - * Note that this is very useful for testing and debugging. For actual - * beamforming operations, this API call won't be enough. Rather, set this - * to 'BF' (or don't do anything) and use the block properties - * - * \throws uhd::value_error if the antenna value was not valid - */ - void set_rx_antenna(const std::string &ant, const size_t chan); - - //! \throws uhd::runtime_error - double set_tx_frequency(const double freq, const size_t chan); - //! \returns Some value in the EISCAT passband - double set_rx_frequency(const double freq, const size_t chan); - //! \returns Width of the EISCAT analog frontend filters - double set_rx_bandwidth(const double bandwidth, const size_t chan); - //! \throws uhd::runtime_error - double get_tx_frequency(const size_t chan); - - //! \throws uhd::runtime_error - double set_tx_gain(const double gain, const size_t chan); - //! \returns zero - double set_rx_gain(const double gain, const size_t chan); - - size_t get_chan_from_dboard_fe(const std::string &fe, const uhd::direction_t dir); - std::string get_dboard_fe_from_chan(const size_t chan, const uhd::direction_t dir); - - //! \returns The EISCAT sampling rate - double get_output_samp_rate(size_t port); - - void set_rx_streamer(bool active, const size_t port); - void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t port); - -protected: - virtual bool check_radio_config(); - - /*! Finalize initialization sequence (ADCs, deframers) etc. - */ - void set_rpc_client( - uhd::rpc_client::sptr rpcc, - const uhd::device_addr_t &block_args - ); - -private: - /************************************************************************* - * Private methods - * To control the dboard (and execute these), take a look at the block - * properties. - ************************************************************************/ - /*! Write filter taps for a specific FIR filter. - * - * Note: If the number of taps is smaller than the number of available - * filter taps, it is padded with zero (i.e., all taps are always written - * and this can't be use to partially update filters). - * - * \param fir_idx The index of the FIR filter we are reprogramming - * \param taps A list of FIR filter taps for this filter. - * - * \throws uhd::value_error if the number of taps is longer than the number - * of taps that the filter can handle, or if any - * tap has more bits than allowed. - */ - void write_fir_taps( - const size_t fir_idx, - const std::vector<fir_tap_t> &taps - ); - - /*! Choose a filter to be applied between an output beam and antenna input - * - * \param beam_index Beam index - * \param antenna_index Antenna index - * \param fir_index The index of the FIR filter taps that get applied - * \param time_spec If non-zero, the taps get applied at this time. - * Otherwise, they get sent out now. - * \param write_time If false, time will never get written *even if* it is - * non-zero. The assumption is that someone else wrote - * the value previously - * \param write_time If false, time will never get written *even if* it is - * non-zero. The assumption is that someone else wrote - * the value previously - */ - void select_filter( - const size_t beam_index, - const size_t antenna_index, - const size_t fir_index, - const uhd::time_spec_t &time_spec, - const bool write_time=true - ); - - - /*! Sets the command time for the next call to select_filter() - * - * \param time_spec This value gets written to the FPGA and is applied to - * *all* subsequent filter selections. To request - * immediate application of filters, set this to zero. - */ - void set_fir_ctrl_time(const uhd::time_spec_t &time_spec); - - /*! Sets the digital gain on a specific antenna - * - * \param antenna_idx Antenna for which this gain setting applies - * \param normalized_gain A value in [0, 1] which gets converted to a - * digital gain value - */ - void set_antenna_gain( - const size_t antenna_idx, - const double normalized_gain - ); - - /*! Directly writes a value to the beam configuration register. - */ - void configure_beams(uint32_t reg_value); - - /*! Controls selection of beams coming from the FIR matrix. - * - * The following values are allowed: - * - 0: We stream the lower 5 beams, plus the neighbours contribution - * - 1: We stream the upper 5 beams, plus the neighbours contribution - * - 2: We stream the lower 5 beams, without the neighbours contribution - * - 3: We stream the upper 5 beams, without the neighbours contribution - */ - void set_beam_selection(int beam_selection); - - /*! Controls if we're using the FIR matrix - * - * If this is false, the beam selection is irrelevant. - */ - void enable_firs(bool enable); - - /*! Enables counter instead of JESD core output - */ - void enable_counter(bool enable); - - //! Sends a SYSREF pulse. Device arg use_mpm_sysref can be used to send it - // via MPM. Default is to send it via CHDR, in which case calling this - // function *will modify the command time!*, but it will ensure that the - // sysref is sent on an even time - void send_sysref(); - - //! Run initialization of JESD cores, put ADCs into reset - bool assert_jesd_cores_initialized(); - - //! Run initialization of ADCs and deframers; returns success status - bool assert_adcs_deframers(); - - //! Run final step of JESD core setup; returns success status - bool assert_deframer_status(); - - /*! The number of channels this block outputs - * - * This is *not* the number of antennas, but the number of streams a single - * block outputs to the crossbar. - */ - size_t _num_ports; - - //! Running with 1 dboard is theoretically possible; thus, store the - // number of active dboards. - size_t _num_dboards = 0; - - //! Additional block args; gets set during set_rpc_client() - uhd::device_addr_t _block_args; - - /*! Reference to the RPC client - */ - uhd::rpc_client::sptr _rpcc; - -}; /* class radio_ctrl_impl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_EISCAT_RADIO_CTRL_IMPL_HPP */ - diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp index dc78cee7d..13186e146 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control.cpp @@ -1,5 +1,6 @@ // // Copyright 2017 Ettus Research, a National Instruments Company +// Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // @@ -8,9 +9,7 @@ #include "magnesium_constants.hpp" #include "magnesium_gain_table.hpp" #include <uhd/exception.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> #include <uhd/rfnoc/registry.hpp> -#include <uhd/transport/chdr.hpp> #include <uhd/types/direction.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/utils/algorithm.hpp> diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp index db2ec9494..d8a1ccba8 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_init.cpp @@ -6,7 +6,6 @@ #include "magnesium_constants.hpp" #include "magnesium_radio_control.hpp" -#include <uhd/transport/chdr.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/log.hpp> diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp index a3b072e74..df2c3aadd 100644 --- a/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp +++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_control.cpp @@ -9,7 +9,6 @@ #include "rhodium_constants.hpp" #include <uhd/exception.hpp> #include <uhd/rfnoc/registry.hpp> -#include <uhd/transport/chdr.hpp> #include <uhd/types/direction.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/utils/algorithm.hpp> diff --git a/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp b/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp index d6b7afd09..850e5aff3 100644 --- a/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp +++ b/host/lib/usrp/dboard/rhodium/rhodium_radio_control_init.cpp @@ -7,7 +7,6 @@ #include "rhodium_constants.hpp" #include "rhodium_radio_control.hpp" -#include <uhd/transport/chdr.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/types/sensors.hpp> #include <uhd/utils/algorithm.hpp> diff --git a/host/lib/usrp/device3/CMakeLists.txt b/host/lib/usrp/device3/CMakeLists.txt deleted file mode 100644 index 979225c2c..000000000 --- a/host/lib/usrp/device3/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright 2014 Ettus Research LLC -# Copyright 2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -######################################################################## -# This file included, use CMake directory variables -######################################################################## - -LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/device3_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/device3_io_impl.cpp -) diff --git a/host/lib/usrp/device3/device3_flow_ctrl.hpp b/host/lib/usrp/device3/device3_flow_ctrl.hpp deleted file mode 100644 index fd445effd..000000000 --- a/host/lib/usrp/device3/device3_flow_ctrl.hpp +++ /dev/null @@ -1,306 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_DEVICE3_FLOW_CTRL_HPP -#define INCLUDED_DEVICE3_FLOW_CTRL_HPP - -#include "device3_impl.hpp" -#include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/utils/log.hpp> -#include <boost/shared_ptr.hpp> - -namespace uhd { namespace usrp { - -//! Stores the state of RX flow control -struct rx_fc_cache_t -{ - rx_fc_cache_t() - : interval(0) - , last_byte_count(0) - , total_bytes_consumed(0) - , total_packets_consumed(0) - , seq_num(0) - { - } - - //! Flow control interval in bytes - size_t interval; - //! Byte count at last flow control packet - uint32_t last_byte_count; - //! This will wrap around, but that's OK, because math. - uint32_t total_bytes_consumed; - //! This will wrap around, but that's OK, because math. - uint32_t total_packets_consumed; - //! Sequence number of next flow control packet - uint64_t seq_num; - uhd::sid_t sid; - uhd::transport::zero_copy_if::sptr xport; - std::function<uint32_t(uint32_t)> to_host; - std::function<uint32_t(uint32_t)> from_host; - std::function<void( - const uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)> - unpack; - std::function<void(uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)> - pack; -}; - -/*! Send out RX flow control packets. - * - * This function handles updating the counters for the consumed - * bytes and packets, determines if a flow control message is - * is necessary, and sends one if it is. Passing a nullptr for - * the buff parameter will skip the counter update. - * - * \param fc_cache RX flow control state information - * \param buff Receive buffer. Setting to nullptr will - * skip the counter update. - */ -inline bool rx_flow_ctrl( - boost::shared_ptr<rx_fc_cache_t> fc_cache, uhd::transport::managed_buffer::sptr buff) -{ - // If the caller supplied a buffer - if (buff) { - // Unpack the header - uhd::transport::vrt::if_packet_info_t packet_info; - packet_info.num_packet_words32 = buff->size() / sizeof(uint32_t); - const uint32_t* pkt = buff->cast<const uint32_t*>(); - try { - fc_cache->unpack(pkt, packet_info); - } catch (const std::exception& ex) { - // Log and ignore - UHD_LOGGER_ERROR("RX FLOW CTRL") - << "Error unpacking packet: " << ex.what() << std::endl; - return true; - } - - // Update counters assuming the buffer is a consumed packet - if (not packet_info.error) { - const size_t bytes = 4 * (packet_info.num_header_words32 + packet_info.num_payload_words32); - fc_cache->total_bytes_consumed += bytes; - fc_cache->total_packets_consumed++; - } - } - - // Just return if there is no need to send a flow control packet - if (fc_cache->total_bytes_consumed - fc_cache->last_byte_count < fc_cache->interval) { - return true; - } - - // Time to send a flow control packet - // Get a send buffer - uhd::transport::managed_send_buffer::sptr fc_buff = - fc_cache->xport->get_send_buff(0.0); - if (not fc_buff) { - throw uhd::runtime_error("rx_flowctrl timed out getting a send buffer"); - } - uint32_t* pkt = fc_buff->cast<uint32_t*>(); - - // load packet info - uhd::transport::vrt::if_packet_info_t packet_info; - packet_info.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_FC; - packet_info.num_payload_words32 = uhd::usrp::DEVICE3_FC_PACKET_LEN_IN_WORDS32; - packet_info.num_payload_bytes = packet_info.num_payload_words32 * sizeof(uint32_t); - packet_info.packet_count = fc_cache->seq_num++; - packet_info.sob = false; - packet_info.eob = false; - packet_info.error = false; - packet_info.fc_ack = false; - packet_info.sid = fc_cache->sid.get(); - packet_info.has_sid = true; - packet_info.has_cid = false; - packet_info.has_tsi = false; - packet_info.has_tsf = false; - packet_info.has_tlr = false; - - // Load Header: - fc_cache->pack(pkt, packet_info); - // Load Payload: Packet count, and byte count - pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_PACKET_COUNT_OFFSET] = - fc_cache->from_host(fc_cache->total_packets_consumed); - pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_BYTE_COUNT_OFFSET] = - fc_cache->from_host(fc_cache->total_bytes_consumed); - - // send the buffer over the interface - fc_buff->commit(sizeof(uint32_t) * (packet_info.num_packet_words32)); - - // update byte count - fc_cache->last_byte_count = fc_cache->total_bytes_consumed; - - return true; -} - -/*! Handle RX flow control ACK packets. - * - */ -inline void handle_rx_flowctrl_ack( - boost::shared_ptr<rx_fc_cache_t> fc_cache, const uint32_t* payload) -{ - const uint32_t pkt_count = fc_cache->to_host(payload[0]); - const uint32_t byte_count = fc_cache->to_host(payload[1]); - if (fc_cache->total_bytes_consumed != byte_count) { - UHD_LOGGER_DEBUG("device3") - << "oh noes: byte_count==" << byte_count - << " total_bytes_consumed==" << fc_cache->total_bytes_consumed << std::hex - << " sid==" << fc_cache->sid << std::dec << std::endl; - } - fc_cache->total_bytes_consumed = byte_count; - fc_cache->total_packets_consumed = pkt_count; // guess we need a pkt offset too? - - // This will send a flow control packet if there is a significant discrepancy - rx_flow_ctrl(fc_cache, nullptr); -} - -//! Stores the state of TX flow control -struct tx_fc_cache_t -{ - tx_fc_cache_t(uint32_t capacity) - : last_byte_ack(0) - , last_seq_ack(0) - , byte_count(0) - , pkt_count(0) - , window_size(capacity) - , fc_ack_seqnum(0) - , fc_received(false) - { - } - - uint32_t last_byte_ack; - uint32_t last_seq_ack; - uint32_t byte_count; - uint32_t pkt_count; - uint32_t window_size; - uint32_t fc_ack_seqnum; - bool fc_received; - std::function<uint32_t(uint32_t)> to_host; - std::function<uint32_t(uint32_t)> from_host; - std::function<void( - const uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)> - unpack; - std::function<void(uint32_t* packet_buff, uhd::transport::vrt::if_packet_info_t&)> - pack; -}; - -inline bool tx_flow_ctrl(boost::shared_ptr<tx_fc_cache_t> fc_cache, - uhd::transport::zero_copy_if::sptr xport, - uhd::transport::managed_buffer::sptr buff) -{ - while (true) { - // If there is space - if (fc_cache->window_size - (fc_cache->byte_count - fc_cache->last_byte_ack) - >= buff->size()) { - // All is good - packet will be sent - fc_cache->byte_count += buff->size(); - // Round up to nearest word - if (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE) { - fc_cache->byte_count += - uhd::usrp::DEVICE3_LINE_SIZE - - (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE); - } - fc_cache->pkt_count++; - return true; - } - - // Look for a flow control message to update the space available in the buffer. - uhd::transport::managed_recv_buffer::sptr buff = xport->get_recv_buff(0.1); - if (buff) { - uhd::transport::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*>(); - try { - fc_cache->unpack(packet_buff, if_packet_info); - } catch (const std::exception& ex) { - UHD_LOGGER_ERROR("TX FLOW CTRL") - << "Error unpacking flow control packet: " << ex.what() << std::endl; - continue; - } - - if (if_packet_info.packet_type - != uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_FC) { - UHD_LOGGER_ERROR("TX FLOW CTRL") - << "Unexpected packet received by flow control handler: " - << if_packet_info.packet_type << std::endl; - continue; - } - - const uint32_t* payload = &packet_buff[if_packet_info.num_header_words32]; - const uint32_t pkt_count = fc_cache->to_host(payload[0]); - const uint32_t byte_count = fc_cache->to_host(payload[1]); - - // update the amount of space - fc_cache->last_byte_ack = byte_count; - fc_cache->last_seq_ack = pkt_count; - - fc_cache->fc_received = true; - } - } - return false; -} - -inline void tx_flow_ctrl_ack(boost::shared_ptr<tx_fc_cache_t> fc_cache, - uhd::transport::zero_copy_if::sptr send_xport, - uhd::sid_t send_sid) -{ - if (not fc_cache->fc_received) { - return; - } - - // Time to send a flow control ACK packet - // Get a send buffer - uhd::transport::managed_send_buffer::sptr fc_buff = send_xport->get_send_buff(0.0); - if (not fc_buff) { - UHD_LOGGER_ERROR("tx_flow_ctrl_ack") << "timed out getting a send buffer"; - return; - } - uint32_t* pkt = fc_buff->cast<uint32_t*>(); - - // Load packet info - uhd::transport::vrt::if_packet_info_t packet_info; - packet_info.packet_type = uhd::transport::vrt::if_packet_info_t::PACKET_TYPE_ACK; - packet_info.num_payload_words32 = uhd::usrp::DEVICE3_FC_PACKET_LEN_IN_WORDS32; - packet_info.num_payload_bytes = packet_info.num_payload_words32 * sizeof(uint32_t); - packet_info.packet_count = fc_cache->fc_ack_seqnum++; - packet_info.sob = false; - packet_info.eob = true; - packet_info.error = false; - packet_info.fc_ack = false; - packet_info.sid = send_sid.get(); - packet_info.has_sid = true; - packet_info.has_cid = false; - packet_info.has_tsi = false; - packet_info.has_tsf = false; - packet_info.has_tlr = false; - - // Load Header: - fc_cache->pack(pkt, packet_info); - - // Update counters to include this packet - size_t fc_ack_pkt_size = sizeof(uint32_t) * (packet_info.num_packet_words32); - fc_cache->byte_count += fc_ack_pkt_size; - // Round up to nearest word - if (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE) { - fc_cache->byte_count += uhd::usrp::DEVICE3_LINE_SIZE - - (fc_cache->byte_count % uhd::usrp::DEVICE3_LINE_SIZE); - } - fc_cache->pkt_count++; - - // Load Payload: Packet count, and byte count - pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_PACKET_COUNT_OFFSET] = - fc_cache->from_host(fc_cache->pkt_count); - pkt[packet_info.num_header_words32 + uhd::usrp::DEVICE3_FC_BYTE_COUNT_OFFSET] = - fc_cache->from_host(fc_cache->byte_count); - - // Send the buffer over the interface - fc_buff->commit(fc_ack_pkt_size); - - // Reset for next FC - fc_cache->fc_received = false; -} - -}}; // namespace uhd::usrp - -#endif /* INCLUDED_DEVICE3_FLOW_CTRL_HPP */ diff --git a/host/lib/usrp/device3/device3_impl.cpp b/host/lib/usrp/device3/device3_impl.cpp deleted file mode 100644 index bc1cf9002..000000000 --- a/host/lib/usrp/device3/device3_impl.cpp +++ /dev/null @@ -1,206 +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 "device3_impl.hpp" -#include <uhd/rfnoc/block_ctrl_base.hpp> -#include <uhd/utils/log.hpp> -#include <uhdlib/rfnoc/ctrl_iface.hpp> -#include <uhdlib/rfnoc/graph_impl.hpp> -#include <boost/make_shared.hpp> -#include <algorithm> - -using namespace uhd::usrp; - -device3_impl::device3_impl() -{ - _type = uhd::device::USRP; - _async_md.reset(new async_md_type(1000 /*messages deep*/)); - _tree = uhd::property_tree::make(); -}; - -//! Returns true if the integer value stored in lhs is smaller than that in rhs -bool _compare_string_indexes(const std::string& lhs, const std::string& rhs) -{ - return boost::lexical_cast<size_t>(lhs) < boost::lexical_cast<size_t>(rhs); -} - -void device3_impl::merge_channel_defs(const std::vector<uhd::rfnoc::block_id_t>& chan_ids, - const std::vector<uhd::device_addr_t>& chan_args, - const uhd::direction_t dir) -{ - UHD_ASSERT_THROW(chan_ids.size() == chan_args.size()); - if (dir == uhd::DX_DIRECTION) { - merge_channel_defs(chan_ids, chan_args, RX_DIRECTION); - merge_channel_defs(chan_ids, chan_args, TX_DIRECTION); - return; - } - - uhd::fs_path chans_root = - uhd::fs_path("/channels/") / (dir == RX_DIRECTION ? "rx" : "tx"); - // Store the new positions of the channels: - std::vector<size_t> chan_idxs; - - // 1. Get sorted list of currently defined channels - std::vector<std::string> curr_channels; - if (_tree->exists(chans_root)) { - curr_channels = _tree->list(chans_root); - std::sort(curr_channels.begin(), curr_channels.end(), _compare_string_indexes); - } - - // 2. Cycle through existing channels to find out where to merge - // the new channels. Rules are: - // - The order of chan_ids must be preserved - // - All block indices that are in chan_ids may be overwritten in the channel - // definition - // - If the channels in chan_ids are not yet in the property tree channel list, - // they are appended. - for (const std::string& chan_idx : curr_channels) { - if (_tree->exists(chans_root / chan_idx)) { - rfnoc::block_id_t chan_block_id = - _tree->access<rfnoc::block_id_t>(chans_root / chan_idx).get(); - if (std::find(chan_ids.begin(), chan_ids.end(), chan_block_id) - != chan_ids.end()) { - chan_idxs.push_back(boost::lexical_cast<size_t>(chan_idx)); - } - } - } - size_t last_chan_idx = curr_channels.empty() - ? 0 - : (boost::lexical_cast<size_t>(curr_channels.back()) + 1); - while (chan_idxs.size() < chan_ids.size()) { - chan_idxs.push_back(last_chan_idx); - last_chan_idx++; - } - - // 3. Write the new channels - for (size_t i = 0; i < chan_ids.size(); i++) { - if (not _tree->exists(chans_root / chan_idxs[i])) { - _tree->create<rfnoc::block_id_t>(chans_root / chan_idxs[i]); - } - _tree->access<rfnoc::block_id_t>(chans_root / chan_idxs[i]).set(chan_ids[i]); - if (not _tree->exists(chans_root / chan_idxs[i] / "args")) { - _tree->create<uhd::device_addr_t>(chans_root / chan_idxs[i] / "args"); - } - _tree->access<uhd::device_addr_t>(chans_root / chan_idxs[i] / "args") - .set(chan_args[i]); - } -} - -/*********************************************************************** - * RFNoC-Specific - **********************************************************************/ -void device3_impl::enumerate_rfnoc_blocks(size_t device_index, - size_t n_blocks, - size_t base_port, - const uhd::sid_t& base_sid, - uhd::device_addr_t transport_args) -{ - // entries that are already connected to this block - uhd::sid_t ctrl_sid = base_sid; - uhd::property_tree::sptr subtree = - _tree->subtree(uhd::fs_path("/mboards") / device_index); - // 1) Clean property tree entries - // TODO put this back once radios are actual rfnoc blocks!!!!!! - // if (subtree->exists("xbar")) { - // subtree->remove("xbar"); - //} - // 2) Destroy existing block controllers - // TODO: Clear out all the old block control classes - // 3) Create new block controllers - for (size_t i = 0; i < n_blocks; i++) { - // First, make a transport for port number zero, because we always need that: - ctrl_sid.set_dst_xbarport(base_port + i); - ctrl_sid.set_dst_blockport(0); - both_xports_t xport = this->make_transport(ctrl_sid, CTRL, transport_args); - UHD_LOG_TRACE("DEVICE3", - str(boost::format("Setting up NoC-Shell Control for port #0 (SID: %s)...") - % xport.send_sid.to_pp_string_hex())); - uhd::rfnoc::ctrl_iface::sptr ctrl = uhd::rfnoc::ctrl_iface::make(xport, - str(boost::format("CE_%02d_Port_%02X") % i % ctrl_sid.get_dst_endpoint())); - uint64_t noc_id = ctrl->send_cmd_pkt( - uhd::rfnoc::SR_READBACK, uhd::rfnoc::SR_READBACK_REG_ID, true); - UHD_LOG_DEBUG("DEVICE3", - str(boost::format("Port 0x%02X: Found NoC-Block with ID %016X.") - % int(ctrl_sid.get_dst_endpoint()) % noc_id)); - uhd::rfnoc::make_args_t make_args; - uhd::rfnoc::blockdef::sptr block_def = - uhd::rfnoc::blockdef::make_from_noc_id(noc_id); - if (not block_def) { - UHD_LOG_WARNING("DEVICE3", - "No block definition found, using default block configuration " - "for block with NOC ID: " - + str(boost::format("0x%08X") % noc_id)); - block_def = - uhd::rfnoc::blockdef::make_from_noc_id(uhd::rfnoc::DEFAULT_NOC_ID_64); - } - UHD_ASSERT_THROW(block_def); - make_args.ctrl_ifaces[0] = ctrl; - for (const size_t port_number : block_def->get_all_port_numbers()) { - if (port_number == 0) { // We've already set this up - continue; - } - ctrl_sid.set_dst_blockport(port_number); - both_xports_t xport1 = this->make_transport(ctrl_sid, CTRL, transport_args); - UHD_LOG_TRACE("DEVICE3", - str(boost::format("Setting up NoC-Shell Control for port #%d " - "(SID: %s)...") - % port_number % xport1.send_sid.to_pp_string_hex())); - uhd::rfnoc::ctrl_iface::sptr ctrl1 = uhd::rfnoc::ctrl_iface::make(xport1, - str(boost::format("CE_%02d_Port_%02X") % i - % ctrl_sid.get_dst_endpoint())); - make_args.ctrl_ifaces[port_number] = ctrl1; - } - UHD_LOG_TRACE("DEVICE3", - "All control transports successfully created for block with ID " - << str(boost::format("0x%08X") % noc_id)); - - make_args.base_address = xport.send_sid.get_dst(); - make_args.device_index = device_index; - make_args.tree = subtree; - { // Critical section for block_ctrl vector access - boost::lock_guard<boost::mutex> lock(_block_ctrl_mutex); - _rfnoc_block_ctrl.push_back( - uhd::rfnoc::block_ctrl_base::make(make_args, noc_id)); - _rfnoc_block_ctrl.back()->set_graph_update_cb([this]() { - update_rx_streamers(); - update_tx_streamers(); - }); - } - } -} - - -uhd::rfnoc::graph::sptr device3_impl::create_graph(const std::string& name) -{ - // Create an async message handler - UHD_LOGGER_TRACE("DEVICE3") - << "Creating async message handler for graph `" << name << "'..."; - // FIXME: right now this only can only handle source sid of 0 and xbar local addr - // of 2. This is ok for now because that most of our device has xbard local addr - // hardcode to 2. - sid_t async_sid(0); - async_sid.set_dst_addr(2); - both_xports_t async_xports = make_transport(async_sid, - ASYNC_MSG, - // FIXME: only get rx_hints from mb index of 0 - get_rx_hints(0)); - UHD_LOGGER_TRACE("DEVICE3") << " Async transport ready." << std::endl; - uhd::rfnoc::async_msg_handler::sptr async_msg_handler = - uhd::rfnoc::async_msg_handler::make(async_xports.recv, - async_xports.send, - async_xports.send_sid, - async_xports.endianness); - UHD_LOGGER_TRACE("DEVICE3") - << "Async message has address " << async_xports.send_sid << std::endl; - - // Create the graph - UHD_LOGGER_TRACE("DEVICE3") << "Creating graph `" << name << "'..." << std::endl; - uhd::rfnoc::graph::sptr graph = boost::make_shared<uhd::rfnoc::graph_impl>( - name, shared_from_this(), async_msg_handler); - - return graph; -} diff --git a/host/lib/usrp/device3/device3_impl.hpp b/host/lib/usrp/device3/device3_impl.hpp deleted file mode 100644 index 17f6a3f6f..000000000 --- a/host/lib/usrp/device3/device3_impl.hpp +++ /dev/null @@ -1,264 +0,0 @@ -// -// Copyright 2014-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -// Declares the device3_impl class which is a layer between device3 and -// the different 3-rd gen device impls (e.g. x300_impl) - -#ifndef INCLUDED_DEVICE3_IMPL_HPP -#define INCLUDED_DEVICE3_IMPL_HPP - -#include "../../transport/super_recv_packet_handler.hpp" -#include "../../transport/super_send_packet_handler.hpp" -#include <uhd/device3.hpp> -#include <uhd/transport/bounded_buffer.hpp> -#include <uhd/transport/chdr.hpp> -#include <uhd/transport/vrt_if_packet.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/direction.hpp> -#include <uhd/types/endianness.hpp> -#include <uhd/types/metadata.hpp> -#include <uhd/types/sid.hpp> -#include <uhd/utils/tasks.hpp> -#include <uhdlib/rfnoc/rx_stream_terminator.hpp> -#include <uhdlib/rfnoc/tx_stream_terminator.hpp> -#include <uhdlib/rfnoc/xports.hpp> - -namespace uhd { namespace usrp { - -/*********************************************************************** - * Default settings (any device3 may override these) - **********************************************************************/ -static const size_t DEVICE3_RX_FC_REQUEST_FREQ = 32; // per flow-control window -static const size_t DEVICE3_TX_FC_RESPONSE_FREQ = 8; -static const size_t DEVICE3_FC_PACKET_LEN_IN_WORDS32 = 2; -static const size_t DEVICE3_FC_PACKET_COUNT_OFFSET = 0; -static const size_t DEVICE3_FC_BYTE_COUNT_OFFSET = 1; -static const size_t DEVICE3_LINE_SIZE = 8; - -static const size_t DEVICE3_TX_MAX_HDR_LEN = - uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes -static const size_t DEVICE3_RX_MAX_HDR_LEN = - uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes - -// This class manages the lifetime of the TX async message handler task, transports, and -// terminator -class device3_send_packet_streamer : public uhd::transport::sph::send_packet_streamer -{ -public: - device3_send_packet_streamer(const size_t max_num_samps, - const uhd::rfnoc::tx_stream_terminator::sptr terminator, - const both_xports_t data_xport, - const both_xports_t async_msg_xport) - : uhd::transport::sph::send_packet_streamer(max_num_samps) - , _terminator(terminator) - , _data_xport(data_xport) - , _async_msg_xport(async_msg_xport) - { - } - - ~device3_send_packet_streamer() - { - // Make sure the async task is destroyed before the transports - _tx_async_msg_tasks.clear(); - } - - uhd::rfnoc::tx_stream_terminator::sptr get_terminator() - { - return _terminator; - } - - void add_async_msg_task(task::sptr task) - { - _tx_async_msg_tasks.push_back(task); - } - -private: - uhd::rfnoc::tx_stream_terminator::sptr _terminator; - both_xports_t _data_xport; - both_xports_t _async_msg_xport; - std::vector<task::sptr> _tx_async_msg_tasks; -}; - -// This class manages the lifetime of the RX transports and terminator and provides access -// to both -class device3_recv_packet_streamer : public uhd::transport::sph::recv_packet_streamer -{ -public: - device3_recv_packet_streamer(const size_t max_num_samps, - const uhd::rfnoc::rx_stream_terminator::sptr terminator, - const both_xports_t xport) - : uhd::transport::sph::recv_packet_streamer(max_num_samps) - , _terminator(terminator) - , _xport(xport) - { - } - - ~device3_recv_packet_streamer() {} - - both_xports_t get_xport() - { - return _xport; - } - - uhd::rfnoc::rx_stream_terminator::sptr get_terminator() - { - return _terminator; - } - -private: - uhd::rfnoc::rx_stream_terminator::sptr _terminator; - both_xports_t _xport; -}; - -class device3_impl : public uhd::device3, - public boost::enable_shared_from_this<device3_impl> -{ -public: - /*********************************************************************** - * device3-specific Types - **********************************************************************/ - typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type; - - //! The purpose of a transport - enum xport_type_t { CTRL = 0, ASYNC_MSG, TX_DATA, RX_DATA }; - - enum xport_t { AXI, ETH, PCIE }; - - //! Stores all streaming-related options - struct stream_options_t - { - //! Max size of the header in bytes for TX - size_t tx_max_len_hdr; - //! Max size of the header in bytes for RX - size_t rx_max_len_hdr; - //! How often we send ACKs to the upstream block per one full FC window - size_t rx_fc_request_freq; - //! How often the downstream block should send ACKs per one full FC window - size_t tx_fc_response_freq; - stream_options_t(void) - : tx_max_len_hdr(DEVICE3_TX_MAX_HDR_LEN) - , rx_max_len_hdr(DEVICE3_RX_MAX_HDR_LEN) - , rx_fc_request_freq(DEVICE3_RX_FC_REQUEST_FREQ) - , tx_fc_response_freq(DEVICE3_TX_FC_RESPONSE_FREQ) - { - } - }; - - /*********************************************************************** - * I/O Interface - **********************************************************************/ - uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t&); - uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t&); - bool recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout); - - /*********************************************************************** - * Other public APIs - **********************************************************************/ - rfnoc::graph::sptr create_graph(const std::string& name = ""); - -protected: - /*********************************************************************** - * Structors - **********************************************************************/ - device3_impl(); - virtual ~device3_impl() {} - - /*********************************************************************** - * Streaming-related - **********************************************************************/ -public: // TODO make these protected again - /*! Update tick rate, samp rate, and scaling on the streamers by querying - * the graph. - */ - void update_rx_streamers(); - /*! Update tick rate, samp rate, and scaling on the streamers by querying - * the graph. - */ - void update_tx_streamers(); - -protected: - /*********************************************************************** - * Transport-related - **********************************************************************/ - stream_options_t stream_options; - - /*! \brief Create a transport to a given endpoint. - * - * \param address The endpoint address of the block we're creating a transport to. - * The source address in this value is not considered, only the - * destination address. - * \param xport_type Specify which kind of transport this is. - * \param args Additional arguments for the transport generation. See \ref - * page_transport for valid arguments. - */ - virtual uhd::both_xports_t make_transport(const uhd::sid_t& address, - const xport_type_t xport_type, - const uhd::device_addr_t& args) = 0; - - virtual uhd::device_addr_t get_tx_hints(size_t) - { - return uhd::device_addr_t(); - } - virtual uhd::device_addr_t get_rx_hints(size_t) - { - return uhd::device_addr_t(); - } - - //! Is called after a streamer is generated - virtual void post_streamer_hooks(uhd::direction_t) {} - - //! get mtu - virtual size_t get_mtu(const size_t, const uhd::direction_t) = 0; - - /*********************************************************************** - * Channel-related - **********************************************************************/ - /*! Merge a list of channels into the existing channel definition. - * - * Intelligently merge the channels described in \p chan_ids - * into the current channel definition. If none of the channels in - * \p chan_ids is in the current definition, they simply get appended. - * Otherwise, they get overwritten in the order of \p chan_ids. - * - * \param chan_ids List of block IDs for the channels. - * \param chan_args New channel args. Must have same length as chan_ids. - * - */ - void merge_channel_defs(const std::vector<rfnoc::block_id_t>& chan_ids, - const std::vector<uhd::device_addr_t>& chan_args, - const uhd::direction_t dir); - - /*********************************************************************** - * RFNoC-Specific - **********************************************************************/ - void enumerate_rfnoc_blocks(size_t device_index, - size_t n_blocks, - size_t base_port, - const uhd::sid_t& base_sid, - uhd::device_addr_t transport_args); - - /*********************************************************************** - * Members - **********************************************************************/ - // TODO: Maybe move these to private - uhd::dict<std::string, boost::weak_ptr<uhd::rx_streamer>> _rx_streamers; - uhd::dict<std::string, boost::weak_ptr<uhd::tx_streamer>> _tx_streamers; - -private: - /*********************************************************************** - * Private Members - **********************************************************************/ - //! Buffer for async metadata - boost::shared_ptr<async_md_type> _async_md; - - //! This mutex locks the get_xx_stream() functions. - boost::mutex _transport_setup_mutex; -}; - -}} /* namespace uhd::usrp */ - -#endif /* INCLUDED_DEVICE3_IMPL_HPP */ diff --git a/host/lib/usrp/device3/device3_io_impl.cpp b/host/lib/usrp/device3/device3_io_impl.cpp deleted file mode 100644 index 800d2f5a8..000000000 --- a/host/lib/usrp/device3/device3_io_impl.cpp +++ /dev/null @@ -1,827 +0,0 @@ -// -// Copyright 2014-2016 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -// Provides streaming-related functions which are used by device3 objects. - -#include "device3_flow_ctrl.hpp" -#include "device3_impl.hpp" -#include <uhd/rfnoc/constants.hpp> -#include <uhd/rfnoc/radio_ctrl.hpp> -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <uhd/rfnoc/sink_block_ctrl_base.hpp> -#include <uhd/rfnoc/source_block_ctrl_base.hpp> -#include <uhd/transport/zero_copy_flow_ctrl.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/log.hpp> -#include <uhdlib/rfnoc/rx_stream_terminator.hpp> -#include <uhdlib/rfnoc/tx_stream_terminator.hpp> -#include <uhdlib/usrp/common/async_packet_handler.hpp> -#include <boost/atomic.hpp> - -#define UHD_TX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER") -#define UHD_RX_STREAMER_LOG() UHD_LOGGER_TRACE("STREAMER") - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -/*********************************************************************** - * Helper functions for get_?x_stream() - **********************************************************************/ -static uhd::stream_args_t sanitize_stream_args(const uhd::stream_args_t& args_) -{ - uhd::stream_args_t args = args_; - if (args.channels.empty()) { - args.channels = std::vector<size_t>(1, 0); - } - - return args; -} - -static void check_stream_sig_compatible( - const rfnoc::stream_sig_t& stream_sig, stream_args_t& args, const std::string& tx_rx) -{ - if (args.otw_format.empty()) { - if (stream_sig.item_type.empty()) { - throw uhd::runtime_error( - str(boost::format("[%s Streamer] No otw_format defined!") % tx_rx)); - } else { - args.otw_format = stream_sig.item_type; - } - } else if (not stream_sig.item_type.empty() - and stream_sig.item_type != args.otw_format) { - throw uhd::runtime_error( - str(boost::format("[%s Streamer] Conflicting OTW types defined: " - "args.otw_format = '%s' <=> stream_sig.item_type = '%s'") - % tx_rx % args.otw_format % stream_sig.item_type)); - } - const size_t bpi = convert::get_bytes_per_item(args.otw_format); // bytes per item - if (stream_sig.packet_size) { - if (args.args.has_key("spp")) { - size_t args_spp = args.args.cast<size_t>("spp", 0); - if (args_spp * bpi != stream_sig.packet_size) { - throw uhd::runtime_error( - str(boost::format( - "[%s Streamer] Conflicting packet sizes defined: args yields " - "%d bytes but stream_sig.packet_size is %d bytes") - % tx_rx % (args_spp * bpi) % stream_sig.packet_size)); - } - } else { - args.args["spp"] = str(boost::format("%d") % (stream_sig.packet_size / bpi)); - } - } -} - -/*! \brief Returns a list of rx or tx channels for a streamer. - * - * If the given stream args contain instructions to set up channels, - * those are used. Otherwise, the current device's channel definition - * is consulted. - * - * \param args_ Stream args. - * \param[out] chan_list The list of channels in the correct order. - * \param[out] chan_args Channel args for every channel. `chan_args.size() == - * chan_list.size()` - */ -void generate_channel_list(const uhd::stream_args_t& args_, - std::vector<uhd::rfnoc::block_id_t>& chan_list, - std::vector<device_addr_t>& chan_args) -{ - uhd::stream_args_t args = args_; - std::vector<uhd::rfnoc::block_id_t> chan_list_(args.channels.size()); - std::vector<device_addr_t> chan_args_(args.channels.size()); - - for (size_t i = 0; i < args.channels.size(); i++) { - // Extract block ID - size_t chan_idx = args.channels[i]; - std::string key = str(boost::format("block_id%d") % chan_idx); - if (args.args.has_key(key)) { - chan_list_[i] = args.args.pop(key); - } else if (args.args.has_key("block_id")) { - chan_list_[i] = args.args["block_id"]; - } else { - throw uhd::runtime_error( - str(boost::format( - "Cannot create streamers: No block_id specified for channel %d.") - % chan_idx)); - } - - // Split off known channel specific args - key = str(boost::format("block_port%d") % chan_idx); - if (args.args.has_key(key)) { - chan_args_[i]["block_port"] = args.args.pop(key); - } - key = str(boost::format("radio_id%d") % chan_idx); - if (args.args.has_key(key)) { - chan_args_[i]["radio_id"] = args.args.pop(key); - } - key = str(boost::format("radio_port%d") % chan_idx); - if (args.args.has_key(key)) { - chan_args_[i]["radio_port"] = args.args.pop(key); - } - } - - // Add all remaining args to all channel args - for (device_addr_t& chan_arg : chan_args_) { - chan_arg = chan_arg.to_string() + "," + args.args.to_string(); - } - - chan_list = chan_list_; - chan_args = chan_args_; -} - - -/*********************************************************************** - * RX Flow Control Functions - **********************************************************************/ -/*! Determine the size of the flow control window in number of packets. - * - * This value depends on three things: - * - The packet size (in bytes), P - * - The size of the software buffer (in bytes), B - * - The desired buffer fullness, F - * - * The FC window size is thus X = floor(B*F/P). - * - * \param pkt_size The maximum packet size in bytes - * \param sw_buff_size Software buffer size in bytes - * \param rx_args If this has a key 'recv_buff_fullness', this value will - * be used for said fullness. Must be between 0.01 and 1. - * - * \returns The size of the flow control window in number of packets - */ -static size_t get_rx_flow_control_window( - size_t pkt_size, size_t sw_buff_size, const device_addr_t& rx_args) -{ - double fullness_factor = rx_args.cast<double>( - "recv_buff_fullness", uhd::rfnoc::DEFAULT_FC_RX_SW_BUFF_FULL_FACTOR); - - if (fullness_factor < 0.01 || fullness_factor > 1) { - throw uhd::value_error( - "recv_buff_fullness must be in [0.01, 1] inclusive (1% to 100%)"); - } - - size_t window_in_bytes = (static_cast<size_t>(fullness_factor * sw_buff_size)); - if (rx_args.has_key("max_recv_window")) { - window_in_bytes = std::min( - window_in_bytes, - pkt_size * rx_args.cast<size_t>("max_recv_window", 1) - ); - } - if (window_in_bytes < pkt_size) { - throw uhd::value_error("recv_buff_size must be larger than the recv_frame_size."); - } - UHD_ASSERT_THROW(size_t(sw_buff_size * fullness_factor) >= window_in_bytes); - return window_in_bytes; -} - - -/*********************************************************************** - * TX Async Message Functions - **********************************************************************/ -#define DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL 0 - -struct async_tx_info_t -{ - size_t stream_channel; - size_t device_channel; - boost::shared_ptr<device3_impl::async_md_type> async_queue; - boost::shared_ptr<device3_impl::async_md_type> old_async_queue; -}; - -/*! Handle incoming messages. - * Send them to the async message queue for the user to poll. - * - * This is run inside a uhd::task as long as this streamer lives. - */ -static void handle_tx_async_msgs(boost::shared_ptr<async_tx_info_t> async_info, - zero_copy_if::sptr xport, - uint32_t (*to_host)(uint32_t), - void (*unpack)(const uint32_t* packet_buff, vrt::if_packet_info_t&), - boost::function<double(void)> get_tick_rate) -{ - managed_recv_buffer::sptr buff = xport->get_recv_buff(); - if (not buff) { - return; - } - - // extract 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 - try { - unpack(packet_buff, if_packet_info); - } catch (const std::exception& ex) { - UHD_LOGGER_ERROR("STREAMER") - << "Error parsing async message packet: " << ex.what(); - return; - } - - double tick_rate = get_tick_rate(); - if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) { - tick_rate = 1; - } - - // fill in the async metadata - async_metadata_t metadata; - load_metadata_from_buff(to_host, - metadata, - if_packet_info, - packet_buff, - tick_rate, - async_info->stream_channel); - - // Filter out any flow control messages and cache the rest - if (metadata.event_code == DEVICE3_ASYNC_EVENT_CODE_FLOW_CTRL) { - UHD_LOGGER_ERROR("TX ASYNC MSG") - << "Unexpected flow control message found in async message handling" - << std::endl; - } else { - async_info->async_queue->push_with_pop_on_full(metadata); - metadata.channel = async_info->device_channel; - async_info->old_async_queue->push_with_pop_on_full(metadata); - standard_async_msg_prints(metadata); - } -} - -bool device3_impl::recv_async_msg(async_metadata_t& async_metadata, double timeout) -{ - return _async_md->pop_with_timed_wait(async_metadata, timeout); -} - -/*********************************************************************** - * Receive streamer - **********************************************************************/ -void device3_impl::update_rx_streamers() -{ - for (const std::string& block_id : _rx_streamers.keys()) { - UHD_RX_STREAMER_LOG() << "updating RX streamer to " << block_id; - boost::shared_ptr<device3_recv_packet_streamer> my_streamer = - boost::dynamic_pointer_cast<device3_recv_packet_streamer>( - _rx_streamers[block_id].lock()); - if (my_streamer) { - double tick_rate = my_streamer->get_terminator()->get_tick_rate(); - if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) { - tick_rate = 1.0; - } - double samp_rate = my_streamer->get_terminator()->get_output_samp_rate(); - if (samp_rate == rfnoc::rate_node_ctrl::RATE_UNDEFINED) { - samp_rate = 1.0; - } - double scaling = my_streamer->get_terminator()->get_output_scale_factor(); - if (scaling == rfnoc::scalar_node_ctrl::SCALE_UNDEFINED) { - scaling = 1 / 32767.; - } - UHD_RX_STREAMER_LOG() - << " New tick_rate == " << tick_rate - << " New samp_rate == " << samp_rate << " New scaling == " << scaling; - - my_streamer->set_tick_rate(tick_rate); - my_streamer->set_samp_rate(samp_rate); - my_streamer->set_scale_factor(scaling); - } - } -} - -rx_streamer::sptr device3_impl::get_rx_stream(const stream_args_t& args_) -{ - boost::mutex::scoped_lock lock(_transport_setup_mutex); - stream_args_t args = sanitize_stream_args(args_); - - // I. Generate the channel list - std::vector<uhd::rfnoc::block_id_t> chan_list; - std::vector<device_addr_t> chan_args; - generate_channel_list(args, chan_list, chan_args); - // Note: All 'args.args' are merged into chan_args now. - - // II. Iterate over all channels - boost::shared_ptr<device3_recv_packet_streamer> my_streamer; - // The terminator's lifetime is coupled to the streamer. - // There is only one terminator. If the streamer has multiple channels, - // it will be connected to each upstream block. - rfnoc::rx_stream_terminator::sptr recv_terminator = - rfnoc::rx_stream_terminator::make(); - for (size_t stream_i = 0; stream_i < chan_list.size(); stream_i++) { - // First, configure blocks and create transport - - // Get block ID and mb index - uhd::rfnoc::block_id_t block_id = chan_list[stream_i]; - UHD_RX_STREAMER_LOG() << "chan " << stream_i << " connecting to " << block_id; - // Update args so args.args is always valid for this particular channel: - args.args = chan_args[stream_i]; - size_t mb_index = block_id.get_device_no(); - size_t suggested_block_port = - args.args.cast<size_t>("block_port", rfnoc::ANY_PORT); - - // Access to this channel's block control - uhd::rfnoc::source_block_ctrl_base::sptr blk_ctrl = - boost::dynamic_pointer_cast<uhd::rfnoc::source_block_ctrl_base>( - get_block_ctrl(block_id)); - - // Connect the terminator with this channel's block. - size_t block_port = blk_ctrl->connect_downstream( - recv_terminator, suggested_block_port, args.args); - const size_t terminator_port = recv_terminator->connect_upstream(blk_ctrl); - blk_ctrl->set_downstream_port(block_port, terminator_port); - recv_terminator->set_upstream_port(terminator_port, block_port); - - // Check if the block connection is compatible (spp and item type) - check_stream_sig_compatible( - blk_ctrl->get_output_signature(block_port), args, "RX"); - - // Setup the DSP transport hints - device_addr_t rx_hints = get_rx_hints(mb_index); - - // Search the device and all nodes for lowest MTU - size_t mtu = std::min( - get_mtu(mb_index, uhd::direction_t::RX_DIRECTION), - blk_ctrl->get_mtu(block_port)); - UHD_RX_STREAMER_LOG() << "Maximum MTU supported by " - << blk_ctrl->unique_id() - << ": " << blk_ctrl->get_mtu(block_port); - std::vector<boost::shared_ptr<uhd::rfnoc::source_block_ctrl_base>> - upstream_source_nodes = - blk_ctrl->find_upstream_node<uhd::rfnoc::source_block_ctrl_base>(); - for (const boost::shared_ptr<uhd::rfnoc::source_block_ctrl_base>& node : - upstream_source_nodes) { - // Get MTU from Port 0 of the upstream nodes. This is okay for now as - // currently we use port 0 of a block in case of channel 1. - UHD_RX_STREAMER_LOG() << "Maximum MTU supported by " << node->unique_id() - << ": " << node->get_mtu(0); - mtu = std::min(mtu, node->get_mtu(0)); - } - rx_hints["mtu"] = std::to_string(mtu); - - // Make sure user supplied recv_frame_size is less than the MTU - if (rx_hints.cast<size_t>("recv_frame_size", mtu) > mtu) { - UHD_LOGGER_WARNING("STREAMER") - << "Requested recv_frame_size of " - << rx_hints["recv_frame_size"] - << " exceeds the maximum possible on this stream. Using " - << mtu; - rx_hints["recv_frame_size"] = std::to_string(mtu); - } - - // allocate sid and create transport - uhd::sid_t stream_address = blk_ctrl->get_address(block_port); - UHD_RX_STREAMER_LOG() << "creating rx stream " << rx_hints.to_string(); - both_xports_t xport = make_transport(stream_address, RX_DATA, rx_hints); - UHD_RX_STREAMER_LOG() << std::hex << "data_sid = " << xport.send_sid << std::dec - << " actual recv_buff_size = " << xport.recv_buff_size; - - // Configure the block - // Flow control setup - const size_t pkt_size = xport.recv->get_recv_frame_size(); - // Leave one pkt_size space for overrun packets - TODO make this obsolete - const size_t fc_window = - get_rx_flow_control_window(pkt_size, xport.recv_buff_size, rx_hints) - - pkt_size; - const size_t fc_handle_window = - std::max<size_t>(pkt_size, fc_window / stream_options.rx_fc_request_freq); - UHD_RX_STREAMER_LOG() << "Flow Control Window = " << (fc_window) - << ", Flow Control Handler Window = " << fc_handle_window; - blk_ctrl->configure_flow_control_out(true, - xport.lossless, - fc_window, - rx_hints.cast<size_t>("recv_pkt_limit", - 0), // On rfnoc-devel, update e300_impl::get_rx_hints() to set this to 32 - block_port); - - // Add flow control transport - boost::shared_ptr<rx_fc_cache_t> fc_cache(new rx_fc_cache_t()); - fc_cache->sid = xport.send_sid; - fc_cache->xport = xport.send; - fc_cache->interval = fc_handle_window; - if (xport.endianness == ENDIANNESS_BIG) { - fc_cache->to_host = uhd::ntohx<uint32_t>; - fc_cache->from_host = uhd::htonx<uint32_t>; - fc_cache->pack = vrt::chdr::if_hdr_pack_be; - fc_cache->unpack = vrt::chdr::if_hdr_unpack_be; - } else { - fc_cache->to_host = uhd::wtohx<uint32_t>; - fc_cache->from_host = uhd::htowx<uint32_t>; - fc_cache->pack = vrt::chdr::if_hdr_pack_le; - fc_cache->unpack = vrt::chdr::if_hdr_unpack_le; - } - xport.recv = zero_copy_flow_ctrl::make( - xport.recv, 0, [fc_cache](managed_buffer::sptr buff) { - return rx_flow_ctrl(fc_cache, buff); - }); - - // Configure the block - // Note: We need to set_destination() after writing to SR_CLEAR_TX_FC. - // See noc_shell.v, in the section called Stream Source for details. - // Setting SR_CLEAR_TX_FC will actually also clear the destination and - // other settings. - blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x1, block_port); - blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_TX_FC, 0x0, block_port); - // Configure routing for data - blk_ctrl->set_destination(xport.send_sid.get_src(), block_port); - - // Configure routing for responses - blk_ctrl->sr_write( - uhd::rfnoc::SR_RESP_OUT_DST_SID, xport.send_sid.get_src(), block_port); - UHD_RX_STREAMER_LOG() << "resp_out_dst_sid == " << xport.send_sid.get_src(); - - // Find all upstream radio nodes and set their response in SID to the host - std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>> upstream_radio_nodes = - blk_ctrl->find_upstream_node<uhd::rfnoc::radio_ctrl>(); - UHD_RX_STREAMER_LOG() << "Number of upstream radio nodes: " - << upstream_radio_nodes.size(); - for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node : - upstream_radio_nodes) { - node->sr_write( - uhd::rfnoc::SR_RESP_OUT_DST_SID, xport.send_sid.get_src(), block_port); - } - - // Second, configure the streamer - - // make the new streamer given the samples per packet - if (not my_streamer) { - // To calculate the max number of samples per packet, we assume the maximum - // header length to avoid fragmentation should the entire header be used. - const size_t bpp = - pkt_size - stream_options.rx_max_len_hdr; // bytes per packet - const size_t bpi = - convert::get_bytes_per_item(args.otw_format); // bytes per item - const size_t spp = std::min(args.args.cast<size_t>("spp", bpp / bpi), - bpp / bpi); // samples per packet - UHD_RX_STREAMER_LOG() << "bpp == " << bpp << ", bpi == " << bpi << ", spp == " << spp; - - my_streamer = boost::make_shared<device3_recv_packet_streamer>( - spp, recv_terminator, xport); - my_streamer->resize(chan_list.size()); - } - - // init some streamer stuff - std::string conv_endianness; - if (xport.endianness == ENDIANNESS_BIG) { - my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be); - conv_endianness = "be"; - } else { - my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le); - conv_endianness = "le"; - } - - // set the converter - uhd::convert::id_type id; - id.input_format = args.otw_format + "_item32_" + conv_endianness; - id.num_inputs = 1; - id.output_format = args.cpu_format; - id.num_outputs = 1; - my_streamer->set_converter(id); - - // Give the streamer a functor to handle flow control ACK messages - my_streamer->set_xport_handle_flowctrl_ack( - stream_i, [fc_cache](const uint32_t* payload) { - handle_rx_flowctrl_ack(fc_cache, payload); - }); - - // Give the streamer a functor to get the recv_buffer - my_streamer->set_xport_chan_get_buff(stream_i, - [xport](double timeout) { return xport.recv->get_recv_buff(timeout); }, - true /*flush*/ - ); - - // Give the streamer a functor to handle overruns - // bind requires a weak_ptr to break the a streamer->streamer circular dependency - // Using "this" is OK because we know that this device3_impl will outlive the - // streamer - boost::weak_ptr<uhd::rx_streamer> weak_ptr(my_streamer); - my_streamer->set_overflow_handler( - stream_i, [recv_terminator, weak_ptr, stream_i]() { - recv_terminator->handle_overrun(weak_ptr, stream_i); - }); - - // Give the streamer a functor issue stream cmd - my_streamer->set_issue_stream_cmd( - stream_i, [blk_ctrl, block_port](const stream_cmd_t& stream_cmd) { - blk_ctrl->issue_stream_cmd(stream_cmd, block_port); - }); - } - - // Notify all blocks in this chain that they are connected to an active streamer - recv_terminator->set_rx_streamer(true, 0); - - // Store a weak pointer to prevent a streamer->device3_impl->streamer circular - // dependency. Note that we store the streamer only once, and use its terminator's ID - // to do so. - _rx_streamers[recv_terminator->unique_id()] = - boost::weak_ptr<uhd::rx_streamer>(my_streamer); - - // Sets tick rate, samp rate and scaling on this streamer. - // A registered terminator is required to do this. - update_rx_streamers(); - - post_streamer_hooks(RX_DIRECTION); - return my_streamer; -} - -/*********************************************************************** - * Transmit streamer - **********************************************************************/ -void device3_impl::update_tx_streamers() -{ - for (const std::string& block_id : _tx_streamers.keys()) { - UHD_TX_STREAMER_LOG() << "updating TX streamer: " << block_id; - boost::shared_ptr<device3_send_packet_streamer> my_streamer = - boost::dynamic_pointer_cast<device3_send_packet_streamer>( - _tx_streamers[block_id].lock()); - if (my_streamer) { - double tick_rate = my_streamer->get_terminator()->get_tick_rate(); - if (tick_rate == rfnoc::tick_node_ctrl::RATE_UNDEFINED) { - tick_rate = 1.0; - } - double samp_rate = my_streamer->get_terminator()->get_input_samp_rate(); - if (samp_rate == rfnoc::rate_node_ctrl::RATE_UNDEFINED) { - samp_rate = 1.0; - } - double scaling = my_streamer->get_terminator()->get_input_scale_factor(); - if (scaling == rfnoc::scalar_node_ctrl::SCALE_UNDEFINED) { - scaling = 32767.; - } - UHD_TX_STREAMER_LOG() - << "New tick_rate == " << tick_rate << " New samp_rate == " << samp_rate - << " New scaling == " << scaling; - my_streamer->set_tick_rate(tick_rate); - my_streamer->set_samp_rate(samp_rate); - my_streamer->set_scale_factor(scaling); - } - } -} - -tx_streamer::sptr device3_impl::get_tx_stream(const uhd::stream_args_t& args_) -{ - boost::mutex::scoped_lock lock(_transport_setup_mutex); - stream_args_t args = sanitize_stream_args(args_); - - // I. Generate the channel list - std::vector<uhd::rfnoc::block_id_t> chan_list; - std::vector<device_addr_t> chan_args; - generate_channel_list(args, chan_list, chan_args); - // Note: All 'args.args' are merged into chan_args now. - - // shared async queue for all channels in streamer - boost::shared_ptr<async_md_type> async_md(new async_md_type(1000 /*messages deep*/)); - - // II. Iterate over all channels - boost::shared_ptr<device3_send_packet_streamer> my_streamer; - // The terminator's lifetime is coupled to the streamer. - // There is only one terminator. If the streamer has multiple channels, - // it will be connected to each downstream block. - rfnoc::tx_stream_terminator::sptr send_terminator = - rfnoc::tx_stream_terminator::make(); - for (size_t stream_i = 0; stream_i < chan_list.size(); stream_i++) { - // First, configure the downstream blocks and create the transports - - // Get block ID and mb index - uhd::rfnoc::block_id_t block_id = chan_list[stream_i]; - // Update args so args.args is always valid for this particular channel: - args.args = chan_args[stream_i]; - size_t mb_index = block_id.get_device_no(); - size_t suggested_block_port = - args.args.cast<size_t>("block_port", rfnoc::ANY_PORT); - - // Access to this channel's block control - uhd::rfnoc::sink_block_ctrl_base::sptr blk_ctrl = - boost::dynamic_pointer_cast<uhd::rfnoc::sink_block_ctrl_base>( - get_block_ctrl(block_id)); - - // Connect the terminator with this channel's block. - // This will throw if the connection is not possible. - size_t block_port = - blk_ctrl->connect_upstream(send_terminator, suggested_block_port, args.args); - const size_t terminator_port = send_terminator->connect_downstream(blk_ctrl); - blk_ctrl->set_upstream_port(block_port, terminator_port); - send_terminator->set_downstream_port(terminator_port, block_port); - - // Check if the block connection is compatible (spp and item type) - check_stream_sig_compatible( - blk_ctrl->get_input_signature(block_port), args, "TX"); - - // Setup the dsp transport hints - device_addr_t tx_hints = get_tx_hints(mb_index); - - // Search the device and all nodes for lowest MTU - size_t mtu = std::min( - get_mtu(mb_index, uhd::direction_t::TX_DIRECTION), - blk_ctrl->get_mtu(block_port)); - UHD_TX_STREAMER_LOG() << "Maximum MTU supported by " - << blk_ctrl->unique_id() << ": " - << blk_ctrl->get_mtu(block_port); - std::vector<boost::shared_ptr<uhd::rfnoc::sink_block_ctrl_base>> - downstream_sink_nodes = - blk_ctrl->find_downstream_node<uhd::rfnoc::sink_block_ctrl_base>(); - for (const boost::shared_ptr<uhd::rfnoc::sink_block_ctrl_base>& node : - downstream_sink_nodes) { - // Get MTU from Port 0 of the downstream nodes. This is okay for now as - // currently we use port 0 of a block in case of channel 1. - UHD_TX_STREAMER_LOG() << "Maximum MTU supported by " - << node->unique_id() << ": " - << node->get_mtu(0); - mtu = std::min(mtu, node->get_mtu(0)); - } - tx_hints["mtu"] = std::to_string(mtu); - - // Make sure user supplied send_frame_size is less than the MTU - if (tx_hints.cast<size_t>("send_frame_size", mtu) > mtu) { - UHD_LOGGER_WARNING("STREAMER") - << "Requested send_frame_size of " - << tx_hints["send_frame_size"] - << " exceeds the maximum possible on this stream. Using " - << mtu; - tx_hints["send_frame_size"] = std::to_string(mtu); - } - - const size_t fifo_size = blk_ctrl->get_fifo_size(block_port); - // Allocate sid and create transport - uhd::sid_t stream_address = blk_ctrl->get_address(block_port); - UHD_TX_STREAMER_LOG() << "creating tx stream " << tx_hints.to_string(); - both_xports_t xport = make_transport(stream_address, TX_DATA, tx_hints); - both_xports_t async_xport = - make_transport(stream_address, ASYNC_MSG, device_addr_t("")); - UHD_TX_STREAMER_LOG() << std::hex << "data_sid = " << xport.send_sid << std::dec; - - // Configure flow control - // This disables the FC module's output, do this before configuring flow control - blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x1, block_port); - blk_ctrl->sr_write(uhd::rfnoc::SR_CLEAR_RX_FC, 0x0, block_port); - // Configure flow control on downstream block - const size_t pkt_size = xport.send->get_send_frame_size(); - const size_t fc_window = - std::min(tx_hints.cast<size_t>("send_buff_size", fifo_size), fifo_size); - const size_t fc_handle_window = - std::max<size_t>(pkt_size, fc_window / stream_options.tx_fc_response_freq); - UHD_TX_STREAMER_LOG() << "Flow Control Window = " << fc_window - << ", Flow Control Handler Window = " << fc_handle_window - << ", FIFO size = " << fifo_size; - blk_ctrl->configure_flow_control_in(fc_handle_window, /*bytes*/ - block_port); - // Add flow control transport - boost::shared_ptr<tx_fc_cache_t> fc_cache(new tx_fc_cache_t(fc_window)); - if (xport.endianness == ENDIANNESS_BIG) { - fc_cache->to_host = uhd::ntohx<uint32_t>; - fc_cache->from_host = uhd::htonx<uint32_t>; - fc_cache->pack = vrt::chdr::if_hdr_pack_be; - fc_cache->unpack = vrt::chdr::if_hdr_unpack_be; - } else { - fc_cache->to_host = uhd::wtohx<uint32_t>; - fc_cache->from_host = uhd::htowx<uint32_t>; - fc_cache->pack = vrt::chdr::if_hdr_pack_le; - fc_cache->unpack = vrt::chdr::if_hdr_unpack_le; - } - xport.send = zero_copy_flow_ctrl::make(xport.send, - [fc_cache, xport](managed_buffer::sptr buff) { - return tx_flow_ctrl(fc_cache, xport.recv, buff); - }, - 0); - - // Configure return path for async messages - blk_ctrl->sr_write( - uhd::rfnoc::SR_RESP_IN_DST_SID, async_xport.recv_sid.get_dst(), block_port); - UHD_TX_STREAMER_LOG() << "resp_in_dst_sid == " - << boost::format("0x%04X") % xport.recv_sid.get_dst(); - - // FIXME: Once there is a better way to map the radio block and port - // to the channel or another way to receive asynchronous messages that - // is not in-band, this should be removed. - if (args.args.has_key("radio_id") and args.args.has_key("radio_port")) { - // Find downstream radio node and set the response SID to the host - uhd::rfnoc::block_id_t radio_id(args.args["radio_id"]); - size_t radio_port = args.args.cast<size_t>("radio_port", 0); - std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>> - downstream_radio_nodes = - blk_ctrl->find_downstream_node<uhd::rfnoc::radio_ctrl>(); - UHD_TX_STREAMER_LOG() - << "Number of downstream radio nodes: " << downstream_radio_nodes.size(); - for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node : - downstream_radio_nodes) { - if (node->get_block_id() == radio_id) { - node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, - async_xport.recv_sid.get_dst(), - radio_port); - } - } - } else { - // FIXME: This block is preserved for legacy behavior where the - // radio_id and radio_port are not provided. It fails if more - // than one radio is visible downstream or the port on the radio - // is not the same as the block_port. It should be removed as - // soon as possible. - // Find all downstream radio nodes and set their response SID to the host - std::vector<boost::shared_ptr<uhd::rfnoc::radio_ctrl>> - downstream_radio_nodes = - blk_ctrl->find_downstream_node<uhd::rfnoc::radio_ctrl>(); - UHD_TX_STREAMER_LOG() - << "Number of downstream radio nodes: " << downstream_radio_nodes.size(); - for (const boost::shared_ptr<uhd::rfnoc::radio_ctrl>& node : - downstream_radio_nodes) { - node->sr_write(uhd::rfnoc::SR_RESP_IN_DST_SID, - async_xport.recv_sid.get_dst(), - block_port); - } - } - - // Second, configure the streamer now that the blocks and transports are - // configured - - // make the new streamer given the samples per packet - if (not my_streamer) { - // To calculate the max number of samples per packet, we assume the maximum - // header length to avoid fragmentation should the entire header be used. - const size_t bpp = - tx_hints.cast<size_t>("bpp", pkt_size) - - stream_options.tx_max_len_hdr; - const size_t bpi = - convert::get_bytes_per_item(args.otw_format); // bytes per item - const size_t spp = std::min(args.args.cast<size_t>("spp", bpp / bpi), - bpp / bpi); // samples per packet - UHD_TX_STREAMER_LOG() - << "bpp == " << bpp - << ", bpi == " << bpi - << ", spp == " << spp; - - my_streamer = boost::make_shared<device3_send_packet_streamer>( - spp, send_terminator, xport, async_xport); - my_streamer->resize(chan_list.size()); - } - - // init some streamer stuff - std::string conv_endianness; - if (xport.endianness == ENDIANNESS_BIG) { - my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be); - conv_endianness = "be"; - } else { - my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le); - conv_endianness = "le"; - } - - // set the converter - uhd::convert::id_type id; - id.input_format = args.cpu_format; - id.num_inputs = 1; - id.output_format = args.otw_format + "_item32_" + conv_endianness; - id.num_outputs = 1; - my_streamer->set_converter(id); - - boost::shared_ptr<async_tx_info_t> async_tx_info(new async_tx_info_t()); - async_tx_info->stream_channel = args.channels[stream_i]; - async_tx_info->device_channel = mb_index; - async_tx_info->async_queue = async_md; - async_tx_info->old_async_queue = _async_md; - - task::sptr async_task = - task::make([async_tx_info, async_xport, xport, send_terminator]() { - handle_tx_async_msgs(async_tx_info, - async_xport.recv, - xport.endianness == ENDIANNESS_BIG ? uhd::ntohx<uint32_t> - : uhd::wtohx<uint32_t>, - xport.endianness == ENDIANNESS_BIG ? vrt::chdr::if_hdr_unpack_be - : vrt::chdr::if_hdr_unpack_le, - [send_terminator]() { return send_terminator->get_tick_rate(); }); - }); - my_streamer->add_async_msg_task(async_task); - - // Give the streamer a functor to get the send buffer - my_streamer->set_xport_chan_get_buff(stream_i, - [xport](const double timeout) { return xport.send->get_send_buff(timeout); }); - // Give the streamer a functor handled received async messages - my_streamer->set_async_receiver( - [async_md](uhd::async_metadata_t& md, const double timeout) { - return async_md->pop_with_timed_wait(md, timeout); - }); - my_streamer->set_xport_chan_sid(stream_i, true, xport.send_sid); - // CHDR does not support trailers - my_streamer->set_enable_trailer(false); - - // Avoid sending FC ACKs if the transport is lossless or the user - // has explictly requested not to send them - if (not(xport.lossless or tx_hints.has_key("send_no_fc_acks"))) { - my_streamer->set_xport_chan_post_send_cb(stream_i, [fc_cache, xport]() { - tx_flow_ctrl_ack(fc_cache, xport.send, xport.send_sid); - }); - } - } - - // Notify all blocks in this chain that they are connected to an active streamer - send_terminator->set_tx_streamer(true, 0); - - // Store a weak pointer to prevent a streamer->device3_impl->streamer circular - // dependency. Note that we store the streamer only once, and use its terminator's ID - // to do so. - _tx_streamers[send_terminator->unique_id()] = - boost::weak_ptr<uhd::tx_streamer>(my_streamer); - - // Sets tick rate, samp rate and scaling on this streamer - // A registered terminator is required to do this. - update_tx_streamers(); - - post_streamer_hooks(TX_DIRECTION); - return my_streamer; -} diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp index 30a3c5804..69f990807 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_impl.cpp @@ -7,15 +7,9 @@ #include "mpmd_impl.hpp" #include <uhd/exception.hpp> #include <uhd/types/component_file.hpp> -#include <uhd/types/eeprom.hpp> -#include <uhd/types/sensors.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> #include <uhd/utils/static.hpp> #include <uhd/utils/tasks.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> -#include <uhdlib/rfnoc/rpc_block_ctrl.hpp> #include <boost/algorithm/string.hpp> -#include <boost/asio.hpp> #include <boost/make_shared.hpp> #include <boost/thread.hpp> #include <chrono> diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp index baf0dde3e..2a3a48b62 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.cpp @@ -192,77 +192,79 @@ mpmd_link_if_ctrl_dpdk_udp::mpmd_link_if_ctrl_dpdk_udp( } } -uhd::both_xports_t -mpmd_link_if_ctrl_dpdk_udp::make_transport( - mpmd_link_if_mgr::xport_info_t &xport_info, - const usrp::device3_impl::xport_type_t xport_type, - const uhd::device_addr_t& xport_args -) { +// uhd::both_xports_t +// mpmd_link_if_ctrl_dpdk_udp::make_transport( +// mpmd_link_if_mgr::xport_info_t &xport_info, +// const uhd::transport::link_type_t xport_type, +// const uhd::device_addr_t& xport_args +//) { - // Constrain by this transport's MTU and the MTU in the xport_args - const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION), - xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION))); - const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION), - xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION))); +//// Constrain by this transport's MTU and the MTU in the xport_args +// const size_t send_mtu = std::min(get_mtu(uhd::TX_DIRECTION), +// xport_args.cast<size_t>("mtu", get_mtu(uhd::TX_DIRECTION))); +// const size_t recv_mtu = std::min(get_mtu(uhd::RX_DIRECTION), +// xport_args.cast<size_t>("mtu", get_mtu(uhd::RX_DIRECTION))); - // Create actual UHD-DPDK UDP transport - transport::zero_copy_xport_params default_buff_args; - default_buff_args.num_recv_frames = MPMD_ETH_NUM_CTRL_FRAMES; - default_buff_args.num_send_frames = MPMD_ETH_NUM_CTRL_FRAMES; - default_buff_args.recv_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; - default_buff_args.send_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; +//// Create actual UHD-DPDK UDP transport +// transport::zero_copy_xport_params default_buff_args; +// default_buff_args.num_recv_frames = MPMD_ETH_NUM_CTRL_FRAMES; +// default_buff_args.num_send_frames = MPMD_ETH_NUM_CTRL_FRAMES; +// default_buff_args.recv_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; +// default_buff_args.send_frame_size = MPMD_10GE_MSG_FRAME_DEFAULT_SIZE; - if (xport_type == usrp::device3_impl::RX_DATA) { - default_buff_args.num_recv_frames = - xport_args.cast<size_t>("num_recv_frames", MPMD_ETH_NUM_RECV_FRAMES); - default_buff_args.recv_frame_size = std::min( - xport_args.cast<size_t>("recv_frame_size", - MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), - recv_mtu); - } else if (xport_type == usrp::device3_impl::TX_DATA) { - default_buff_args.num_send_frames = - xport_args.cast<size_t>("num_send_frames", MPMD_ETH_NUM_SEND_FRAMES); - default_buff_args.send_frame_size = std::min( - xport_args.cast<size_t>("send_frame_size", - MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), - send_mtu); - } +// if (xport_type == uhd::transport::link_type_t::RX_DATA) { +// default_buff_args.num_recv_frames = +// xport_args.cast<size_t>("num_recv_frames", MPMD_ETH_NUM_RECV_FRAMES); +// default_buff_args.recv_frame_size = std::min( +// xport_args.cast<size_t>("recv_frame_size", +// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), +// recv_mtu); +//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { +// default_buff_args.num_send_frames = +// xport_args.cast<size_t>("num_send_frames", MPMD_ETH_NUM_SEND_FRAMES); +// default_buff_args.send_frame_size = std::min( +// xport_args.cast<size_t>("send_frame_size", +// MPMD_10GE_DATA_FRAME_DEFAULT_SIZE), +// send_mtu); +//} - UHD_LOG_TRACE("BUFF", "num_recv_frames=" << default_buff_args.num_recv_frames - << ", num_send_frames=" << default_buff_args.num_send_frames - << ", recv_frame_size=" << default_buff_args.recv_frame_size - << ", send_frame_size=" << default_buff_args.send_frame_size); +// UHD_LOG_TRACE("BUFF", "num_recv_frames=" << default_buff_args.num_recv_frames +//<< ", num_send_frames=" << default_buff_args.num_send_frames +//<< ", recv_frame_size=" << default_buff_args.recv_frame_size +//<< ", send_frame_size=" << default_buff_args.send_frame_size); - int dpdk_port_id = _ctx.get_route(xport_info["ipv4"]); - if (dpdk_port_id < 0) { - throw uhd::runtime_error("Could not find a DPDK port with route to " + - xport_info["ipv4"]); - } - auto recv = transport::dpdk_zero_copy::make( - _ctx, - (const unsigned int) dpdk_port_id, - xport_info["ipv4"], - xport_info["port"], - "0", - default_buff_args, - uhd::device_addr_t() - ); - const uint16_t port = recv->get_local_port(); - const std::string src_ip_addr = recv->get_local_addr(); - xport_info["src_port"] = std::to_string(port); - xport_info["src_ipv4"] = src_ip_addr; +// int dpdk_port_id = _ctx.get_route(xport_info["ipv4"]); +// if (dpdk_port_id < 0) { +// throw uhd::runtime_error("Could not find a DPDK port with route to " + +// xport_info["ipv4"]); +//} +// auto recv = transport::dpdk_zero_copy::make( +//_ctx, +//(const unsigned int) dpdk_port_id, +// xport_info["ipv4"], +// xport_info["port"], +//"0", +// default_buff_args, +// uhd::device_addr_t() +//); +// const uint16_t port = recv->get_local_port(); +// const std::string src_ip_addr = recv->get_local_addr(); +// xport_info["src_port"] = std::to_string(port); +// xport_info["src_ipv4"] = src_ip_addr; - // Create both_xports_t object and finish: - both_xports_t xports; - xports.endianness = uhd::ENDIANNESS_BIG; - xports.send_sid = sid_t(xport_info["send_sid"]); - xports.recv_sid = xports.send_sid.reversed(); - xports.recv_buff_size = (default_buff_args.recv_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_recv_frames; - xports.send_buff_size = (default_buff_args.send_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_send_frames; - xports.recv = recv; // Note: This is a type cast! - xports.send = recv; // This too - return xports; -} +//// Create both_xports_t object and finish: +// both_xports_t xports; +// xports.endianness = uhd::ENDIANNESS_BIG; +// xports.send_sid = sid_t(xport_info["send_sid"]); +// xports.recv_sid = xports.send_sid.reversed(); +// xports.recv_buff_size = +// (default_buff_args.recv_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_recv_frames; +// xports.send_buff_size = +// (default_buff_args.send_frame_size-MPMD_UDP_RESERVED_FRAME_SIZE)*default_buff_args.num_send_frames; +// xports.recv = recv; // Note: This is a type cast! +// xports.send = recv; // This too +// return xports; +//} bool mpmd_link_if_ctrl_dpdk_udp::is_valid( const mpmd_link_if_mgr::xport_info_t& xport_info diff --git a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp index 4423b4340..8f4f1c7d1 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_ctrl_dpdk_udp.hpp @@ -10,7 +10,6 @@ #include "mpmd_link_if_ctrl_base.hpp" #include <uhd/types/device_addr.hpp> #include <uhdlib/transport/dpdk_zero_copy.hpp> -#include "../device3/device3_impl.hpp" namespace uhd { namespace mpmd { namespace xport { @@ -25,12 +24,6 @@ public: const uhd::device_addr_t& mb_args ); - both_xports_t make_transport( - mpmd_link_if_mgr::xport_info_t& xport_info, - const usrp::device3_impl::xport_type_t xport_type, - const uhd::device_addr_t& xport_args - ); - bool is_valid( const mpmd_link_if_mgr::xport_info_t& xport_info ) const; diff --git a/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp index 4b0ba4212..a1d11bad7 100644 --- a/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp +++ b/host/lib/usrp/mpmd/mpmd_link_if_mgr.hpp @@ -130,10 +130,10 @@ public: * The latter needs to get sent back to MPM to complete the * transport handshake. */ - //virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list, - //const usrp::device3_impl::xport_type_t xport_type, - //const uhd::device_addr_t& xport_args, - //xport_info_t& xport_info_out) = 0; + // virtual both_xports_t make_transport(const xport_info_list_t& xport_info_list, + // const uhd::transport::link_type_t::xport_type_t xport_type, + // const uhd::device_addr_t& xport_args, + // xport_info_t& xport_info_out) = 0; /*! Return the path MTU for whatever this manager lets us do */ diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 227ba4212..6f8b794ce 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -20,7 +20,6 @@ #include <uhd/convert.hpp> #include <uhd/utils/soft_register.hpp> #include <uhdlib/usrp/gpio_defs.hpp> -#include <uhdlib/rfnoc/legacy_compat.hpp> #include <uhdlib/rfnoc/rfnoc_device.hpp> #include <boost/assign/list_of.hpp> #include <boost/format.hpp> @@ -397,8 +396,7 @@ static double derive_freq_from_xx_subdev_and_dsp( **********************************************************************/ class multi_usrp_impl : public multi_usrp{ public: - multi_usrp_impl(device::sptr dev, const device_addr_t& addr) - : _dev(dev) + multi_usrp_impl(device::sptr dev) : _dev(dev) { _tree = _dev->get_tree(); } @@ -2259,7 +2257,6 @@ public: private: device::sptr _dev; property_tree::sptr _tree; - uhd::rfnoc::legacy_compat::sptr _legacy_compat; struct mboard_chan_pair{ size_t mboard, chan; @@ -2517,5 +2514,5 @@ multi_usrp::sptr multi_usrp::make(const device_addr_t& dev_addr) if (rfnoc_dev) { return rfnoc::detail::make_rfnoc_device(rfnoc_dev, dev_addr); } - return boost::make_shared<multi_usrp_impl>(dev, dev_addr); + return boost::make_shared<multi_usrp_impl>(dev); } diff --git a/host/lib/usrp/x300/x300_eth_mgr.cpp b/host/lib/usrp/x300/x300_eth_mgr.cpp index b1d9f40ee..8ff63b050 100644 --- a/host/lib/usrp/x300/x300_eth_mgr.cpp +++ b/host/lib/usrp/x300/x300_eth_mgr.cpp @@ -239,46 +239,46 @@ both_links_t eth_manager::get_links(link_type_t link_type, //#ifdef HAVE_DPDK // auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); - // default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES; - // default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES; - // if (link_type == link_type_t::CTRL) { - //// Increasing number of recv frames here because ctrl_iface uses it - //// to determine how many control packets can be in flight before it - //// must wait for an ACK - // default_buff_args.num_recv_frames = - // uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; - //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) { - // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE - //? GE_DATA_FRAME_SEND_SIZE - //: XGE_DATA_FRAME_SEND_SIZE; - // default_buff_args.send_frame_size = args.cast<size_t>( - //"send_frame_size", std::min(default_frame_size, send_mtu)); - // default_buff_args.num_send_frames = - // args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames); - // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); - //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) { - // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE - //? GE_DATA_FRAME_RECV_SIZE - //: XGE_DATA_FRAME_RECV_SIZE; - // default_buff_args.recv_frame_size = args.cast<size_t>( - //"recv_frame_size", std::min(default_frame_size, recv_mtu)); - // default_buff_args.num_recv_frames = - // args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames); - // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); - //} - - // int dpdk_port_id = dpdk_ctx.get_route(conn.addr); - // if (dpdk_port_id < 0) { - // throw uhd::runtime_error( - //"Could not find a DPDK port with route to " + conn.addr); - //} - // auto recv = transport::dpdk_zero_copy::make(dpdk_ctx, - //(const unsigned int)dpdk_port_id, - // conn.addr, - // BOOST_STRINGIZE(X300_VITA_UDP_PORT), - //"0", - // default_buff_args, - // uhd::device_addr_t()); +// default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES; +// default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES; +// if (link_type == link_type_t::CTRL) { +//// Increasing number of recv frames here because ctrl_iface uses it +//// to determine how many control packets can be in flight before it +//// must wait for an ACK +// default_buff_args.num_recv_frames = +// uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; +//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { +// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE +//? GE_DATA_FRAME_SEND_SIZE +//: XGE_DATA_FRAME_SEND_SIZE; +// default_buff_args.send_frame_size = args.cast<size_t>( +//"send_frame_size", std::min(default_frame_size, send_mtu)); +// default_buff_args.num_send_frames = +// args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames); +// default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); +//} else if (xport_type == uhd::transport::link_type_t::RX_DATA) { +// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE +//? GE_DATA_FRAME_RECV_SIZE +//: XGE_DATA_FRAME_RECV_SIZE; +// default_buff_args.recv_frame_size = args.cast<size_t>( +//"recv_frame_size", std::min(default_frame_size, recv_mtu)); +// default_buff_args.num_recv_frames = +// args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames); +// default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); +//} + +// int dpdk_port_id = dpdk_ctx.get_route(conn.addr); +// if (dpdk_port_id < 0) { +// throw uhd::runtime_error( +//"Could not find a DPDK port with route to " + conn.addr); +//} +// auto recv = transport::dpdk_zero_copy::make(dpdk_ctx, +//(const unsigned int)dpdk_port_id, +// conn.addr, +// BOOST_STRINGIZE(X300_VITA_UDP_PORT), +//"0", +// default_buff_args, +// uhd::device_addr_t()); //#else UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP"); diff --git a/host/lib/usrp/x300/x300_pcie_mgr.cpp b/host/lib/usrp/x300/x300_pcie_mgr.cpp index 220a96530..6560f2770 100644 --- a/host/lib/usrp/x300/x300_pcie_mgr.cpp +++ b/host/lib/usrp/x300/x300_pcie_mgr.cpp @@ -275,13 +275,13 @@ uint32_t pcie_manager::allocate_pcie_dma_chan( const rfnoc::sep_id_t& /*remote_epid*/, const link_type_t /*link_type*/) { throw uhd::not_implemented_error("allocate_pcie_dma_chan()"); - //constexpr uint32_t CTRL_CHANNEL = 0; - //constexpr uint32_t ASYNC_MSG_CHANNEL = 1; - //constexpr uint32_t FIRST_DATA_CHANNEL = 2; - //if (link_type == uhd::usrp::device3_impl::CTRL) { - //return CTRL_CHANNEL; - //} else if (link_type == uhd::usrp::device3_impl::ASYNC_MSG) { - //return ASYNC_MSG_CHANNEL; + // constexpr uint32_t CTRL_CHANNEL = 0; + // constexpr uint32_t ASYNC_MSG_CHANNEL = 1; + // constexpr uint32_t FIRST_DATA_CHANNEL = 2; + // if (link_type == uhd::transport::link_type_t::CTRL) { + // return CTRL_CHANNEL; + //} else if (link_type == uhd::transport::link_type_t::ASYNC_MSG) { + // return ASYNC_MSG_CHANNEL; //} else { //// sid_t has no comparison defined, so we need to convert it uint32_t //uint32_t raw_sid = tx_sid.get(); @@ -330,50 +330,50 @@ both_links_t pcie_manager::get_links(link_type_t /*link_type*/, + std::to_string(local_device_id) + ", no such device associated with this motherboard!"); } - //zero_copy_xport_params default_buff_args; - //xports.endianness = ENDIANNESS_LITTLE; - //xports.lossless = true; - //const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid, xport_type); - //if (xport_type == uhd::usrp::device3_impl::CTRL) { - //// Transport for control stream - //if (not _ctrl_dma_xport) { - //// One underlying DMA channel will handle - //// all control traffic - //_ctrl_dma_xport = - //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS); - //} - //// Create a virtual control transport - //xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); - //} else if (xport_type == uhd::usrp::device3_impl::ASYNC_MSG) { - //// Transport for async message stream - //if (not _async_msg_dma_xport) { - //// One underlying DMA channel will handle - //// all async message traffic - //_async_msg_dma_xport = - //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS); - //} - //// Create a virtual async message transport - //xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); - //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) { - //default_buff_args.send_frame_size = args.cast<size_t>( - //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE)); - //default_buff_args.num_send_frames = - //args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES); - //default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); - //default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE; - //default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES; - //xports.recv = nirio_zero_copy::make( - //_rio_fpga_interface, dma_channel_num, default_buff_args); - //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) { - //default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE; - //default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES; - //default_buff_args.recv_frame_size = args.cast<size_t>( - //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE)); - //default_buff_args.num_recv_frames = - //args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES); - //default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); - //xports.recv = nirio_zero_copy::make( - //_rio_fpga_interface, dma_channel_num, default_buff_args); + // zero_copy_xport_params default_buff_args; + // xports.endianness = ENDIANNESS_LITTLE; + // xports.lossless = true; + // const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid, + // xport_type); if (xport_type == uhd::transport::link_type_t::CTRL) { + //// Transport for control stream + // if (not _ctrl_dma_xport) { + //// One underlying DMA channel will handle + //// all control traffic + //_ctrl_dma_xport = + // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS); + //} + //// Create a virtual control transport + // xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); + //} else if (xport_type == uhd::transport::link_type_t::ASYNC_MSG) { + //// Transport for async message stream + // if (not _async_msg_dma_xport) { + //// One underlying DMA channel will handle + //// all async message traffic + //_async_msg_dma_xport = + // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS); + //} + //// Create a virtual async message transport + // xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); + //} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { + // default_buff_args.send_frame_size = args.cast<size_t>( + //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE)); + // default_buff_args.num_send_frames = + // args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES); + // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); + // default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE; + // default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES; + // xports.recv = nirio_zero_copy::make( + //_rio_fpga_interface, dma_channel_num, default_buff_args); + //} else if (xport_type == uhd::transport::link_type_t::RX_DATA) { + // default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE; + // default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES; + // default_buff_args.recv_frame_size = args.cast<size_t>( + //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE)); + // default_buff_args.num_recv_frames = + // args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES); + // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); + // xports.recv = nirio_zero_copy::make( + //_rio_fpga_interface, dma_channel_num, default_buff_args); //} //xports.send = xports.recv; diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp deleted file mode 100644 index c280f77c5..000000000 --- a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp +++ /dev/null @@ -1,1577 +0,0 @@ -// -// Copyright 2015-2017 Ettus Research, A National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "x300_radio_ctrl_impl.hpp" -#include "x300_dboard_iface.hpp" -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/transport/chdr.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/dboard_iface.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/math.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhdlib/rfnoc/wb_iface_adapter.hpp> -#include <uhdlib/usrp/common/apply_corrections.hpp> -#include <uhdlib/usrp/cores/gpio_atr_3000.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/date_time/posix_time/posix_time_io.hpp> -#include <boost/make_shared.hpp> -#include <chrono> -#include <thread> -#include <bitset> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::rfnoc; -using namespace uhd::usrp::x300; - -static const size_t IO_MASTER_RADIO = 0; - -namespace { - -gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree) -{ - gain_fcns_t gain_fcns; - gain_fcns.get_range = [subtree]() { - return subtree->access<meta_range_t>("range").get(); - }; - gain_fcns.get_value = [subtree]() { return subtree->access<double>("value").get(); }; - gain_fcns.set_value = [subtree](const double gain) { - subtree->access<double>("value").set(gain); - }; - return gain_fcns; -} - -} // namespace - -/**************************************************************************** - * Structors - ***************************************************************************/ -UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(x300_radio_ctrl) -, _ignore_cal_file(false) -{ - UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::ctor() "; - - //////////////////////////////////////////////////////////////////// - // Set up basic info - //////////////////////////////////////////////////////////////////// - _radio_type = (get_block_id().get_block_count() == 0) ? PRIMARY : SECONDARY; - _radio_slot = (get_block_id().get_block_count() == 0) ? "A" : "B"; - _radio_clk_rate = _tree->access<double>("master_clock_rate").get(); - - //////////////////////////////////////////////////////////////////// - // Set up peripherals - //////////////////////////////////////////////////////////////////// - wb_iface::sptr ctrl = _get_ctrl(IO_MASTER_RADIO); - _regs = boost::make_shared<radio_regmap_t>(_radio_type == PRIMARY ? 0 : 1); - _regs->initialize(*ctrl, true); - - // Only Radio0 has the ADC/DAC reset bits. Those bits are reserved for Radio1 - if (_radio_type == PRIMARY) { - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - _regs->misc_outs_reg.flush(); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1); - _regs->misc_outs_reg.flush(); - } - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 1); - - //////////////////////////////////////////////////////////////// - // Setup peripherals - //////////////////////////////////////////////////////////////// - _spi = spi_core_3000::make(ctrl, - regs::sr_addr(radio_ctrl_impl::regs::SPI), - regs::rb_addr(radio_ctrl_impl::regs::RB_SPI)); - _adc = x300_adc_ctrl::make(_spi, DB_ADC_SEN); - _dac = x300_dac_ctrl::make(_spi, DB_DAC_SEN, _radio_clk_rate); - - if (_radio_type == PRIMARY) { - _fp_gpio = gpio_atr::gpio_atr_3000::make( - ctrl, regs::sr_addr(regs::FP_GPIO), regs::rb_addr(regs::RB_FP_GPIO)); - for (const gpio_atr::gpio_attr_map_t::value_type attr : gpio_atr::gpio_attr_map) { - switch (attr.first) { - case usrp::gpio_atr::GPIO_SRC: - _tree - ->create<std::vector<std::string>>( - fs_path("gpio") / "FP0" / attr.second) - .set(std::vector<std::string>( - 32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) - .add_coerced_subscriber([this](const std::vector<std::string>&) { - throw uhd::runtime_error("This device does not support " - "setting the GPIO_SRC attribute."); - }); - break; - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: - _tree - ->create<std::vector<std::string>>( - fs_path("gpio") / "FP0" / attr.second) - .set(std::vector<std::string>( - 32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) - .add_coerced_subscriber( - [this, attr](const std::vector<std::string> str_val) { - uint32_t val = 0; - for (size_t i = 0; i < str_val.size(); i++) { - val += usrp::gpio_atr::gpio_attr_value_pair - .at(attr.second) - .at(str_val[i]) - << i; - } - _fp_gpio->set_gpio_attr(attr.first, val); - }); - break; - case usrp::gpio_atr::GPIO_READBACK: - _tree->create<uint32_t>(fs_path("gpio") / "FP0" / "READBACK") - .set_publisher([this]() { return _fp_gpio->read_gpio(); }); - break; - default: - _tree->create<uint32_t>(fs_path("gpio") / "FP0" / attr.second) - .set(0) - .add_coerced_subscriber([this, attr](const uint32_t val) { - _fp_gpio->set_gpio_attr(attr.first, val); - }); - } - } - } - - //////////////////////////////////////////////////////////////// - // create legacy codec control objects - //////////////////////////////////////////////////////////////// - _tree->create<int>( - "rx_codecs" / _radio_slot / "gains"); // phony property so this dir exists - _tree->create<int>( - "tx_codecs" / _radio_slot / "gains"); // phony property so this dir exists - _tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("ads62p48"); - _tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("ad9146"); - - _tree->create<meta_range_t>("rx_codecs" / _radio_slot / "gains" / "digital" / "range") - .set(meta_range_t(0, 6.0, 0.5)); - _tree->create<double>("rx_codecs" / _radio_slot / "gains" / "digital" / "value") - .add_coerced_subscriber(boost::bind(&x300_adc_ctrl::set_gain, _adc, _1)) - .set(0); - - //////////////////////////////////////////////////////////////// - // create front-end objects - //////////////////////////////////////////////////////////////// - for (size_t i = 0; i < _get_num_radios(); i++) { - _leds[i] = gpio_atr::gpio_atr_3000::make_write_only( - _get_ctrl(i), regs::sr_addr(regs::LEDS)); - _leds[i]->set_atr_mode( - usrp::gpio_atr::MODE_ATR, usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL); - - _rx_fe_map[i].core = rx_frontend_core_3000::make( - _get_ctrl(i), regs::sr_addr(x300_regs::RX_FE_BASE)); - _rx_fe_map[i].core->set_adc_rate(_radio_clk_rate); - _rx_fe_map[i].core->set_dc_offset(rx_frontend_core_3000::DEFAULT_DC_OFFSET_VALUE); - _rx_fe_map[i].core->set_dc_offset_auto( - rx_frontend_core_3000::DEFAULT_DC_OFFSET_ENABLE); - _rx_fe_map[i].core->populate_subtree( - _tree->subtree(_root_path / "rx_fe_corrections" / i)); - - _tx_fe_map[i].core = tx_frontend_core_200::make( - _get_ctrl(i), regs::sr_addr(x300_regs::TX_FE_BASE)); - _tx_fe_map[i].core->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); - _tx_fe_map[i].core->set_iq_balance( - tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - _tx_fe_map[i].core->populate_subtree( - _tree->subtree(_root_path / "tx_fe_corrections" / i)); - - //////////////////////////////////////////////////////////////// - // Bind the daughterboard command time to the motherboard level property - //////////////////////////////////////////////////////////////// - - if (_tree->exists(fs_path("time") / "cmd")) { - _tree->access<time_spec_t>(fs_path("time") / "cmd") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_fe_cmd_time, this, _1, i)); - } - } - - //////////////////////////////////////////////////////////////// - // Update default SPP (overwrites the default value from the XML file) - //////////////////////////////////////////////////////////////// - const size_t max_bytes_header = - uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); - const size_t default_spp = - (_tree->access<size_t>("mtu/recv").get() - max_bytes_header) - / (2 * sizeof(int16_t)); - _tree->access<int>(get_arg_path("spp") / "value").set(default_spp); -} - -x300_radio_ctrl_impl::~x300_radio_ctrl_impl() -{ - UHD_SAFE_CALL( - // Tear down our part of the tree: - _tree->remove(fs_path("rx_codecs" / _radio_slot)); - _tree->remove(fs_path("tx_codecs" / _radio_slot)); - _tree->remove(_root_path / "rx_fe_corrections"); - _tree->remove(_root_path / "tx_fe_corrections"); - if (_radio_type == PRIMARY) { - for (const gpio_atr::gpio_attr_map_t::value_type attr : - gpio_atr::gpio_attr_map) { - _tree->remove(fs_path("gpio") / "FP0" / attr.second); - } - } - - // Reset peripherals - if (_radio_type == PRIMARY) { - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - } _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 0); - _regs->misc_outs_reg.flush();) -} - -/**************************************************************************** - * API calls - ***************************************************************************/ -double x300_radio_ctrl_impl::set_rate(double rate) -{ - const double actual_rate = get_rate(); - if (not uhd::math::frequencies_are_equal(rate, actual_rate)) { - UHD_LOGGER_WARNING("X300 RADIO") - << "Requesting invalid sampling rate from device: " << rate / 1e6 - << " MHz. Actual rate is: " << actual_rate / 1e6 << " MHz."; - } - // On X3x0, tick rate can't actually be changed at runtime - return actual_rate; -} - -void x300_radio_ctrl_impl::set_fe_cmd_time(const time_spec_t& time, const size_t chan) -{ - if (_tree->exists(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd"))) { - _tree - ->access<time_spec_t>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd")) - .set(time); - } -} - -void x300_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan) -{ - _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .set(ant); -} - -std::string x300_radio_ctrl_impl::get_tx_antenna(const size_t chan) -{ - return _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .get(); -} - -void x300_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan) -{ - _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .set(ant); -} - -std::string x300_radio_ctrl_impl::get_rx_antenna(const size_t chan) -{ - return _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .set(freq) - .get(); -} - -double x300_radio_ctrl_impl::get_tx_frequency(const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .set(freq) - .get(); -} - -double x300_radio_ctrl_impl::get_rx_frequency(const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) -{ - return _tree - ->access<double>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value")) - .set(bandwidth) - .get(); -} - -double x300_radio_ctrl_impl::get_rx_bandwidth(const size_t chan) -{ - return _tree - ->access<double>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) -{ - if (_tx_gain_groups.count(chan)) { - auto& gg = _tx_gain_groups.at(chan); - gg->set_value(gain); - return radio_ctrl_impl::set_tx_gain(gg->get_value(), chan); - } - return radio_ctrl_impl::set_tx_gain(0.0, chan); -} - -double x300_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) -{ - auto& gg = _rx_gain_groups.at(chan); - gg->set_value(gain); - return radio_ctrl_impl::set_rx_gain(gg->get_value(), chan); -} - -double x300_radio_ctrl_impl::get_rx_gain(const size_t chan) -{ - return _rx_gain_groups.at(chan)->get_value(); -} - -std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_names(const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - std::vector<std::string> lo_names; - if (_tree->exists(rx_fe_fe_root / "los")) { - for (const std::string& name : _tree->list(rx_fe_fe_root / "los")) { - lo_names.push_back(name); - } - } - return lo_names; -} - -std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_sources( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree - ->access<std::vector<std::string>>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "options") - .get(); - } else { - return std::vector<std::string>(); - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<std::vector<std::string>>( - rx_fe_fe_root / "los" / name / "source" / "options") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s) then it can only be internal - return std::vector<std::string>(1, "internal"); - } -} - -void x300_radio_ctrl_impl::set_rx_lo_source( - const std::string& src, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - _tree - ->access<std::string>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "value") - .set(src); - } else { - for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) { - this->set_rx_lo_source(src, n, chan); - } - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree - ->access<std::string>( - rx_fe_fe_root / "los" / name / "source" / "value") - .set(src); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -const std::string x300_radio_ctrl_impl::get_rx_lo_source( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree - ->access<std::string>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "value") - .get(); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<std::string>( - rx_fe_fe_root / "los" / name / "source" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s) then it can only be internal - return "internal"; - } -} - -void x300_radio_ctrl_impl::set_rx_lo_export_enabled( - bool enabled, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export") - .set(enabled); - } else { - for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) { - this->set_rx_lo_export_enabled(enabled, n, chan); - } - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").set(enabled); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -bool x300_radio_ctrl_impl::get_rx_lo_export_enabled( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export").get(); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s), assume it cannot export - return false; - } -} - -double x300_radio_ctrl_impl::set_rx_lo_freq( - double freq, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency must be set for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .set(freq); - return _tree - ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -double x300_radio_ctrl_impl::get_rx_lo_freq(const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency must be retrieved for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // Return actual RF frequency if the daughterboard doesn't expose it's LO(s) - return _tree->access<double>(rx_fe_fe_root / "freq" / " value").get(); - } -} - -freq_range_t x300_radio_ctrl_impl::get_rx_lo_freq_range( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency range must be retrieved for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<freq_range_t>( - rx_fe_fe_root / "los" / name / "freq" / "range") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // Return the actual RF range if the daughterboard doesn't expose it's LO(s) - return _tree->access<meta_range_t>(rx_fe_fe_root / "freq" / "range").get(); - } -} - -template <typename map_type> -static size_t _get_chan_from_map(std::map<size_t, map_type> map, const std::string& fe) -{ - for (auto it = map.begin(); it != map.end(); ++it) { - if (it->second.db_fe_name == fe) { - return it->first; - } - } - throw uhd::runtime_error( - str(boost::format("Invalid daughterboard frontend name: %s") % fe)); -} - -size_t x300_radio_ctrl_impl::get_chan_from_dboard_fe( - const std::string& fe, const uhd::direction_t direction) -{ - switch (direction) { - case uhd::TX_DIRECTION: - return _get_chan_from_map(_tx_fe_map, fe); - case uhd::RX_DIRECTION: - return _get_chan_from_map(_rx_fe_map, fe); - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -std::string x300_radio_ctrl_impl::get_dboard_fe_from_chan( - const size_t chan, const uhd::direction_t direction) -{ - switch (direction) { - case uhd::TX_DIRECTION: - return _tx_fe_map.at(chan).db_fe_name; - case uhd::RX_DIRECTION: - return _rx_fe_map.at(chan).db_fe_name; - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -double x300_radio_ctrl_impl::get_output_samp_rate(size_t chan) -{ - // TODO: chan should never be ANY_PORT, but due to our current graph search - // method, this can actually happen: - if (chan == ANY_PORT) { - chan = 0; - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_is_streamer_active(uhd::RX_DIRECTION, chan)) { - chan = i; - break; - } - } - } - return _rx_fe_map.at(chan).core->get_output_rate(); -} - -std::vector<std::string> x300_radio_ctrl_impl::get_gpio_banks() const -{ - std::vector<std::string> banks{"RX", "TX"}; - // These pairs are the same, but RXA/TXA are from pre-rfnoc era and are kept for - // backward compat: - banks.push_back("RX" + _radio_slot); - banks.push_back("TX" + _radio_slot); - if (_fp_gpio) { - banks.push_back("FP0"); - } - return banks; -} - -void x300_radio_ctrl_impl::set_gpio_attr(const std::string& bank, - const std::string& attr, - const uint32_t value, - const uint32_t mask) -{ - if (bank == "FP0" and _fp_gpio) { - std::vector<std::string> attr_value; - const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr); - switch (attr_type) { - case usrp::gpio_atr::GPIO_SRC: - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: { - attr_value = - _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr) - .get(); - std::bitset<32> bit_mask = std::bitset<32>(mask); - std::bitset<32> new_value = std::bitset<32>(value); - for (size_t i = 0; i < bit_mask.size(); i++) { - if (bit_mask[i] == 1) { - attr_value[i] = - usrp::gpio_atr::attr_value_map.at(attr_type).at(new_value[i]); - } - } - _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr) - .set(attr_value); - return; - } break; - default: { - const uint32_t curr_value = - _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get(); - uint32_t new_value = (curr_value & ~mask) | (value & mask); - _tree->access<uint32_t>(fs_path("gpio") / bank / attr).set(new_value); - } break; - } - } - if (bank.size() > 2 and bank[1] == 'X') { - const std::string name = bank.substr(2); - const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX - : dboard_iface::UNIT_TX; - dboard_iface::sptr iface = - _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get(); - if (attr == "CTRL") - iface->set_pin_ctrl(unit, uint16_t(value), uint16_t(mask)); - if (attr == "DDR") - iface->set_gpio_ddr(unit, uint16_t(value), uint16_t(mask)); - if (attr == "OUT") - iface->set_gpio_out(unit, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_0X") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_IDLE, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_RX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_RX_ONLY, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_TX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_TX_ONLY, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_XX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_FULL_DUPLEX, uint16_t(value), uint16_t(mask)); - } -} - -uint32_t x300_radio_ctrl_impl::get_gpio_attr( - const std::string& bank, const std::string& attr) -{ - if (bank == "FP0" and _fp_gpio) { - const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr); - switch(attr_type) { - case usrp::gpio_atr::GPIO_SRC: - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: { - auto str_val = - _tree->access<std::vector<std::string>>( - fs_path("gpio") / bank / attr).get(); - uint32_t val = 0; - for (size_t i = 0; i < str_val.size(); i++) { - val += usrp::gpio_atr::gpio_attr_value_pair.at(attr).at(str_val[i]) << i; - } - return val; - } - break; - default: { - return _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get(); - } - break; - } - } - if (bank.size() > 2 and bank[1] == 'X') { - const std::string name = bank.substr(2); - const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX - : dboard_iface::UNIT_TX; - dboard_iface::sptr iface = - _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get(); - if (attr == "CTRL") - return iface->get_pin_ctrl(unit); - if (attr == "DDR") - return iface->get_gpio_ddr(unit); - if (attr == "OUT") - return iface->get_gpio_out(unit); - if (attr == "ATR_0X") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_IDLE); - if (attr == "ATR_RX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_RX_ONLY); - if (attr == "ATR_TX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_TX_ONLY); - if (attr == "ATR_XX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_FULL_DUPLEX); - if (attr == "READBACK") - return iface->read_gpio(unit); - } - return 0; -} - -/**************************************************************************** - * Radio control and setup - ***************************************************************************/ -void x300_radio_ctrl_impl::setup_radio(uhd::i2c_iface::sptr zpu_i2c, - x300_clock_ctrl::sptr clock, - bool ignore_cal_file, - bool verbose) -{ - _self_cal_adc_capture_delay(verbose); - _ignore_cal_file = ignore_cal_file; - - //////////////////////////////////////////////////////////////////// - // create RF frontend interfacing - //////////////////////////////////////////////////////////////////// - static const size_t BASE_ADDR = 0x50; - static const size_t RX_EEPROM_ADDR = 0x5; - static const size_t TX_EEPROM_ADDR = 0x4; - static const size_t GDB_EEPROM_ADDR = 0x1; - const static std::vector<size_t> EEPROM_ADDRS{ - RX_EEPROM_ADDR, TX_EEPROM_ADDR, GDB_EEPROM_ADDR}; - const static std::vector<std::string> EEPROM_PATHS{ - "rx_eeprom", "tx_eeprom", "gdb_eeprom"}; - - const size_t DB_OFFSET = (_radio_slot == "A") ? 0x0 : 0x2; - const fs_path db_path = ("dboards" / _radio_slot); - for (size_t i = 0; i < EEPROM_ADDRS.size(); i++) { - const size_t addr = EEPROM_ADDRS[i] + DB_OFFSET; - // Load EEPROM - _db_eeproms[addr].load(*zpu_i2c, BASE_ADDR | addr); - // Add to tree - _tree->create<dboard_eeprom_t>(db_path / EEPROM_PATHS[i]) - .set(_db_eeproms[addr]) - .add_coerced_subscriber(boost::bind(&x300_radio_ctrl_impl::_set_db_eeprom, - this, - zpu_i2c, - (BASE_ADDR | addr), - _1)); - } - - // create a new dboard interface - x300_dboard_iface_config_t db_config; - db_config.gpio = gpio_atr::db_gpio_atr_3000::make(_get_ctrl(IO_MASTER_RADIO), - radio_ctrl_impl::regs::sr_addr(radio_ctrl_impl::regs::GPIO), - radio_ctrl_impl::regs::rb_addr(radio_ctrl_impl::regs::RB_DB_GPIO)); - db_config.spi = _spi; - db_config.rx_spi_slaveno = DB_RX_SEN; - db_config.tx_spi_slaveno = DB_TX_SEN; - db_config.i2c = zpu_i2c; - db_config.clock = clock; - db_config.which_rx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_RX - : X300_CLOCK_WHICH_DB1_RX; - db_config.which_tx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_TX - : X300_CLOCK_WHICH_DB1_TX; - db_config.dboard_slot = (_radio_slot == "A") ? 0 : 1; - db_config.cmd_time_ctrl = _get_ctrl(IO_MASTER_RADIO); - - // create a new dboard manager - boost::shared_ptr<x300_dboard_iface> db_iface = - boost::make_shared<x300_dboard_iface>(db_config); - _db_manager = dboard_manager::make(_db_eeproms[RX_EEPROM_ADDR + DB_OFFSET], - _db_eeproms[TX_EEPROM_ADDR + DB_OFFSET], - _db_eeproms[GDB_EEPROM_ADDR + DB_OFFSET], - db_iface, - _tree->subtree(db_path), - true // defer daughterboard intitialization - ); - - size_t rx_chan = 0, tx_chan = 0; - for (const std::string& fe : _db_manager->get_rx_frontends()) { - if (rx_chan >= _get_num_radios()) { - break; - } - _rx_fe_map[rx_chan].db_fe_name = fe; - db_iface->add_rx_fe(fe, _rx_fe_map[rx_chan].core); - const fs_path fe_path(db_path / "rx_frontends" / fe); - const std::string conn = _tree->access<std::string>(fe_path / "connection").get(); - const double if_freq = - (_tree->exists(fe_path / "if_freq/value")) - ? _tree->access<double>(fe_path / "if_freq/value").get() - : 0.0; - _rx_fe_map[rx_chan].core->set_fe_connection(usrp::fe_connection_t(conn, if_freq)); - rx_chan++; - } - for (const std::string& fe : _db_manager->get_tx_frontends()) { - if (tx_chan >= _get_num_radios()) { - break; - } - _tx_fe_map[tx_chan].db_fe_name = fe; - const fs_path fe_path(db_path / "tx_frontends" / fe); - const std::string conn = _tree->access<std::string>(fe_path / "connection").get(); - _tx_fe_map[tx_chan].core->set_mux(conn); - tx_chan++; - } - UHD_ASSERT_THROW(rx_chan or tx_chan); - - // Initialize the daughterboards now that frontend cores and connections exist - _db_manager->initialize_dboards(); - - // now that dboard is created -- register into rx antenna event - if (not _rx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists(db_path / "rx_frontends" / _rx_fe_map[i].db_fe_name - / "antenna" / "value")) { - // We need a desired subscriber for antenna/value because the experts - // don't coerce that property. - _tree - ->access<std::string>(db_path / "rx_frontends" - / _rx_fe_map[i].db_fe_name / "antenna" - / "value") - .add_desired_subscriber(boost::bind( - &x300_radio_ctrl_impl::_update_atr_leds, this, _1, i)); - _update_atr_leds(_tree - ->access<std::string>(db_path / "rx_frontends" - / _rx_fe_map[i].db_fe_name - / "antenna" / "value") - .get(), - i); - } else { - _update_atr_leds("", i); // init anyway, even if never called - } - } - } - - // bind frontend corrections to the dboard freq props - const fs_path db_tx_fe_path = db_path / "tx_frontends"; - if (not _tx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists( - db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) { - _tree - ->access<double>( - db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_tx_fe_corrections, - this, - db_path, - _root_path / "tx_fe_corrections" / _tx_fe_map[i].db_fe_name, - _1)); - } - } - } - const fs_path db_rx_fe_path = db_path / "rx_frontends"; - if (not _rx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists( - db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) { - _tree - ->access<double>( - db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_rx_fe_corrections, - this, - db_path, - _root_path / "rx_fe_corrections" / _tx_fe_map[i].db_fe_name, - _1)); - } - } - } - - //////////////////////////////////////////////////////////////// - // Set tick rate - //////////////////////////////////////////////////////////////// - const double tick_rate = _tree->access<double>("tick_rate").get(); - radio_ctrl_impl::set_rate(tick_rate); - - //////////////////////////////////////////////////////////////// - // Set gain groups - // Note: The actual gain control comes from the daughterboard drivers, thus, - // we need to call into the prop tree at the appropriate location in order - // to modify the gains. - //////////////////////////////////////////////////////////////// - // TX - for (size_t chan = 0; chan < _num_tx_channels; chan++) { - fs_path rf_gains_path(db_tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "gains"); - if (!_tree->exists(rf_gains_path)) { - continue; - } - - std::vector<std::string> gain_stages = _tree->list(rf_gains_path); - if (gain_stages.empty()) { - continue; - } - - // DAC does not have a gain path - auto gg = gain_group::make(); - for (const auto& name : gain_stages) { - gg->register_fcns(name, - make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)), - 1 /* high prio */); - } - _tx_gain_groups[chan] = gg; - } - // RX - for (size_t chan = 0; chan < _num_rx_channels; chan++) { - fs_path rf_gains_path(db_rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "gains"); - fs_path adc_gains_path("rx_codecs" / _radio_slot / "gains"); - - auto gg = gain_group::make(); - // ADC also has a gain path - for (const auto& name : _tree->list(adc_gains_path)) { - gg->register_fcns("ADC-" + name, - make_gain_fcns_from_subtree(_tree->subtree(adc_gains_path / name)), - 0 /* low prio */); - } - if (_tree->exists(rf_gains_path)) { - for (const auto& name : _tree->list(rf_gains_path)) { - gg->register_fcns(name, - make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)), - 1 /* high prio */); - } - } - _rx_gain_groups[chan] = gg; - } -} - -void x300_radio_ctrl_impl::set_rx_fe_corrections( - const fs_path& db_path, const fs_path& rx_fe_corr_path, const double lo_freq) -{ - if (not _ignore_cal_file) { - apply_rx_fe_corrections(_tree, db_path, rx_fe_corr_path, lo_freq); - } -} - -void x300_radio_ctrl_impl::set_tx_fe_corrections( - const fs_path& db_path, const fs_path& tx_fe_corr_path, const double lo_freq) -{ - if (not _ignore_cal_file) { - apply_tx_fe_corrections(_tree, db_path, tx_fe_corr_path, lo_freq); - } -} - -void x300_radio_ctrl_impl::reset_codec() -{ - if (_radio_type == PRIMARY) { // ADC/DAC reset lines only exist in Radio0 - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - _regs->misc_outs_reg.flush(); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1); - _regs->misc_outs_reg.flush(); - } - UHD_ASSERT_THROW(bool(_adc)); - UHD_ASSERT_THROW(bool(_dac)); - _adc->reset(); - _dac->reset(); -} - -void x300_radio_ctrl_impl::self_test_adc(uint32_t ramp_time_ms) -{ - // Bypass all front-end corrections - for (size_t i = 0; i < _get_num_radios(); i++) { - _rx_fe_map[i].core->bypass_all(true); - } - - // Test basic patterns - _adc->set_test_word("ones", "ones"); - _check_adc(0xfffcfffc); - _adc->set_test_word("zeros", "zeros"); - _check_adc(0x00000000); - _adc->set_test_word("ones", "zeros"); - _check_adc(0xfffc0000); - _adc->set_test_word("zeros", "ones"); - _check_adc(0x0000fffc); - for (size_t k = 0; k < 14; k++) { - _adc->set_test_word("zeros", "custom", 1 << k); - _check_adc(1 << (k + 2)); - } - for (size_t k = 0; k < 14; k++) { - _adc->set_test_word("custom", "zeros", 1 << k); - _check_adc(1 << (k + 18)); - } - - // Turn on ramp pattern test - _adc->set_test_word("ramp", "ramp"); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - // Sleep added for SPI transactions to finish and ramp to start before checker is - // enabled. - std::this_thread::sleep_for(std::chrono::microseconds(1000)); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - - std::this_thread::sleep_for(std::chrono::milliseconds(ramp_time_ms)); - _regs->misc_ins_reg.refresh(); - - std::string i_status, q_status; - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED)) - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR)) - i_status = "Bit Errors!"; - else - i_status = "Good"; - else - i_status = "Not Locked!"; - - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED)) - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR)) - q_status = "Bit Errors!"; - else - q_status = "Good"; - else - q_status = "Not Locked!"; - - // Return to normal mode - _adc->set_test_word("normal", "normal"); - - if ((i_status != "Good") or (q_status != "Good")) { - throw uhd::runtime_error( - (boost::format( - "ADC self-test failed for %s. Ramp checker status: {ADC_A=%s, ADC_B=%s}") - % unique_id() % i_status % q_status) - .str()); - } - - // Restore front-end corrections - for (size_t i = 0; i < _get_num_radios(); i++) { - _rx_fe_map[i].core->bypass_all(false); - } -} - -void x300_radio_ctrl_impl::extended_adc_test( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, double duration_s) -{ - static const size_t SECS_PER_ITER = 5; - UHD_LOGGER_INFO("X300 RADIO") - << boost::format( - "Running Extended ADC Self-Test (Duration=%.0fs, %ds/iteration)...") - % duration_s % SECS_PER_ITER; - - size_t num_iters = static_cast<size_t>(ceil(duration_s / SECS_PER_ITER)); - size_t num_failures = 0; - for (size_t iter = 0; iter < num_iters; iter++) { - // Run self-test - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("Extended ADC Self-Test Iteration %06d... ") % (iter + 1); - try { - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->self_test_adc((SECS_PER_ITER * 1000) / radios.size()); - } - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("Extended ADC Self-Test Iteration %06d passed ") - % (iter + 1); - } catch (std::exception& e) { - num_failures++; - UHD_LOGGER_ERROR("X300 RADIO") << e.what(); - } - } - if (num_failures == 0) { - UHD_LOGGER_INFO("X300 RADIO") << "Extended ADC Self-Test PASSED"; - } else { - throw uhd::runtime_error( - (boost::format("Extended ADC Self-Test FAILED!!! (%d/%d failures)\n") - % num_failures % num_iters) - .str()); - } -} - -void x300_radio_ctrl_impl::synchronize_dacs( - const std::vector<x300_radio_ctrl_impl::sptr>& radios) -{ - if (radios.size() < 2) - return; // Nothing to synchronize - - //**PRECONDITION** - // This function assumes that all the VITA times in "radios" are synchronized - // to a common reference. Currently, this function is called in get_tx_stream - // which also has the same precondition. - - // Get a rough estimate of the cumulative command latency - boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time(); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->user_reg_read64( - regs::RB_TIME_NOW); // Discard value. We are just timing the call - } - boost::posix_time::time_duration t_elapsed = - boost::posix_time::microsec_clock::local_time() - t_start; - - // Add 100% of headroom + uncertainty to the command time - uint64_t t_sync_us = - (t_elapsed.total_microseconds() * 2) + 16000 /*Scheduler latency*/; - - std::string err_str; - // Try to sync 3 times before giving up - for (size_t attempt = 0; attempt < 3; attempt++) { - try { - // Reinitialize and resync all DACs - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->_dac->sync(); - } - - // Set tick rate and make sure FRAMEP/N is 0 - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_tick_rate( - radios[i]->_radio_clk_rate, IO_MASTER_RADIO); - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); - } - - // Pick radios[0] as the time reference. - uhd::time_spec_t sync_time = radios[0]->_time64->get_time_now() - + uhd::time_spec_t(((double)t_sync_us) / 1e6); - - // Send the sync command - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_time(sync_time, IO_MASTER_RADIO); - // Arm FRAMEP/N sync pulse by asserting a rising edge - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 1); - } - - // Reset FRAMEP/N to 0 after 2 clock cycles - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_time( - sync_time + (2.0 / radios[i]->_radio_clk_rate), IO_MASTER_RADIO); - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); - radios[i]->set_command_time(uhd::time_spec_t(0.0), IO_MASTER_RADIO); - } - - // Wait and check status - std::this_thread::sleep_for(std::chrono::microseconds(t_sync_us)); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->_dac->verify_sync(); - } - - return; - } catch (const uhd::runtime_error& e) { - err_str = e.what(); - UHD_LOGGER_TRACE("X300 RADIO") << "Retrying DAC synchronization: " << err_str; - } - } - throw uhd::runtime_error(err_str); -} - -double x300_radio_ctrl_impl::self_cal_adc_xfer_delay( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, - x300_clock_ctrl::sptr clock, - boost::function<void(double)> wait_for_clk_locked, - bool apply_delay) -{ - UHD_LOGGER_INFO("X300 RADIO") << "Running ADC transfer delay self-cal: "; - - // Effective resolution of the self-cal. - static const size_t NUM_DELAY_STEPS = 100; - - double master_clk_period = (1.0e9 / clock->get_master_clock_rate()); // in ns - double delay_start = 0.0; - double delay_range = 2 * master_clk_period; - double delay_incr = delay_range / NUM_DELAY_STEPS; - - double cached_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_ADC0); - double fpga_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_FPGA); - - // Iterate through several values of delays and measure ADC data integrity - std::vector<std::pair<double, bool>> results; - for (size_t i = 0; i < NUM_DELAY_STEPS; i++) { - // Delay the ADC clock (will set both Ch0 and Ch1 delays) - double delay = - clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, delay_incr * i + delay_start); - wait_for_clk_locked(0.1); - - uint32_t err_code = 0; - for (size_t r = 0; r < radios.size(); r++) { - // Test each channel (I and Q) individually so as to not accidentally trigger - // on the data from the other channel if there is a swap - - // -- Test I Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - radios[r]->_adc->set_test_word("ramp", "ones"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 50ms @ 200MHz = 10 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - if (radios[r]->_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED)) { - err_code += radios[r]->_regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - // -- Test Q Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - radios[r]->_adc->set_test_word("ones", "ramp"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 50ms @ 200MHz = 10 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - if (radios[r]->_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED)) { - err_code += radios[r]->_regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - } - // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("XferDelay=%fns, Error=%d") % - // delay % err_code); - results.push_back(std::pair<double, bool>(delay, err_code == 0)); - } - - // Calculate the valid window - int win_start_idx = -1, win_stop_idx = -1, cur_start_idx = -1, cur_stop_idx = -1; - for (size_t i = 0; i < results.size(); i++) { - std::pair<double, bool>& item = results[i]; - if (item.second) { // If data is stable - if (cur_start_idx == -1) { // This is the first window - cur_start_idx = i; - cur_stop_idx = i; - } else { // We are extending the window - cur_stop_idx = i; - } - } else { - if (cur_start_idx == -1) { // We haven't yet seen valid data - // Do nothing - } else if (win_start_idx == -1) { // We passed the first valid window - win_start_idx = cur_start_idx; - win_stop_idx = cur_stop_idx; - } else { // Update cached window if current window is larger - double cur_win_len = - results[cur_stop_idx].first - results[cur_start_idx].first; - double cached_win_len = - results[win_stop_idx].first - results[win_start_idx].first; - if (cur_win_len > cached_win_len) { - win_start_idx = cur_start_idx; - win_stop_idx = cur_stop_idx; - } - } - // Reset current window - cur_start_idx = -1; - cur_stop_idx = -1; - } - } - if (win_start_idx == -1) { - throw uhd::runtime_error( - "self_cal_adc_xfer_delay: Self calibration failed. Convergence error."); - } - - double win_center = - (results[win_stop_idx].first + results[win_start_idx].first) / 2.0; - double win_length = results[win_stop_idx].first - results[win_start_idx].first; - if (win_length < master_clk_period / 4) { - throw uhd::runtime_error( - "self_cal_adc_xfer_delay: Self calibration failed. Valid window too narrow."); - } - - // Cycle slip the relative delay by a clock cycle to prevent sample misalignment - // fpga_clk_delay > 0 and 0 < win_center < 2*(1/MCR) so one cycle slip is all we need - bool cycle_slip = (win_center - fpga_clk_delay >= master_clk_period); - if (cycle_slip) { - win_center -= master_clk_period; - } - - if (apply_delay) { - // Apply delay - win_center = clock->set_clock_delay( - X300_CLOCK_WHICH_ADC0, win_center); // Sets ADC0 and ADC1 - wait_for_clk_locked(0.1); - // Validate - for (size_t r = 0; r < radios.size(); r++) { - radios[r]->self_test_adc(2000); - } - } else { - // Restore delay - clock->set_clock_delay( - X300_CLOCK_WHICH_ADC0, cached_clk_delay); // Sets ADC0 and ADC1 - } - - // Teardown - for (size_t r = 0; r < radios.size(); r++) { - radios[r]->_adc->set_test_word("normal", "normal"); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - } - UHD_LOGGER_INFO("X300 RADIO") - << (boost::format( - "ADC transfer delay self-cal done (FPGA->ADC=%.3fns%s, Window=%.3fns)") - % (win_center - fpga_clk_delay) % (cycle_slip ? " +cyc" : "") - % win_length); - - return win_center; -} -/**************************************************************************** - * Helpers - ***************************************************************************/ -void x300_radio_ctrl_impl::_update_atr_leds(const std::string& rx_ant, const size_t chan) -{ - // The "RX1" port is used by TwinRX and the "TX/RX" port is used by all - // other full-duplex dboards. We need to handle both here. - const bool is_txrx = (rx_ant == "TX/RX" or rx_ant == "RX1"); - const int TXRX_RX = (1 << 0); - const int TXRX_TX = (1 << 1); - const int RX2_RX = (1 << 2); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_IDLE, 0); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, is_txrx ? TXRX_RX : RX2_RX); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, TXRX_TX); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, RX2_RX | TXRX_TX); -} - -void x300_radio_ctrl_impl::_self_cal_adc_capture_delay(bool print_status) -{ - if (print_status) - UHD_LOGGER_INFO("X300 RADIO") << "Running ADC capture delay self-cal..."; - - static const uint32_t NUM_DELAY_STEPS = 32; // The IDELAYE2 element has 32 steps - static const uint32_t NUM_RETRIES = - 2; // Retry self-cal if it fails in warmup situations - static const int32_t MIN_WINDOW_LEN = 4; - - int32_t win_start = -1, win_stop = -1; - uint32_t iter = 0; - while (iter++ < NUM_RETRIES) { - for (uint32_t dly_tap = 0; dly_tap < NUM_DELAY_STEPS; dly_tap++) { - // Apply delay - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, dly_tap); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0); - - uint32_t err_code = 0; - - // -- Test I Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - _adc->set_test_word("ramp", "ones"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 5ms @ 200MHz = 1 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - if (_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_LOCKED)) { - err_code += _regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - // -- Test Q Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - _adc->set_test_word("ones", "ramp"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 5ms @ 200MHz = 1 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - if (_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_LOCKED)) { - err_code += _regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - if (err_code == 0) { - if (win_start == -1) { // This is the first window - win_start = dly_tap; - win_stop = dly_tap; - } else { // We are extending the window - win_stop = dly_tap; - } - } else { - if (win_start != -1) { // A valid window turned invalid - if (win_stop - win_start >= MIN_WINDOW_LEN) { - break; // Valid window found - } else { - win_start = -1; // Reset window - } - } - } - // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("CapTap=%d, Error=%d") % - // dly_tap % err_code); - } - - // Retry the self-cal if it fails - if ((win_start == -1 || (win_stop - win_start) < MIN_WINDOW_LEN) - && iter < NUM_RETRIES /*not last iteration*/) { - win_start = -1; - win_stop = -1; - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - } else { - break; - } - } - _adc->set_test_word("normal", "normal"); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - - if (win_start == -1) { - throw uhd::runtime_error( - "self_cal_adc_capture_delay: Self calibration failed. Convergence error."); - } - - if (win_stop - win_start < MIN_WINDOW_LEN) { - throw uhd::runtime_error("self_cal_adc_capture_delay: Self calibration failed. " - "Valid window too narrow."); - } - - uint32_t ideal_tap = (win_stop + win_start) / 2; - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, ideal_tap); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0); - - if (print_status) { - double tap_delay = (1.0e12 / _radio_clk_rate) / (2 * 32); // in ps - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("ADC capture delay self-cal done (Tap=%d, Window=%d, " - "TapDelay=%.3fps, Iter=%d)") - % ideal_tap % (win_stop - win_start) % tap_delay % iter; - } -} - -void x300_radio_ctrl_impl::_check_adc(const uint32_t val) -{ - // Wait for previous control transaction to flush - user_reg_read64(regs::RB_TEST); - // Wait for ADC test pattern to propagate - std::this_thread::sleep_for(std::chrono::microseconds(5)); - // Read value of RX readback register and verify - uint32_t adc_rb = static_cast<uint32_t>(user_reg_read64(regs::RB_TEST) >> 32); - adc_rb ^= 0xfffc0000; // adapt for I inversion in FPGA - if (val != adc_rb) { - throw uhd::runtime_error( - (boost::format("ADC self-test failed for %s. (Exp=0x%x, Got=0x%x)") - % unique_id() % val % adc_rb) - .str()); - } -} - -void x300_radio_ctrl_impl::_set_db_eeprom( - i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t& db_eeprom) -{ - db_eeprom.store(*i2c, addr); - _db_eeproms[addr] = db_eeprom; -} - -void x300_radio_ctrl_impl::_set_command_time(const time_spec_t& spec, const size_t port) -{ - set_fe_cmd_time(spec, port); -} -/**************************************************************************** - * Helpers - ***************************************************************************/ -bool x300_radio_ctrl_impl::check_radio_config() -{ - UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::check_radio_config() "; - const fs_path rx_fe_path = fs_path("dboards" / _radio_slot / "rx_frontends"); - for (size_t chan = 0; chan < _num_rx_channels; chan++) { - if (_tree->exists(rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled")) { - const bool chan_active = _is_streamer_active(uhd::RX_DIRECTION, chan); - if (chan_active) { - _tree - ->access<bool>( - rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled") - .set(chan_active); - } - } - } - - const fs_path tx_fe_path = fs_path("dboards" / _radio_slot / "tx_frontends"); - for (size_t chan = 0; chan < _num_tx_channels; chan++) { - if (_tree->exists(tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled")) { - const bool chan_active = _is_streamer_active(uhd::TX_DIRECTION, chan); - if (chan_active) { - _tree - ->access<bool>( - tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled") - .set(chan_active); - } - } - } - - return true; -} - -/**************************************************************************** - * Register block - ***************************************************************************/ -UHD_RFNOC_BLOCK_REGISTER(x300_radio_ctrl, "X300Radio"); diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp deleted file mode 100644 index 63aac876d..000000000 --- a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright 2015-2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP - -#include "x300_adc_ctrl.hpp" -#include "x300_clock_ctrl.hpp" -#include "x300_dac_ctrl.hpp" -#include "x300_regs.hpp" -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/gpio_defs.hpp> -#include <uhd/utils/gain_group.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> -#include <uhdlib/usrp/cores/rx_frontend_core_3000.hpp> -#include <uhdlib/usrp/cores/spi_core_3000.hpp> -#include <uhdlib/usrp/cores/tx_frontend_core_200.hpp> -#include <unordered_map> - -namespace uhd { namespace rfnoc { - -/*! \brief Provide access to an X300 radio. - */ -class x300_radio_ctrl_impl : public radio_ctrl_impl -{ -public: - typedef boost::shared_ptr<x300_radio_ctrl_impl> sptr; - - /************************************************************************ - * Structors - ***********************************************************************/ - UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(x300_radio_ctrl) - virtual ~x300_radio_ctrl_impl(); - - /************************************************************************ - * API calls - ***********************************************************************/ - double set_rate(double rate); - - void set_tx_antenna(const std::string& ant, const size_t chan); - void set_rx_antenna(const std::string& ant, const size_t chan); - std::string get_tx_antenna(const size_t chan); - std::string get_rx_antenna(const size_t chan); - - double set_tx_frequency(const double freq, const size_t chan); - double set_rx_frequency(const double freq, const size_t chan); - double set_rx_bandwidth(const double bandwidth, const size_t chan); - double get_tx_frequency(const size_t chan); - double get_rx_frequency(const size_t chan); - double get_rx_bandwidth(const size_t chan); - - double set_tx_gain(const double gain, const size_t chan); - double set_rx_gain(const double gain, const size_t chan); - double get_rx_gain(const size_t chan); - - std::vector<std::string> get_rx_lo_names(const size_t chan); - std::vector<std::string> get_rx_lo_sources( - const std::string& name, const size_t chan); - freq_range_t get_rx_lo_freq_range(const std::string& name, const size_t chan); - - void set_rx_lo_source( - const std::string& src, const std::string& name, const size_t chan); - const std::string get_rx_lo_source(const std::string& name, const size_t chan); - - void set_rx_lo_export_enabled( - bool enabled, const std::string& name, const size_t chan); - bool get_rx_lo_export_enabled(const std::string& name, const size_t chan); - - double set_rx_lo_freq(double freq, const std::string& name, const size_t chan); - double get_rx_lo_freq(const std::string& name, const size_t chan); - - size_t get_chan_from_dboard_fe(const std::string& fe, const direction_t dir); - std::string get_dboard_fe_from_chan(const size_t chan, const direction_t dir); - - std::vector<std::string> get_gpio_banks() const; - void set_gpio_attr(const std::string& bank, - const std::string& attr, - const uint32_t value, - const uint32_t mask); - uint32_t get_gpio_attr(const std::string& bank, const std::string& attr); - - double get_output_samp_rate(size_t port); - - /************************************************************************ - * Hardware setup and control - ***********************************************************************/ - /*! Set up the radio. No API calls may be made before this one. - */ - void setup_radio(uhd::i2c_iface::sptr zpu_i2c, - x300_clock_ctrl::sptr clock, - bool ignore_cal_file, - bool verbose); - - void reset_codec(); - - void self_test_adc(uint32_t ramp_time_ms = 100); - - static void extended_adc_test( - const std::vector<x300_radio_ctrl_impl::sptr>&, double duration_s); - - static void synchronize_dacs(const std::vector<x300_radio_ctrl_impl::sptr>& radios); - - static double self_cal_adc_xfer_delay( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, - x300_clock_ctrl::sptr clock, - boost::function<void(double)> wait_for_clk_locked, - bool apply_delay); - -protected: - virtual bool check_radio_config(); - -private: - class radio_regmap_t : public uhd::soft_regmap_t - { - public: - typedef boost::shared_ptr<radio_regmap_t> sptr; - class misc_outs_reg_t : public uhd::soft_reg32_wo_t - { - public: - UHD_DEFINE_SOFT_REG_FIELD(DAC_ENABLED, /*width*/ 1, /*shift*/ 0); //[0] - UHD_DEFINE_SOFT_REG_FIELD(DAC_RESET_N, /*width*/ 1, /*shift*/ 1); //[1] - UHD_DEFINE_SOFT_REG_FIELD(ADC_RESET, /*width*/ 1, /*shift*/ 2); //[2] - UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_STB, /*width*/ 1, /*shift*/ 3); //[3] - UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL, /*width*/ 5, /*shift*/ 4); //[8:4] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER_ENABLED, /*width*/ 1, /*shift*/ 9); //[9] - UHD_DEFINE_SOFT_REG_FIELD(DAC_SYNC, /*width*/ 1, /*shift*/ 10); //[10] - - misc_outs_reg_t() : uhd::soft_reg32_wo_t(regs::sr_addr(regs::MISC_OUTS)) - { - // Initial values - set(DAC_ENABLED, 0); - set(DAC_RESET_N, 0); - set(ADC_RESET, 0); - set(ADC_DATA_DLY_STB, 0); - set(ADC_DATA_DLY_VAL, 16); - set(ADC_CHECKER_ENABLED, 0); - set(DAC_SYNC, 0); - } - } misc_outs_reg; - - class misc_ins_reg_t : public uhd::soft_reg64_ro_t - { - public: - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_Q_LOCKED, /*width*/ 1, /*shift*/ 32); //[0] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_I_LOCKED, /*width*/ 1, /*shift*/ 33); //[1] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_Q_LOCKED, /*width*/ 1, /*shift*/ 34); //[2] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_I_LOCKED, /*width*/ 1, /*shift*/ 35); //[3] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_Q_ERROR, /*width*/ 1, /*shift*/ 36); //[4] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_I_ERROR, /*width*/ 1, /*shift*/ 37); //[5] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_Q_ERROR, /*width*/ 1, /*shift*/ 38); //[6] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_I_ERROR, /*width*/ 1, /*shift*/ 39); //[7] - - misc_ins_reg_t() : uhd::soft_reg64_ro_t(regs::rb_addr(regs::RB_MISC_IO)) {} - } misc_ins_reg; - - radio_regmap_t(int radio_num) - : soft_regmap_t("radio" + std::to_string(radio_num) + "_regmap") - { - add_to_map(misc_outs_reg, "misc_outs_reg", PRIVATE); - add_to_map(misc_ins_reg, "misc_ins_reg", PRIVATE); - } - }; - - struct x300_regs - { - static const uint32_t TX_FE_BASE = 224; - static const uint32_t RX_FE_BASE = 232; - }; - - void _update_atr_leds(const std::string& rx_ant, const size_t chan); - - void _self_cal_adc_capture_delay(bool print_status); - - void _check_adc(const uint32_t val); - - void _set_db_eeprom( - uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t&); - - void set_rx_fe_corrections(const uhd::fs_path& db_path, - const uhd::fs_path& rx_fe_corr_path, - const double lo_freq); - void set_tx_fe_corrections(const uhd::fs_path& db_path, - const uhd::fs_path& tx_fe_corr_path, - const double lo_freq); - - void _set_command_time(const uhd::time_spec_t& spec, const size_t port); - void set_fe_cmd_time(const time_spec_t& time, const size_t chan); - -private: // members - enum radio_connection_t { PRIMARY, SECONDARY }; - - radio_connection_t _radio_type; - std::string _radio_slot; - //! Radio clock rate is the rate at which the ADC and DAC are running at. - // Not necessarily this block's sampling rate (tick rate). - double _radio_clk_rate; - - radio_regmap_t::sptr _regs; - std::map<size_t, usrp::gpio_atr::gpio_atr_3000::sptr> _leds; - spi_core_3000::sptr _spi; - x300_adc_ctrl::sptr _adc; - x300_dac_ctrl::sptr _dac; - usrp::gpio_atr::gpio_atr_3000::sptr _fp_gpio; - - std::map<size_t, usrp::dboard_eeprom_t> _db_eeproms; - usrp::dboard_manager::sptr _db_manager; - - struct rx_fe_perif - { - std::string name; - std::string db_fe_name; - rx_frontend_core_3000::sptr core; - }; - struct tx_fe_perif - { - std::string name; - std::string db_fe_name; - tx_frontend_core_200::sptr core; - }; - - std::map<size_t, rx_fe_perif> _rx_fe_map; - std::map<size_t, tx_fe_perif> _tx_fe_map; - - bool _ignore_cal_file; - - std::unordered_map<size_t, uhd::gain_group::sptr> _tx_gain_groups; - std::unordered_map<size_t, uhd::gain_group::sptr> _rx_gain_groups; -}; /* class radio_ctrl_impl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP */ diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index d790b214e..8a477b181 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -42,7 +42,6 @@ set(test_sources property_test.cpp ranges_test.cpp scope_exit_test.cpp - sid_t_test.cpp sensors_test.cpp soft_reg_test.cpp sph_recv_test.cpp @@ -53,29 +52,16 @@ set(test_sources vrt_test.cpp expert_test.cpp fe_conn_test.cpp - rfnoc_node_test.cpp link_test.cpp rx_streamer_test.cpp tx_streamer_test.cpp + block_id_test.cpp + rfnoc_property_test.cpp ) #turn each test cpp file into an executable with an int main() function add_definitions(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN) -if(ENABLE_RFNOC) - list(APPEND test_sources - block_id_test.cpp - blockdef_test.cpp - device3_test.cpp - graph_search_test.cpp - node_connect_test.cpp - rate_node_test.cpp - stream_sig_test.cpp - tick_node_test.cpp - rfnoc_property_test.cpp - ) -endif(ENABLE_RFNOC) - if(ENABLE_C_API) list(APPEND test_sources eeprom_c_test.c @@ -149,15 +135,6 @@ if(ENABLE_DPDK) ENDIF(ENABLE_DPDK) UHD_ADD_NONAPI_TEST( - TARGET "nocscript_expr_test.cpp" - EXTRA_SOURCES - "${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/expression.cpp" - INCLUDE_DIRS - ${CMAKE_BINARY_DIR}/lib/rfnoc/nocscript/ - ${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/ -) - -UHD_ADD_NONAPI_TEST( TARGET "system_time_test.cpp" EXTRA_SOURCES "${CMAKE_SOURCE_DIR}/lib/utils/system_time.cpp" @@ -175,36 +152,6 @@ UHD_ADD_NONAPI_TEST( NOAUTORUN # Don't register for auto-run ) -#UHD_ADD_NONAPI_TEST( - #TARGET "nocscript_expr_test.cpp" - #EXTRA_SOURCES - #"${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/expression.cpp" - #INCLUDE_DIRS - #${CMAKE_BINARY_DIR}/lib/rfnoc/nocscript/ - #${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/ -#) - -#UHD_ADD_NONAPI_TEST( - #TARGET "nocscript_ftable_test.cpp" - #EXTRA_SOURCES - #${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/function_table.cpp - #${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/expression.cpp - #INCLUDE_DIRS - #${CMAKE_BINARY_DIR}/lib/rfnoc/nocscript/ - #${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/ -#) - -UHD_ADD_NONAPI_TEST( - TARGET "nocscript_parser_test.cpp" - EXTRA_SOURCES - ${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/parser.cpp - ${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/function_table.cpp - ${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/expression.cpp - INCLUDE_DIRS - ${CMAKE_BINARY_DIR}/lib/rfnoc/nocscript/ - ${CMAKE_SOURCE_DIR}/lib/rfnoc/nocscript/ -) - UHD_ADD_NONAPI_TEST( TARGET "packet_handler_benchmark.cpp" NOAUTORUN diff --git a/host/tests/common/CMakeLists.txt b/host/tests/common/CMakeLists.txt index 58299c688..7f31f3463 100644 --- a/host/tests/common/CMakeLists.txt +++ b/host/tests/common/CMakeLists.txt @@ -8,8 +8,6 @@ # Build uhd_test static lib ######################################################################## include_directories("${CMAKE_SOURCE_DIR}/lib/include") -add_library(uhd_test ${CMAKE_CURRENT_SOURCE_DIR}/mock_ctrl_iface_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/mock_zero_copy.cpp - ${CMAKE_SOURCE_DIR}/lib/rfnoc/graph_impl.cpp - ${CMAKE_SOURCE_DIR}/lib/rfnoc/async_msg_handler.cpp +add_library(uhd_test + ${CMAKE_CURRENT_SOURCE_DIR}/mock_zero_copy.cpp ) diff --git a/host/tests/common/mock_ctrl_iface_impl.cpp b/host/tests/common/mock_ctrl_iface_impl.cpp deleted file mode 100644 index af32637df..000000000 --- a/host/tests/common/mock_ctrl_iface_impl.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "mock_ctrl_iface_impl.hpp" -static const uint64_t TEST_NOC_ID = 0xAAAABBBBCCCCDDDD; - -uint64_t mock_ctrl_iface_impl::send_cmd_pkt(const size_t addr, - const size_t data, - const bool readback, - const uint64_t /* timestamp */ -) -{ - if (not readback) { - std::cout << str(boost::format("[MOCK] poke to addr: %016X, data == %016X") % addr - % data) - << std::endl; - } else { - std::cout << str(boost::format("[MOCK] peek64 to addr: %016X") % data) - << std::endl; - switch (data) { - case uhd::rfnoc::SR_READBACK_REG_ID: - return TEST_NOC_ID; - case uhd::rfnoc::SR_READBACK_REG_FIFOSIZE: - return 0x0000000000010000; - case uhd::rfnoc::SR_READBACK_REG_USER: - return 0x0123456789ABCDEF; - case uhd::rfnoc::SR_READBACK_COMPAT: - return uint64_t(uhd::rfnoc::NOC_SHELL_COMPAT_MAJOR) << 32 - | uint64_t(uhd::rfnoc::NOC_SHELL_COMPAT_MINOR); - default: - return 0; - } - } - return 0; -} diff --git a/host/tests/common/mock_ctrl_iface_impl.hpp b/host/tests/common/mock_ctrl_iface_impl.hpp deleted file mode 100644 index f20858b63..000000000 --- a/host/tests/common/mock_ctrl_iface_impl.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - - -#ifndef INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP -#define INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP - -#include <uhd/rfnoc/constants.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> - -class mock_ctrl_iface_impl : public uhd::rfnoc::ctrl_iface -{ - uint64_t send_cmd_pkt(const size_t addr, - const size_t data, - const bool readback = false, - const uint64_t timestamp = 0); - - void set_cmd_fifo_size(const size_t) {} -}; -#endif /* INCLUDED_MOCK_CTRL_IFACE_IMPL_HPP */ diff --git a/host/tests/common/mock_zero_copy.hpp b/host/tests/common/mock_zero_copy.hpp index 60e5f4659..515fde498 100644 --- a/host/tests/common/mock_zero_copy.hpp +++ b/host/tests/common/mock_zero_copy.hpp @@ -12,9 +12,7 @@ #include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/types/endianness.hpp> -#include <uhd/types/sid.hpp> #include <uhd/utils/byteswap.hpp> -#include <uhdlib/rfnoc/xports.hpp> #include <boost/make_shared.hpp> #include <boost/shared_array.hpp> #include <boost/shared_ptr.hpp> diff --git a/host/tests/device3_test.cpp b/host/tests/device3_test.cpp deleted file mode 100644 index b737e7012..000000000 --- a/host/tests/device3_test.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - - -#include "mock_ctrl_iface_impl.hpp" -#include "mock_zero_copy.hpp" -#include <uhd/device3.hpp> -#include <uhd/property_tree.hpp> -#include <uhd/rfnoc/block_ctrl.hpp> -#include <uhd/rfnoc/graph.hpp> -#include <uhdlib/rfnoc/graph_impl.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/test/unit_test.hpp> -#include <exception> -#include <iostream> - - -using namespace uhd; -using namespace uhd::rfnoc; -using namespace uhd::transport::vrt; -using uhd::transport::managed_recv_buffer; -using uhd::transport::managed_send_buffer; - -static const sid_t TEST_SID0 = 0x00000200; // 0.0.2.0 -static const sid_t TEST_SID1 = 0x00000210; // 0.0.2.F - -uhd::both_xports_t make_mock_transport(const uhd::sid_t& tx_sid) -{ - uhd::both_xports_t xports; - xports.send_sid = tx_sid; - xports.recv_sid = tx_sid.reversed(); - xports.send = boost::make_shared<mock_zero_copy>(if_packet_info_t::LINK_TYPE_CHDR); - xports.recv = xports.send; - xports.send_buff_size = xports.send->get_send_frame_size(); - xports.recv_buff_size = xports.recv->get_recv_frame_size(); - return xports; -} - -// Mock-device -class mock_device3_impl : public uhd::device3, - public boost::enable_shared_from_this<mock_device3_impl> -{ -public: - mock_device3_impl() - { - _tree = uhd::property_tree::make(); - _tree->create<std::string>("/name").set("Test Mock-Device3"); - // We can re-use this: - std::map<size_t, ctrl_iface::sptr> ctrl_ifaces{ - {0, ctrl_iface::sptr(new mock_ctrl_iface_impl())}}; - - // Add two block controls: - uhd::rfnoc::make_args_t make_args; - make_args.ctrl_ifaces = ctrl_ifaces; - make_args.base_address = TEST_SID0.get_dst(); - make_args.device_index = 0; - make_args.tree = _tree; - std::cout << "[MOCK] Generating block controls 1/2:" << std::endl; - _rfnoc_block_ctrl.push_back(block_ctrl_base::make(make_args)); - std::cout << "[MOCK] Generating block controls 2/2:" << std::endl; - make_args.base_address = TEST_SID1.get_dst(); - _rfnoc_block_ctrl.push_back(block_ctrl::make(make_args)); - } - - rx_streamer::sptr get_rx_stream(const stream_args_t& args) - { - throw uhd::not_implemented_error(args.args.to_string()); - } - - tx_streamer::sptr get_tx_stream(const stream_args_t& args) - { - throw uhd::not_implemented_error(args.args.to_string()); - } - - bool recv_async_msg(async_metadata_t& async_metadata, double timeout) - { - throw uhd::not_implemented_error( - str(boost::format("%d %f") % async_metadata.channel % timeout)); - } - - rfnoc::graph::sptr create_graph(const std::string& name) - { - sid_t async_sid(0); - async_sid.set_dst_addr(2); - auto async_xports = make_mock_transport(async_sid); - - auto async_msg_handler = uhd::rfnoc::async_msg_handler::make(async_xports.recv, - async_xports.send, - async_xports.send_sid, - async_xports.endianness); - auto graph = boost::make_shared<uhd::rfnoc::graph_impl>( - name, shared_from_this(), async_msg_handler); - return graph; - } -}; - -device3::sptr make_mock_device() -{ - return device3::sptr(new mock_device3_impl()); -} - -class mock_block_ctrl : public block_ctrl -{ - int foo; -}; - -BOOST_AUTO_TEST_CASE(test_device3) -{ - device3::sptr my_device = make_mock_device(); - - std::cout << "Checking block 0..." << std::endl; - BOOST_REQUIRE(my_device->find_blocks("Block").size()); - - std::cout << "Getting block 0..." << std::endl; - block_ctrl_base::sptr block0 = - my_device->get_block_ctrl(my_device->find_blocks("Block")[0]); - BOOST_REQUIRE(block0); - BOOST_CHECK_EQUAL(block0->get_block_id(), "0/Block#0"); - - std::cout << "Checking block 1..." << std::endl; - BOOST_REQUIRE(my_device->has_block(block_id_t("0/Block#1"))); - - std::cout << "Getting block 1..." << std::endl; - block_ctrl_base::sptr block1 = my_device->get_block_ctrl(block_id_t("0/Block#1")); - BOOST_REQUIRE(block1); - BOOST_CHECK_EQUAL(block1->get_block_id(), "0/Block#1"); -} - - -BOOST_AUTO_TEST_CASE(test_device3_graph) -{ - auto my_device = make_mock_device(); - std::cout << "Start device3 test graph.." << std::endl; - std::cout << "Checking block 0..." << std::endl; - BOOST_REQUIRE(my_device->find_blocks("Block").size()); - std::cout << "Getting block 0..." << std::endl; - auto block0 = my_device->get_block_ctrl(my_device->find_blocks("Block")[0]); - BOOST_REQUIRE(block0); - BOOST_CHECK_EQUAL(block0->get_block_id(), "0/Block#0"); - - std::cout << "Checking block 1..." << std::endl; - BOOST_REQUIRE(my_device->has_block(block_id_t("0/Block#1"))); - - std::cout << "Getting block 1..." << std::endl; - auto block1 = my_device->get_block_ctrl(block_id_t("0/Block#1")); - BOOST_REQUIRE(block1); - BOOST_CHECK_EQUAL(block1->get_block_id(), "0/Block#1"); - std::cout << "Creating graph..." << std::endl; - auto graph = my_device->create_graph("test_graph"); - BOOST_CHECK(graph); - std::cout << "Connecting block_0 to block_1 ..." << std::endl; - graph->connect(block_id_t("0/Block#0"), 0, block_id_t("0/Block#1"), 0); - - BOOST_CHECK_EQUAL(block0->list_upstream_nodes().size(), 0); - BOOST_CHECK_EQUAL(block0->list_downstream_nodes().size(), 1); - BOOST_CHECK_EQUAL( - block0->list_downstream_nodes()[0].lock()->unique_id(), "0/Block#1"); - BOOST_CHECK_EQUAL(block1->list_upstream_nodes().size(), 1); - BOOST_CHECK_EQUAL(block1->list_downstream_nodes().size(), 0); - BOOST_CHECK_EQUAL(block1->list_upstream_nodes()[0].lock()->unique_id(), "0/Block#0"); -} - -BOOST_AUTO_TEST_CASE(test_device3_cast) -{ - device3::sptr my_device = make_mock_device(); - - std::cout << "Getting block 0..." << std::endl; - block_ctrl::sptr block0 = - my_device->get_block_ctrl<block_ctrl>(block_id_t("0/Block#0")); - BOOST_REQUIRE(block0); - BOOST_CHECK_EQUAL(block0->get_block_id(), "0/Block#0"); - - std::cout << "Getting block 1..." << std::endl; - block_ctrl_base::sptr block1 = - my_device->get_block_ctrl<block_ctrl>(block_id_t("0/Block#1")); - BOOST_CHECK_EQUAL(block1->get_block_id(), "0/Block#1"); -} - -BOOST_AUTO_TEST_CASE(test_device3_fail) -{ - device3::sptr my_device = make_mock_device(); - - BOOST_CHECK(not my_device->has_block(block_id_t("0/FooBarBlock#0"))); - BOOST_CHECK(not my_device->has_block<mock_block_ctrl>(block_id_t("0/Block#1"))); - - BOOST_CHECK(my_device->find_blocks("FooBarBlock").size() == 0); - BOOST_CHECK(my_device->find_blocks<block_ctrl>("FooBarBlock").size() == 0); - - BOOST_REQUIRE_THROW( - my_device->get_block_ctrl(block_id_t("0/FooBarBlock#17")), uhd::lookup_error); - BOOST_REQUIRE_THROW( - my_device->get_block_ctrl<mock_block_ctrl>(block_id_t("0/Block#1")), - uhd::lookup_error); -} - -// vim: sw=4 et: diff --git a/host/tests/graph.hpp b/host/tests/graph.hpp deleted file mode 100644 index fb36ae510..000000000 --- a/host/tests/graph.hpp +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_TEST_GRAPH_HPP -#define INCLUDED_TEST_GRAPH_HPP - -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/rfnoc/sink_node_ctrl.hpp> -#include <uhd/rfnoc/source_node_ctrl.hpp> - -#define MAKE_NODE(name) test_node::sptr name(new test_node(#name)); - -// Smallest possible test class -class test_node : virtual public uhd::rfnoc::sink_node_ctrl, - virtual public uhd::rfnoc::source_node_ctrl -{ -public: - typedef boost::shared_ptr<test_node> sptr; - - test_node(const std::string& test_id) : _test_id(test_id){}; - - void issue_stream_cmd(const uhd::stream_cmd_t&, const size_t){/* nop */}; - - std::string get_test_id() const - { - return _test_id; - }; - -private: - const std::string _test_id; - -}; /* class test_node */ - -void connect_nodes( - uhd::rfnoc::source_node_ctrl::sptr A, uhd::rfnoc::sink_node_ctrl::sptr B) -{ - const size_t actual_src_port = A->connect_downstream(B); - const size_t actual_dst_port = B->connect_upstream(A); - A->set_downstream_port(actual_src_port, actual_dst_port); - B->set_upstream_port(actual_dst_port, actual_src_port); -} - -#endif /* INCLUDED_TEST_GRAPH_HPP */ diff --git a/host/tests/graph_search_test.cpp b/host/tests/graph_search_test.cpp deleted file mode 100644 index 932647d98..000000000 --- a/host/tests/graph_search_test.cpp +++ /dev/null @@ -1,161 +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 "graph.hpp" -#include <boost/test/unit_test.hpp> -#include <iostream> - -using namespace uhd::rfnoc; - -// test class derived, this is what we search for -class result_node : public test_node -{ -public: - typedef boost::shared_ptr<result_node> sptr; - - result_node(const std::string& test_id) : test_node(test_id){}; - -}; /* class result_node */ - -#define MAKE_RESULT_NODE(name) result_node::sptr name(new result_node(#name)); - -BOOST_AUTO_TEST_CASE(test_simplest_downstream_search) -{ - MAKE_NODE(node_A); - MAKE_NODE(node_B); - - // Simplest possible scenario: Connect B downstream of A and let - // A find B - connect_nodes(node_A, node_B); - - test_node::sptr result = node_A->find_downstream_node<test_node>()[0]; - BOOST_REQUIRE(result); - BOOST_CHECK_EQUAL(result->get_test_id(), "node_B"); -} - -BOOST_AUTO_TEST_CASE(test_simple_downstream_search) -{ - MAKE_NODE(node_A); - MAKE_NODE(node_B0); - MAKE_NODE(node_B1); - - // Simple scenario: Connect both B{1,2} downstream of A and let - // it find them - connect_nodes(node_A, node_B0); - connect_nodes(node_A, node_B1); - - // We're still searching for test_node, so any downstream block will match - std::vector<test_node::sptr> result = node_A->find_downstream_node<test_node>(); - BOOST_REQUIRE(result.size() == 2); - BOOST_CHECK( - (result[0]->get_test_id() == "node_B0" and result[1]->get_test_id() == "node_B1") - or (result[1]->get_test_id() == "node_B0" - and result[0]->get_test_id() == "node_B1")); - BOOST_CHECK(result[0] == node_B0 or result[0] == node_B1); -} - -BOOST_AUTO_TEST_CASE(test_linear_downstream_search) -{ - MAKE_NODE(node_A); - MAKE_RESULT_NODE(node_B); - MAKE_RESULT_NODE(node_C); - - // Slightly more complex graph: - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - - // This time, we search for result_node - std::vector<result_node::sptr> result = node_A->find_downstream_node<result_node>(); - std::cout << "size: " << result.size() << std::endl; - BOOST_CHECK_EQUAL(result.size(), 1); - BOOST_CHECK_EQUAL(result[0]->get_test_id(), "node_B"); - for (const result_node::sptr& node : result) { - std::cout << node->get_test_id() << std::endl; - } -} - -BOOST_AUTO_TEST_CASE(test_multi_iter_downstream_search) -{ - MAKE_NODE(node_A); - MAKE_NODE(node_B0); - MAKE_NODE(node_B1); - MAKE_NODE(node_C0); - MAKE_RESULT_NODE(node_C1); - MAKE_RESULT_NODE(node_C2); - MAKE_RESULT_NODE(node_C3); - MAKE_RESULT_NODE(node_D0); - - // Slightly more complex graph: - connect_nodes(node_A, node_B0); - connect_nodes(node_A, node_B1); - connect_nodes(node_B0, node_C0); - connect_nodes(node_B0, node_C1); - connect_nodes(node_B1, node_C2); - connect_nodes(node_B1, node_C3); - connect_nodes(node_C0, node_D0); - - // This time, we search for result_node - std::vector<result_node::sptr> result = node_A->find_downstream_node<result_node>(); - BOOST_REQUIRE(result.size() == 4); - for (const result_node::sptr& node : result) { - std::cout << node->get_test_id() << std::endl; - } -} - -BOOST_AUTO_TEST_CASE(test_multi_iter_cycle_downstream_search) -{ - MAKE_NODE(node_A); - MAKE_NODE(node_B0); - MAKE_NODE(node_B1); - MAKE_NODE(node_C0); - MAKE_RESULT_NODE(node_C1); - MAKE_RESULT_NODE(node_C2); - MAKE_RESULT_NODE(node_C3); - MAKE_RESULT_NODE(node_D0); - - // Slightly more complex graph: - connect_nodes(node_A, node_B0); - // This connection goes both ways, causing a cycle - connect_nodes(node_A, node_B1); - connect_nodes(node_B1, node_A); - connect_nodes(node_B0, node_C0); - connect_nodes(node_B0, node_C1); - connect_nodes(node_B1, node_C2); - connect_nodes(node_B1, node_C3); - connect_nodes(node_C0, node_D0); - - // This time, we search for result_node - std::vector<result_node::sptr> result = node_A->find_downstream_node<result_node>(); - BOOST_REQUIRE(result.size() == 4); - for (const result_node::sptr& node : result) { - std::cout << node->get_test_id() << std::endl; - } -} - -BOOST_AUTO_TEST_CASE(test_mini_cycle_downstream_and_upstream) -{ - MAKE_NODE(node_A); - MAKE_NODE(node_B); - - // Connect them in a loop - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_A); - - std::vector<test_node::sptr> result; - result = node_A->find_downstream_node<test_node>(); - BOOST_REQUIRE_EQUAL(result.size(), 1); - BOOST_REQUIRE(result[0] == node_B); - result = node_B->find_downstream_node<test_node>(); - BOOST_REQUIRE_EQUAL(result.size(), 1); - BOOST_REQUIRE(result[0] == node_A); - result = node_A->find_upstream_node<test_node>(); - BOOST_REQUIRE_EQUAL(result.size(), 1); - BOOST_REQUIRE(result[0] == node_B); - result = node_B->find_upstream_node<test_node>(); - BOOST_REQUIRE_EQUAL(result.size(), 1); - BOOST_REQUIRE(result[0] == node_A); -} diff --git a/host/tests/nocscript_common.hpp b/host/tests/nocscript_common.hpp deleted file mode 100644 index ad254fa0e..000000000 --- a/host/tests/nocscript_common.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "../lib/rfnoc/nocscript/expression.hpp" -#include <boost/assign/list_of.hpp> - -using namespace uhd::rfnoc::nocscript; - -// Some global defs to make tests easier to write -expression_function::argtype_list_type one_int_arg = - boost::assign::list_of(expression::TYPE_INT); -expression_function::argtype_list_type two_int_args = - boost::assign::list_of(expression::TYPE_INT)(expression::TYPE_INT); -expression_function::argtype_list_type one_double_arg = - boost::assign::list_of(expression::TYPE_DOUBLE); -expression_function::argtype_list_type two_double_args = - boost::assign::list_of(expression::TYPE_DOUBLE)(expression::TYPE_DOUBLE); -expression_function::argtype_list_type one_bool_arg = - boost::assign::list_of(expression::TYPE_BOOL); -expression_function::argtype_list_type two_bool_args = - boost::assign::list_of(expression::TYPE_BOOL)(expression::TYPE_BOOL); -expression_function::argtype_list_type no_args; - -expression_container::expr_list_type empty_arg_list; - -#define E(x) expression_literal::make(x) diff --git a/host/tests/nocscript_expr_test.cpp b/host/tests/nocscript_expr_test.cpp deleted file mode 100644 index ed5f6598d..000000000 --- a/host/tests/nocscript_expr_test.cpp +++ /dev/null @@ -1,405 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "../lib/rfnoc/nocscript/function_table.hpp" -#include "nocscript_common.hpp" -#include <boost/bind.hpp> -#include <boost/format.hpp> -#include <boost/make_shared.hpp> -#include <boost/test/floating_point_comparison.hpp> -#include <boost/test/unit_test.hpp> -#include <algorithm> -#include <iostream> - -// We need this global variable for one of the later tests -int and_counter = 0; - -BOOST_AUTO_TEST_CASE(test_literals) -{ - expression_literal literal_int("5", expression::TYPE_INT); - BOOST_CHECK_EQUAL(literal_int.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(literal_int.get_int(), 5); - BOOST_CHECK_EQUAL(literal_int.to_bool(), true); - BOOST_REQUIRE_THROW(literal_int.get_string(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_int.get_bool(), uhd::type_error); - - expression_literal literal_int0("0", expression::TYPE_INT); - BOOST_CHECK_EQUAL(literal_int0.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(literal_int0.to_bool(), false); - - expression_literal literal_double("2.3", expression::TYPE_DOUBLE); - BOOST_CHECK_EQUAL(literal_double.infer_type(), expression::TYPE_DOUBLE); - BOOST_CHECK_CLOSE(literal_double.get_double(), 2.3, 0.01); - BOOST_CHECK_EQUAL(literal_double.to_bool(), true); - BOOST_REQUIRE_THROW(literal_double.get_string(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_double.get_bool(), uhd::type_error); - - expression_literal literal_bool(true); - BOOST_CHECK_EQUAL(literal_bool.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(literal_bool.get_bool(), true); - BOOST_CHECK_EQUAL(literal_bool.to_bool(), true); - BOOST_CHECK_EQUAL(literal_bool.eval().get_bool(), true); - BOOST_REQUIRE_THROW(literal_bool.get_string(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_bool.get_int(), uhd::type_error); - - expression_literal literal_bool_false(false); - BOOST_CHECK_EQUAL(literal_bool_false.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(literal_bool_false.get_bool(), false); - BOOST_CHECK_EQUAL(literal_bool_false.to_bool(), false); - BOOST_REQUIRE_EQUAL(literal_bool_false.eval().get_bool(), false); - BOOST_REQUIRE_THROW(literal_bool_false.get_string(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_bool_false.get_int(), uhd::type_error); - - expression_literal literal_string("'foo bar'", expression::TYPE_STRING); - BOOST_CHECK_EQUAL(literal_string.infer_type(), expression::TYPE_STRING); - BOOST_CHECK_EQUAL(literal_string.get_string(), "foo bar"); - BOOST_REQUIRE_THROW(literal_string.get_bool(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_string.get_int(), uhd::type_error); - - expression_literal literal_int_vec("[1, 2, 3]", expression::TYPE_INT_VECTOR); - BOOST_CHECK_EQUAL(literal_int_vec.infer_type(), expression::TYPE_INT_VECTOR); - std::vector<int> test_data{1, 2, 3}; - std::vector<int> result = literal_int_vec.get_int_vector(); - BOOST_CHECK_EQUAL_COLLECTIONS( - test_data.begin(), test_data.end(), result.begin(), result.end()); - BOOST_REQUIRE_THROW(literal_int_vec.get_bool(), uhd::type_error); - BOOST_REQUIRE_THROW(literal_int_vec.get_int(), uhd::type_error); -} - - -// Need those for the variable testing: -expression::type_t variable_get_type(const std::string& var_name) -{ - if (var_name == "spp") { - std::cout << "Returning type for $spp..." << std::endl; - return expression::TYPE_INT; - } - if (var_name == "is_true") { - std::cout << "Returning type for $is_true..." << std::endl; - return expression::TYPE_BOOL; - } - - throw uhd::syntax_error("Cannot infer type (unknown variable)"); -} - -expression_literal variable_get_value(const std::string& var_name) -{ - if (var_name == "spp") { - std::cout << "Returning value for $spp..." << std::endl; - return expression_literal(5); - } - if (var_name == "is_true") { - std::cout << "Returning value for $is_true..." << std::endl; - return expression_literal(true); - } - - throw uhd::syntax_error("Cannot read value (unknown variable)"); -} - -BOOST_AUTO_TEST_CASE(test_variables) -{ - BOOST_REQUIRE_THROW(expression_variable v_fail("foo", // Invalid token - boost::bind(&variable_get_type, _1), - boost::bind(&variable_get_value, _1)), - uhd::assertion_error); - - expression_variable v("$spp", // The token - boost::bind(&variable_get_type, _1), // type-getter - boost::bind(&variable_get_value, _1) // value-getter - ); - BOOST_CHECK_EQUAL(v.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(v.eval().get_int(), 5); -} - -BOOST_AUTO_TEST_CASE(test_container) -{ - // Create some sub-expressions: - expression_literal::sptr l_true = E(true); - expression_literal::sptr l_false = E(false); - expression_literal::sptr l_int = E(5); - BOOST_REQUIRE_EQUAL(l_false->get_bool(), false); - BOOST_REQUIRE_EQUAL(l_false->to_bool(), false); - expression_variable::sptr l_boolvar = - boost::make_shared<expression_variable>("$is_true", - boost::bind(&variable_get_type, _1), - boost::bind(&variable_get_value, _1)); - - // This will throw anytime it's evaluated: - expression_variable::sptr l_failvar = - boost::make_shared<expression_variable>("$does_not_exist", - boost::bind(&variable_get_type, _1), - boost::bind(&variable_get_value, _1)); - - expression_container c; - std::cout << "One true, OR: " << std::endl; - c.add(l_true); - c.set_combiner_safe(expression_container::COMBINE_OR); - expression_literal ret_val_1 = c.eval(); - BOOST_CHECK_EQUAL(ret_val_1.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(ret_val_1.eval().get_bool(), true); - - std::cout << std::endl << std::endl << "Two true, one false, OR: " << std::endl; - c.add(l_true); - c.add(l_false); - expression_literal ret_val_2 = c.eval(); - BOOST_CHECK_EQUAL(ret_val_2.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(ret_val_2.eval().get_bool(), true); - - expression_container c2; - c2.add(l_false); - c2.add(l_false); - c2.set_combiner(expression_container::COMBINE_AND); - std::cout << std::endl << std::endl << "Two false, AND: " << std::endl; - expression_literal ret_val_3 = c2.eval(); - BOOST_CHECK_EQUAL(ret_val_3.infer_type(), expression::TYPE_BOOL); - BOOST_REQUIRE_EQUAL(ret_val_3.eval().get_bool(), false); - - c2.add(l_failvar); - // Will not fail, because l_failvar never gets eval'd: - expression_literal ret_val_4 = c2.eval(); - BOOST_CHECK_EQUAL(ret_val_4.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(ret_val_4.eval().get_bool(), false); - - // Same here: - c.add(l_failvar); - expression_literal ret_val_5 = c.eval(); - BOOST_CHECK_EQUAL(ret_val_5.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(ret_val_5.eval().get_bool(), true); - - // Now it'll throw: - c.set_combiner(expression_container::COMBINE_ALL); - BOOST_REQUIRE_THROW(c.eval(), uhd::syntax_error); - - std::cout << "Checking type inference on ',' sequences: " << std::endl; - // Check types match - BOOST_CHECK_EQUAL(c2.infer_type(), expression::TYPE_BOOL); - expression_container c3; - c3.set_combiner(expression_container::COMBINE_ALL); - c3.add(l_false); - c3.add(l_int); - BOOST_CHECK_EQUAL(c3.infer_type(), expression::TYPE_INT); -} - - -// We'll define two functions here: ADD and XOR. The former shall -// be defined for INT and DOUBLE -class functable_mockup_impl : public function_table -{ -public: - functable_mockup_impl(void){}; - - bool function_exists(const std::string& name) const - { - return name == "ADD" or name == "XOR" or name == "AND"; - } - - bool function_exists(const std::string& name, - const expression_function::argtype_list_type& arg_types) const - { - if (name == "ADD") { - if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_DOUBLE - and arg_types[1] == expression::TYPE_DOUBLE) { - return true; - } - if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_INT - and arg_types[1] == expression::TYPE_INT) { - return true; - } - return false; - } - - if (name == "XOR" or name == "AND") { - if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_BOOL - and arg_types[1] == expression::TYPE_BOOL) { - return true; - } - return false; - } - - return false; - } - - expression::type_t get_type(const std::string& name, - const expression_function::argtype_list_type& arg_types) const - { - if (not function_exists(name, arg_types)) { - throw uhd::syntax_error( - str(boost::format( - "[EXPR_TEXT] get_type(): Unknown function: %s, %d arguments") - % name % arg_types.size())); - } - - if (name == "XOR" or name == "AND") { - return expression::TYPE_BOOL; - } - if (name == "ADD") { - return arg_types[0]; - } - UHD_THROW_INVALID_CODE_PATH(); - } - - expression_literal eval(const std::string& name, - const expression_function::argtype_list_type& arg_types, - expression_container::expr_list_type& args) - { - if (name == "XOR") { - if (arg_types.size() != 2 or args.size() != 2 - or arg_types[0] != expression::TYPE_BOOL - or arg_types[1] != expression::TYPE_BOOL - or args[0]->infer_type() != expression::TYPE_BOOL - or args[1]->infer_type() != expression::TYPE_BOOL) { - throw uhd::syntax_error("eval(): XOR type mismatch"); - } - return expression_literal( - bool(args[0]->eval().get_bool() xor args[1]->eval().get_bool())); - } - - if (name == "AND") { - if (arg_types.size() != 2 or args.size() != 2 - or arg_types[0] != expression::TYPE_BOOL - or arg_types[1] != expression::TYPE_BOOL - or args[0]->infer_type() != expression::TYPE_BOOL - or args[1]->infer_type() != expression::TYPE_BOOL) { - throw uhd::syntax_error("eval(): AND type mismatch"); - } - std::cout << "Calling AND" << std::endl; - and_counter++; - return expression_literal( - bool(args[0]->eval().get_bool() and args[1]->eval().get_bool())); - } - - if (name == "ADD") { - if (args.size() != 2) { - throw uhd::syntax_error("eval(): ADD type mismatch"); - } - if ((args[0]->infer_type() == expression::TYPE_INT) - and (args[1]->infer_type() == expression::TYPE_INT)) { - return expression_literal( - int(args[0]->eval().get_int() + args[1]->eval().get_int())); - } else if ((args[0]->infer_type() == expression::TYPE_DOUBLE) - and (args[1]->infer_type() == expression::TYPE_DOUBLE)) { - return expression_literal( - double(args[0]->eval().get_double() + args[1]->eval().get_double())); - } - throw uhd::syntax_error("eval(): ADD type mismatch"); - } - throw uhd::syntax_error("eval(): unknown function"); - } - - // We don't actually need this - void register_function(const std::string&, - const function_table::function_ptr&, - const expression::type_t, - const expression_function::argtype_list_type&){}; -}; - - -// The annoying part: Testing the test fixtures -BOOST_AUTO_TEST_CASE(test_functable_mockup) -{ - functable_mockup_impl functable; - - BOOST_CHECK(functable.function_exists("ADD")); - BOOST_CHECK(functable.function_exists("XOR")); - BOOST_CHECK(not functable.function_exists("FOOBAR")); - - BOOST_CHECK(functable.function_exists("ADD", two_int_args)); - BOOST_CHECK(functable.function_exists("ADD", two_double_args)); - BOOST_CHECK(functable.function_exists("XOR", two_bool_args)); - BOOST_CHECK(not functable.function_exists("ADD", two_bool_args)); - BOOST_CHECK(not functable.function_exists("ADD", no_args)); - BOOST_CHECK(not functable.function_exists("XOR", no_args)); - - BOOST_CHECK_EQUAL(functable.get_type("ADD", two_int_args), expression::TYPE_INT); - BOOST_CHECK_EQUAL( - functable.get_type("ADD", two_double_args), expression::TYPE_DOUBLE); - BOOST_CHECK_EQUAL(functable.get_type("XOR", two_bool_args), expression::TYPE_BOOL); - - expression_container::expr_list_type add_args_int{E(2), E(3)}; - expression_container::expr_list_type add_args_dbl{E(2.25), E(5.0)}; - expression_container::expr_list_type xor_args_bool{E(true), E(false)}; - - BOOST_CHECK_EQUAL( - functable.eval("ADD", two_int_args, add_args_int), expression_literal(5)); - BOOST_CHECK_EQUAL( - functable.eval("ADD", two_double_args, add_args_dbl), expression_literal(7.25)); - BOOST_CHECK_EQUAL( - functable.eval("XOR", two_bool_args, xor_args_bool), expression_literal(true)); -} - -BOOST_AUTO_TEST_CASE(test_function_expression) -{ - function_table::sptr ft = boost::make_shared<functable_mockup_impl>(); - - // Very simple function: ADD(2, 3) - expression_function func1("ADD", ft); - func1.add(E(2)); - func1.add(E(3)); - - BOOST_CHECK_EQUAL(func1.eval(), expression_literal(5)); - - // More elaborate: ADD(ADD(2, 3), ADD(ADD(4, 5), 6)) ?= 20 - // f4 f1 f3 f2 - expression_function f1("ADD", ft); - f1.add(E(2)); - f1.add(E(3)); - expression_function f2("ADD", ft); - f2.add(E(4)); - f2.add(E(5)); - expression_function f3("ADD", ft); - f3.add(boost::make_shared<expression_function>(f2)); - f3.add(E(6)); - expression_function f4("ADD", ft); - f4.add(boost::make_shared<expression_function>(f1)); - f4.add(boost::make_shared<expression_function>(f3)); - - BOOST_CHECK_EQUAL(f4.eval().get_int(), 20); -} - -BOOST_AUTO_TEST_CASE(test_function_expression_laziness) -{ - function_table::sptr ft = boost::make_shared<functable_mockup_impl>(); - - // We run AND(AND(false, false), AND(false, false)). - // f1 f2 f3 - // That makes three ANDs - // in total. However, we will only see AND being evaluated twice, because - // the outcome is clear after running the first AND in the argument list. - expression_function::sptr f2 = boost::make_shared<expression_function>("AND", ft); - f2->add(E(false)); - f2->add(E(false)); - BOOST_CHECK(not f2->eval().get_bool()); - - expression_function::sptr f3 = boost::make_shared<expression_function>("AND", ft); - f3->add(E(false)); - f3->add(E(false)); - BOOST_CHECK(not f3->eval().get_bool()); - - and_counter = 0; - expression_function::sptr f1 = boost::make_shared<expression_function>("AND", ft); - f1->add(f2); - f1->add(f3); - - BOOST_CHECK(not f1->eval().get_bool()); - BOOST_CHECK_EQUAL(and_counter, 2); -} - -BOOST_AUTO_TEST_CASE(test_sptrs) -{ - expression_container::sptr c = expression_container::make(); - BOOST_CHECK_EQUAL(c->infer_type(), expression::TYPE_BOOL); - BOOST_CHECK(c->eval().get_bool()); - - expression_variable::sptr v = expression_variable::make("$spp", - boost::bind(&variable_get_type, _1), // type-getter - boost::bind(&variable_get_value, _1) // value-getter - ); - - c->add(v); - BOOST_REQUIRE_EQUAL(c->infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(c->eval().get_int(), 5); -} diff --git a/host/tests/nocscript_ftable_test.cpp b/host/tests/nocscript_ftable_test.cpp deleted file mode 100644 index 36aa314f2..000000000 --- a/host/tests/nocscript_ftable_test.cpp +++ /dev/null @@ -1,248 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "../lib/rfnoc/nocscript/function_table.hpp" -#include "nocscript_common.hpp" -#include <boost/bind.hpp> -#include <boost/make_shared.hpp> -#include <boost/test/floating_point_comparison.hpp> -#include <boost/test/unit_test.hpp> -#include <algorithm> -#include <iostream> - -BOOST_AUTO_TEST_CASE(test_basic_funcs) -{ - function_table::sptr ft = function_table::make(); - BOOST_CHECK(ft->function_exists("ADD")); - BOOST_CHECK(ft->function_exists("ADD", two_int_args)); - BOOST_CHECK(ft->function_exists("LE", two_int_args)); - BOOST_CHECK(ft->function_exists("GE")); - BOOST_CHECK(ft->function_exists("GE", two_int_args)); - BOOST_CHECK(ft->function_exists("TRUE")); - BOOST_CHECK(ft->function_exists("FALSE")); - - // Math - expression_container::expr_list_type two_int_values{E(2), E(3)}; - expression_container::expr_list_type two_int_values2{E(3), E(2)}; - expression_container::expr_list_type two_double_values{E(2.0), E(3.0)}; - - BOOST_REQUIRE_EQUAL(ft->get_type("ADD", two_int_args), expression::TYPE_INT); - expression_literal e_add = ft->eval("ADD", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_add.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_add.get_int(), 5); - - BOOST_REQUIRE_EQUAL(ft->get_type("MULT", two_int_args), expression::TYPE_INT); - expression_literal e_mult_i = ft->eval("MULT", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_mult_i.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_mult_i.get_int(), 6); - - BOOST_REQUIRE_EQUAL(ft->get_type("MULT", two_double_args), expression::TYPE_DOUBLE); - expression_literal e_mult_d = ft->eval("MULT", two_double_args, two_double_values); - BOOST_REQUIRE_EQUAL(e_mult_d.infer_type(), expression::TYPE_DOUBLE); - BOOST_CHECK_CLOSE(e_mult_d.get_double(), 6.0, 0.01); - - BOOST_REQUIRE_EQUAL(ft->get_type("DIV", two_double_args), expression::TYPE_DOUBLE); - expression_literal e_div_d = ft->eval("DIV", two_double_args, two_double_values); - BOOST_REQUIRE_EQUAL(e_div_d.infer_type(), expression::TYPE_DOUBLE); - BOOST_CHECK_CLOSE(e_div_d.get_double(), 2.0 / 3.0, 0.01); - - BOOST_REQUIRE_EQUAL(ft->get_type("MODULO", two_int_args), expression::TYPE_INT); - expression_literal e_modulo_i = ft->eval("MODULO", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_modulo_i.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_modulo_i.get_int(), 2 % 3); - - BOOST_REQUIRE_EQUAL(ft->get_type("LE", two_int_args), expression::TYPE_BOOL); - expression_literal e_le = ft->eval("LE", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_le.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(e_le.get_bool(), true); - BOOST_CHECK_EQUAL(ft->eval("LE", two_int_args, two_int_values2).get_bool(), false); - expression_literal e_ge = ft->eval("GE", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(ft->get_type("GE", two_int_args), expression::TYPE_BOOL); - BOOST_REQUIRE_EQUAL(e_ge.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(e_ge.get_bool(), false); - - expression_container::expr_list_type sixty_four{E(64)}; - expression_literal e_pwr2 = ft->eval("IS_PWR_OF_2", one_int_arg, sixty_four); - BOOST_REQUIRE_EQUAL(e_pwr2.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK_EQUAL(e_pwr2.get_bool(), true); - expression_literal e_log2 = ft->eval("LOG2", one_int_arg, sixty_four); - BOOST_REQUIRE_EQUAL(e_log2.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_log2.get_int(), 6); - - // Boolean Logic - expression_container::expr_list_type e_true{E(true)}; - expression_container::expr_list_type e_false{E(false)}; - BOOST_CHECK(ft->eval("TRUE", no_args, empty_arg_list).to_bool()); - BOOST_CHECK(ft->eval("TRUE", no_args, empty_arg_list).get_bool()); - BOOST_CHECK_EQUAL(ft->eval("FALSE", no_args, empty_arg_list).to_bool(), false); - BOOST_CHECK_EQUAL(ft->eval("FALSE", no_args, empty_arg_list).get_bool(), false); - BOOST_CHECK(ft->eval("NOT", one_bool_arg, e_false).to_bool()); - - // Control - std::cout << "Checking ~1s sleep until... "; - expression_container::expr_list_type e_sleeptime{E(.999)}; - BOOST_CHECK(ft->eval("SLEEP", one_double_arg, e_sleeptime).get_bool()); - std::cout << "Now." << std::endl; -} - -// Some bogus function to test the registry -expression_literal add_plus2_int(expression_container::expr_list_type args) -{ - return expression_literal(args[0]->eval().get_int() + args[1]->eval().get_int() + 2); -} - -BOOST_AUTO_TEST_CASE(test_add_funcs) -{ - function_table::sptr ft = function_table::make(); - - BOOST_CHECK(not ft->function_exists("ADD_PLUS_2")); - - expression_function::argtype_list_type add_int_args{ - expression::TYPE_INT, expression::TYPE_INT}; - ft->register_function("ADD_PLUS_2", - boost::bind(&add_plus2_int, _1), - expression::TYPE_INT, - add_int_args); - - BOOST_CHECK(ft->function_exists("ADD_PLUS_2")); - BOOST_CHECK(ft->function_exists("ADD_PLUS_2", add_int_args)); - - expression_container::expr_list_type add_int_values{E(2), E(3)}; - expression_literal e = ft->eval("ADD_PLUS_2", two_int_args, add_int_values); - BOOST_REQUIRE_EQUAL(e.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e.get_int(), 7); -} - -int dummy_true_counter = 0; -// Some bogus function to test the registry -expression_literal dummy_true(expression_container::expr_list_type) -{ - dummy_true_counter++; - std::cout << "Running dummy/true statement." << std::endl; - return expression_literal(true); -} - -int dummy_false_counter = 0; -// Some bogus function to test the registry -expression_literal dummy_false(expression_container::expr_list_type) -{ - dummy_false_counter++; - std::cout << "Running dummy/false statement." << std::endl; - return expression_literal(false); -} - -BOOST_AUTO_TEST_CASE(test_conditionals) -{ - function_table::sptr ft = function_table::make(); - ft->register_function( - "DUMMY", boost::bind(&dummy_true, _1), expression::TYPE_BOOL, no_args); - ft->register_function( - "DUMMY_F", boost::bind(&dummy_false, _1), expression::TYPE_BOOL, no_args); - BOOST_REQUIRE(ft->function_exists("DUMMY", no_args)); - BOOST_REQUIRE(ft->function_exists("DUMMY_F", no_args)); - - expression_function::sptr dummy_statement = - boost::make_shared<expression_function>("DUMMY", ft); - expression_function::sptr if_statement = - boost::make_shared<expression_function>("IF", ft); - if_statement->add(E(true)); - if_statement->add(dummy_statement); - - std::cout << "Dummy statement should run once until END:" << std::endl; - dummy_true_counter = 0; - BOOST_CHECK(if_statement->eval().get_bool()); - BOOST_CHECK_EQUAL(dummy_true_counter, 1); - std::cout << "END." << std::endl; - - std::cout << "Dummy statement should not run until END:" << std::endl; - expression_function::sptr if_statement2 = - boost::make_shared<expression_function>("IF", ft); - if_statement2->add(E(false)); - if_statement2->add(dummy_statement); - dummy_true_counter = 0; - BOOST_CHECK(not if_statement2->eval().get_bool()); - BOOST_CHECK_EQUAL(dummy_true_counter, 0); - std::cout << "END." << std::endl; - - expression_function::sptr if_else_statement = - boost::make_shared<expression_function>("IF_ELSE", ft); - expression_function::sptr dummy_statement_f = - boost::make_shared<expression_function>("DUMMY_F", ft); - if_else_statement->add(E(true)); - if_else_statement->add(dummy_statement); - if_else_statement->add(dummy_statement_f); - dummy_true_counter = 0; - dummy_false_counter = 0; - std::cout << "Should execute dummy/true statement before END:" << std::endl; - BOOST_CHECK(if_else_statement->eval().get_bool()); - BOOST_CHECK_EQUAL(dummy_true_counter, 1); - BOOST_CHECK_EQUAL(dummy_false_counter, 0); - std::cout << "END." << std::endl; - - expression_function::sptr if_else_statement2 = - boost::make_shared<expression_function>("IF_ELSE", ft); - if_else_statement2->add(E(false)); - if_else_statement2->add(dummy_statement); - if_else_statement2->add(dummy_statement_f); - dummy_true_counter = 0; - dummy_false_counter = 0; - std::cout << "Should execute dummy/false statement before END:" << std::endl; - BOOST_CHECK(not if_else_statement2->eval().get_bool()); - BOOST_CHECK_EQUAL(dummy_true_counter, 0); - BOOST_CHECK_EQUAL(dummy_false_counter, 1); - std::cout << "END." << std::endl; -} - -BOOST_AUTO_TEST_CASE(test_bitwise_funcs) -{ - function_table::sptr ft = function_table::make(); - BOOST_CHECK(ft->function_exists("SHIFT_RIGHT")); - BOOST_CHECK(ft->function_exists("SHIFT_RIGHT", two_int_args)); - BOOST_CHECK(ft->function_exists("SHIFT_LEFT")); - BOOST_CHECK(ft->function_exists("SHIFT_LEFT", two_int_args)); - BOOST_CHECK(ft->function_exists("BITWISE_AND")); - BOOST_CHECK(ft->function_exists("BITWISE_AND", two_int_args)); - BOOST_CHECK(ft->function_exists("BITWISE_OR")); - BOOST_CHECK(ft->function_exists("BITWISE_OR", two_int_args)); - BOOST_CHECK(ft->function_exists("BITWISE_XOR")); - BOOST_CHECK(ft->function_exists("BITWISE_XOR", two_int_args)); - - // Bitwise Math - int int_value1 = 0x2; - int int_value2 = 0x3; - expression_container::expr_list_type two_int_values{E(int_value1), E(int_value2)}; - - BOOST_REQUIRE_EQUAL(ft->get_type("SHIFT_RIGHT", two_int_args), expression::TYPE_INT); - expression_literal e_shift_right = - ft->eval("SHIFT_RIGHT", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_shift_right.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_shift_right.get_int(), int_value1 >> int_value2); - - BOOST_REQUIRE_EQUAL(ft->get_type("SHIFT_LEFT", two_int_args), expression::TYPE_INT); - expression_literal e_shift_left = - ft->eval("SHIFT_LEFT", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_shift_left.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_shift_left.get_int(), int_value1 << int_value2); - - BOOST_REQUIRE_EQUAL(ft->get_type("BITWISE_AND", two_int_args), expression::TYPE_INT); - expression_literal e_bitwise_and = - ft->eval("BITWISE_AND", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_bitwise_and.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_bitwise_and.get_int(), int_value1 & int_value2); - - BOOST_REQUIRE_EQUAL(ft->get_type("BITWISE_OR", two_int_args), expression::TYPE_INT); - expression_literal e_bitwise_or = - ft->eval("BITWISE_OR", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_bitwise_or.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_bitwise_or.get_int(), int_value1 | int_value2); - - BOOST_REQUIRE_EQUAL(ft->get_type("BITWISE_XOR", two_int_args), expression::TYPE_INT); - expression_literal e_bitwise_xor = - ft->eval("BITWISE_XOR", two_int_args, two_int_values); - BOOST_REQUIRE_EQUAL(e_bitwise_xor.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(e_bitwise_xor.get_int(), int_value1 ^ int_value2); -} diff --git a/host/tests/nocscript_parser_test.cpp b/host/tests/nocscript_parser_test.cpp deleted file mode 100644 index eb9352995..000000000 --- a/host/tests/nocscript_parser_test.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright 2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "../lib/rfnoc/nocscript/function_table.hpp" -#include "../lib/rfnoc/nocscript/parser.hpp" -#include "nocscript_common.hpp" -#include <uhd/exception.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/bind.hpp> -#include <boost/make_shared.hpp> -#include <boost/test/floating_point_comparison.hpp> -#include <boost/test/unit_test.hpp> -#include <algorithm> -#include <iostream> - -const int SPP_VALUE = 64; - -// Need those for the variable testing: -expression::type_t variable_get_type(const std::string& var_name) -{ - if (var_name == "spp") { - std::cout << "Returning type for $spp..." << std::endl; - return expression::TYPE_INT; - } - if (var_name == "is_true") { - std::cout << "Returning type for $is_true..." << std::endl; - return expression::TYPE_BOOL; - } - - throw uhd::syntax_error("Cannot infer type (unknown variable)"); -} - -expression_literal variable_get_value(const std::string& var_name) -{ - if (var_name == "spp") { - std::cout << "Returning value for $spp..." << std::endl; - return expression_literal(SPP_VALUE); - } - if (var_name == "is_true") { - std::cout << "Returning value for $is_true..." << std::endl; - return expression_literal(true); - } - - throw uhd::syntax_error("Cannot read value (unknown variable)"); -} - -#define SETUP_FT_AND_PARSER() \ - function_table::sptr ft = function_table::make(); \ - parser::sptr p = parser::make( \ - ft, boost::bind(&variable_get_type, _1), boost::bind(&variable_get_value, _1)); - -BOOST_AUTO_TEST_CASE(test_fail) -{ - SETUP_FT_AND_PARSER(); - - // Missing closing parens: - BOOST_REQUIRE_THROW(p->create_expr_tree("ADD1(1, "), uhd::syntax_error); - // Double comma: - BOOST_REQUIRE_THROW(p->create_expr_tree("ADD(1,, 2)"), uhd::syntax_error); - // No comma: - BOOST_REQUIRE_THROW(p->create_expr_tree("ADD(1 2)"), uhd::syntax_error); - // Double closing parens: - BOOST_REQUIRE_THROW(p->create_expr_tree("ADD(1, 2))"), uhd::syntax_error); - // Unknown function: - BOOST_REQUIRE_THROW(p->create_expr_tree("GLORPGORP(1, 2)"), uhd::syntax_error); -} - -BOOST_AUTO_TEST_CASE(test_adds_no_vars) -{ - SETUP_FT_AND_PARSER(); - BOOST_REQUIRE(ft->function_exists("ADD")); - - const std::string line("ADD(1, ADD(2, ADD(3, 4)))"); - expression::sptr e = p->create_expr_tree(line); - expression_literal result = e->eval(); - - BOOST_REQUIRE_EQUAL(result.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(result.get_int(), 1 + 2 + 3 + 4); -} - -BOOST_AUTO_TEST_CASE(test_adds_with_vars) -{ - SETUP_FT_AND_PARSER(); - - const std::string line("ADD(1, ADD(2, $spp))"); - expression::sptr e = p->create_expr_tree(line); - expression_literal result = e->eval(); - - BOOST_REQUIRE_EQUAL(result.infer_type(), expression::TYPE_INT); - BOOST_CHECK_EQUAL(result.get_int(), 1 + 2 + SPP_VALUE); -} - -BOOST_AUTO_TEST_CASE(test_fft_check) -{ - SETUP_FT_AND_PARSER(); - - const std::string line("GE($spp, 16) AND LE($spp, 4096) AND IS_PWR_OF_2($spp)"); - expression::sptr e = p->create_expr_tree(line); - expression_literal result = e->eval(); - - BOOST_REQUIRE_EQUAL(result.infer_type(), expression::TYPE_BOOL); - BOOST_CHECK(result.get_bool()); -} - -BOOST_AUTO_TEST_CASE(test_pure_string) -{ - SETUP_FT_AND_PARSER(); - - // Eval all, return last expression - const std::string line("'foo foo', \"bar\""); - expression_literal result = p->create_expr_tree(line)->eval(); - - BOOST_REQUIRE_EQUAL(result.infer_type(), expression::TYPE_STRING); - BOOST_CHECK_EQUAL(result.get_string(), "bar"); -} - -int dummy_false_counter = 0; -expression_literal dummy_false(expression_container::expr_list_type) -{ - dummy_false_counter++; - std::cout << "Running dummy/false statement." << std::endl; - return expression_literal(false); -} - -BOOST_AUTO_TEST_CASE(test_multi_commmand) -{ - SETUP_FT_AND_PARSER(); - - ft->register_function( - "DUMMY", boost::bind(&dummy_false, _1), expression::TYPE_BOOL, no_args); - - dummy_false_counter = 0; - p->create_expr_tree("DUMMY(), DUMMY(), DUMMY()")->eval(); - BOOST_CHECK_EQUAL(dummy_false_counter, 3); - - dummy_false_counter = 0; - p->create_expr_tree("DUMMY() AND DUMMY() AND DUMMY()")->eval(); - BOOST_CHECK_EQUAL(dummy_false_counter, 1); - - dummy_false_counter = 0; - p->create_expr_tree("DUMMY() OR DUMMY() OR DUMMY()")->eval(); - BOOST_CHECK_EQUAL(dummy_false_counter, 3); -} diff --git a/host/tests/node_connect_test.cpp b/host/tests/node_connect_test.cpp deleted file mode 100644 index 97d052a06..000000000 --- a/host/tests/node_connect_test.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "graph.hpp" -#include <boost/test/unit_test.hpp> -#include <iostream> - -using namespace uhd::rfnoc; - -class source_node : public test_node -{ -public: - typedef boost::shared_ptr<source_node> sptr; - - source_node(const std::string& test_id, size_t output_port) - : test_node(test_id), active_rx_streamer_on_port(0), _output_port(output_port){}; - - void set_rx_streamer(bool active, const size_t port) - { - if (active) { - std::cout << "[source_node] Someone is registering a rx streamer on port " - << port << std::endl; - active_rx_streamer_on_port = port; - } - } - size_t active_rx_streamer_on_port; - -protected: - size_t _request_output_port(const size_t, const uhd::device_addr_t&) const - { - return _output_port; - } - - const size_t _output_port; - -}; /* class result_node */ - -class sink_node : public test_node -{ -public: - typedef boost::shared_ptr<sink_node> sptr; - - sink_node(const std::string& test_id, size_t input_port) - : test_node(test_id), active_tx_streamer_on_port(0), _input_port(input_port){}; - - void set_tx_streamer(bool active, const size_t port) - { - if (active) { - std::cout << "[sink_node] Someone is registering a tx streamer on port " - << port << std::endl; - active_tx_streamer_on_port = port; - } - } - size_t active_tx_streamer_on_port; - -protected: - size_t _request_input_port(const size_t, const uhd::device_addr_t&) const - { - return _input_port; - } - - const size_t _input_port; - -}; /* class result_node */ - -#define MAKE_SOURCE_NODE(name, port) source_node::sptr name(new source_node(#name, port)); -#define MAKE_SINK_NODE(name, port) sink_node::sptr name(new sink_node(#name, port)); - -BOOST_AUTO_TEST_CASE(test_simple_connect) -{ - MAKE_SOURCE_NODE(node_A, 42); - MAKE_SINK_NODE(node_B, 23); - - size_t src_port = node_A->connect_downstream(node_B, 1); - size_t dst_port = node_B->connect_upstream(node_A, 2); - - BOOST_CHECK_EQUAL(src_port, 42); - BOOST_CHECK_EQUAL(dst_port, 23); - - node_A->set_downstream_port(src_port, dst_port); - node_B->set_upstream_port(dst_port, src_port); - BOOST_CHECK_EQUAL(node_A->get_downstream_port(src_port), dst_port); - BOOST_CHECK_EQUAL(node_B->get_upstream_port(dst_port), src_port); - - BOOST_REQUIRE_THROW(node_A->get_downstream_port(999), uhd::value_error); -} - -BOOST_AUTO_TEST_CASE(test_fail) -{ - MAKE_SOURCE_NODE(node_A, 42); - MAKE_SINK_NODE(node_B, ANY_PORT); - - node_A->connect_downstream(node_B, 1); - BOOST_REQUIRE_THROW(node_B->connect_upstream(node_A, 2), uhd::type_error); -} - -BOOST_AUTO_TEST_CASE(test_set_streamers) -{ - MAKE_SOURCE_NODE(node_A, 0); - MAKE_NODE(node_B); - MAKE_SINK_NODE(node_C, 0); - - size_t src_port_A = node_A->connect_downstream(node_B, 0); - size_t src_port_B = node_B->connect_downstream(node_C, 0); - size_t dst_port_B = node_B->connect_upstream(node_A, 0); - size_t dst_port_C = node_C->connect_upstream(node_B, 0); - - std::cout << "src_port_A: " << src_port_A << std::endl; - std::cout << "src_port_B: " << src_port_B << std::endl; - std::cout << "dst_port_B: " << dst_port_B << std::endl; - std::cout << "dst_port_C: " << dst_port_C << std::endl; - - node_A->set_downstream_port(src_port_A, dst_port_B); - node_B->set_upstream_port(dst_port_B, src_port_A); - node_B->set_downstream_port(src_port_B, dst_port_C); - node_C->set_upstream_port(dst_port_C, src_port_B); - - node_A->set_tx_streamer(true, 0); - node_C->set_rx_streamer(true, 0); - - BOOST_CHECK_EQUAL(node_A->active_rx_streamer_on_port, src_port_A); - BOOST_CHECK_EQUAL(node_C->active_tx_streamer_on_port, dst_port_C); -} diff --git a/host/tests/packet_handler_benchmark.cpp b/host/tests/packet_handler_benchmark.cpp index 6d4849831..d0a28bdc2 100644 --- a/host/tests/packet_handler_benchmark.cpp +++ b/host/tests/packet_handler_benchmark.cpp @@ -13,13 +13,11 @@ #include "../lib/transport/super_recv_packet_handler.hpp" #include "../lib/transport/super_send_packet_handler.hpp" -#include "../lib/usrp/device3/device3_flow_ctrl.hpp" #include "common/mock_zero_copy.hpp" #include <uhd/convert.hpp> #include <uhd/transport/chdr.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/transport/zero_copy_flow_ctrl.hpp> -#include <uhd/types/sid.hpp> #include <uhd/utils/safe_main.hpp> #include <uhd/utils/thread.hpp> #include <boost/program_options.hpp> @@ -47,7 +45,6 @@ struct rx_fc_cache_t uint32_t total_packets_consumed = 0; //! Sequence number of next flow control packet uint64_t seq_num = 0; - uhd::sid_t sid; uhd::transport::zero_copy_if::sptr xport; std::function<uint32_t(uint32_t)> to_host; std::function<uint32_t(uint32_t)> from_host; @@ -155,8 +152,7 @@ inline bool tx_flow_ctrl(boost::shared_ptr<tx_fc_cache_t> fc_cache, } inline void tx_flow_ctrl_ack(boost::shared_ptr<tx_fc_cache_t> fc_cache, - uhd::transport::zero_copy_if::sptr /*send_xport*/, - uhd::sid_t /*send_sid*/) + uhd::transport::zero_copy_if::sptr /*send_xport*/) { if (not fc_cache->fc_received) { return; @@ -296,7 +292,7 @@ void benchmark_send_packet_handler( // Configure flow control ack streamer->set_xport_chan_post_send_cb(0, [fc_cache, zero_copy_xport]() { - tx_flow_ctrl_ack(fc_cache, zero_copy_xport, 0); + tx_flow_ctrl_ack(fc_cache, zero_copy_xport); }); // Allocate buffer diff --git a/host/tests/rate_node_test.cpp b/host/tests/rate_node_test.cpp deleted file mode 100644 index 85502c325..000000000 --- a/host/tests/rate_node_test.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "graph.hpp" -#include <uhd/rfnoc/rate_node_ctrl.hpp> -#include <boost/test/unit_test.hpp> -#include <iostream> - -using namespace uhd::rfnoc; - -// test class derived, knows about rates -class rate_aware_node : public test_node, public rate_node_ctrl -{ -public: - typedef boost::shared_ptr<rate_aware_node> sptr; - - rate_aware_node(const std::string& test_id) : test_node(test_id){}; - -}; /* class rate_aware_node */ - -// test class derived, sets rates -class rate_setting_node : public test_node, public rate_node_ctrl -{ -public: - typedef boost::shared_ptr<rate_setting_node> sptr; - - rate_setting_node(const std::string& test_id, double samp_rate) - : test_node(test_id), _samp_rate(samp_rate){}; - - double get_input_samp_rate(size_t) - { - return _samp_rate; - }; - double get_output_samp_rate(size_t) - { - return _samp_rate; - }; - -private: - double _samp_rate; - -}; /* class rate_setting_node */ - -#define MAKE_RATE_NODE(name) rate_aware_node::sptr name(new rate_aware_node(#name)); -#define MAKE_RATE_SETTING_NODE(name, rate) \ - rate_setting_node::sptr name(new rate_setting_node(#name, rate)); - -BOOST_AUTO_TEST_CASE(test_simplest_downstream_search) -{ - const double test_rate = 0.25; - MAKE_RATE_NODE(node_A); - MAKE_RATE_SETTING_NODE(node_B, test_rate); - - // Simplest possible scenario: Connect B downstream of A and let - // it find B - connect_nodes(node_A, node_B); - - double result_rate = node_A->get_input_samp_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_skip_downstream_search) -{ - const double test_rate = 0.25; - MAKE_RATE_NODE(node_A); - MAKE_NODE(node_B); - MAKE_RATE_SETTING_NODE(node_C, test_rate); - - // Slightly more elaborate: Add another block in between that has no - // clue about rates - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - - double result_rate = node_A->get_input_samp_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_tree_downstream_search) -{ - const double test_rate = 0.25; - MAKE_RATE_NODE(node_A); - MAKE_NODE(node_B0); - MAKE_RATE_SETTING_NODE(node_B1, test_rate); - MAKE_RATE_SETTING_NODE(node_C0, test_rate); - MAKE_RATE_SETTING_NODE(node_C1, rate_node_ctrl::RATE_UNDEFINED); - - // Tree: Downstream of our first node are 3 rate setting blocks. - // Two set the same rate, the third does not care. - connect_nodes(node_A, node_B0); - connect_nodes(node_A, node_B1); - connect_nodes(node_B0, node_C0); - connect_nodes(node_B0, node_C1); - - double result_rate = node_A->get_input_samp_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_tree_downstream_search_throw) -{ - const double test_rate = 0.25; - MAKE_RATE_NODE(node_A); - MAKE_NODE(node_B0); - MAKE_RATE_SETTING_NODE(node_B1, test_rate); - MAKE_RATE_SETTING_NODE(node_C0, test_rate); - MAKE_RATE_SETTING_NODE(node_C1, test_rate * 2); - - // Tree: Downstream of our first node are 3 rate setting blocks. - // Two set the same rate, the third has a different rate. - // This will cause a throw. - connect_nodes(node_A, node_B0); - connect_nodes(node_A, node_B1); - connect_nodes(node_B0, node_C0); - connect_nodes(node_B0, node_C1); - - BOOST_CHECK_THROW(node_A->get_input_samp_rate(), uhd::runtime_error); -} - -BOOST_AUTO_TEST_CASE(test_skip_upstream_search) -{ - const double test_rate = 0.25; - MAKE_RATE_SETTING_NODE(node_A, test_rate); - MAKE_NODE(node_B); - MAKE_RATE_NODE(node_C); - - // Slightly more elaborate: Add another block in between that has no - // clue about rates - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - - double result_rate = node_C->get_output_samp_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} diff --git a/host/tests/sid_t_test.cpp b/host/tests/sid_t_test.cpp deleted file mode 100644 index 2a13995df..000000000 --- a/host/tests/sid_t_test.cpp +++ /dev/null @@ -1,155 +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/exception.hpp> -#include <uhd/types/sid.hpp> -#include <boost/test/unit_test.hpp> -#include <iostream> -#include <sstream> - -using uhd::sid_t; - -BOOST_AUTO_TEST_CASE(test_sid_t) -{ - uint32_t sid_value = 0x01020310; - sid_t sid(sid_value); - - BOOST_CHECK_EQUAL(sid.is_set(), true); - BOOST_CHECK_EQUAL(sid.to_pp_string(), "1.2>3.16"); - BOOST_CHECK_EQUAL(sid.to_pp_string_hex(), "01:02>03:10"); - BOOST_CHECK_EQUAL(sid.get_src(), (uint32_t)0x0102); - BOOST_CHECK_EQUAL(sid.get_dst(), (uint32_t)0x0310); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x01); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x10); - BOOST_CHECK_EQUAL(sid == sid, true); - BOOST_CHECK_EQUAL(sid == sid_value, true); - - uint32_t check_sid_val = (uint32_t)sid; - BOOST_CHECK_EQUAL(check_sid_val, sid_value); - - std::stringstream ss_dec; - ss_dec << sid; - BOOST_CHECK_EQUAL(ss_dec.str(), "1.2>3.16"); - - std::stringstream ss_hex; - ss_hex << std::hex << sid; - BOOST_CHECK_EQUAL(ss_hex.str(), "01:02>03:10"); - - sid_t empty_sid; - BOOST_CHECK_EQUAL(empty_sid.is_set(), false); - BOOST_CHECK_EQUAL(empty_sid.to_pp_string(), "x.x>x.x"); - BOOST_CHECK_EQUAL(empty_sid.to_pp_string_hex(), "xx:xx>xx:xx"); - BOOST_CHECK_EQUAL(empty_sid == sid, false); - BOOST_CHECK_EQUAL(empty_sid == sid_value, false); - BOOST_CHECK_EQUAL((bool)empty_sid, false); - - empty_sid = sid_value; // No longer empty - BOOST_CHECK_EQUAL(empty_sid.is_set(), true); - BOOST_CHECK_EQUAL(empty_sid == sid, true); -} - -BOOST_AUTO_TEST_CASE(test_sid_t_set) -{ - uint32_t sid_value = 0x0; - sid_t sid(sid_value); - - sid.set(0x01020304); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x01020304); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x01); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04); - BOOST_CHECK_EQUAL(sid.get_dst_xbarport(), (uint32_t)0x0); - BOOST_CHECK_EQUAL(sid.get_dst_blockport(), (uint32_t)0x4); - - sid.set_src_addr(0x0a); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a020304); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x02); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04); - - sid.set_src_endpoint(0x0b); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0304); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x03); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04); - - sid.set_dst_addr(0x0c); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0c04); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x04); - - sid.set_dst_endpoint(0x0d); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0c0d); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0x0d); - - sid.set_dst_xbarport(0xb); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0cbd); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0xbd); - - sid.set_dst_blockport(0xc); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0a0b0cbc); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)0x0a); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)0x0b); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)0x0c); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)0xbc); - - const sid_t flipped_sid = sid.reversed(); - BOOST_CHECK_EQUAL(flipped_sid.get(), (uint32_t)0x0cbc0a0b); - BOOST_CHECK_EQUAL(flipped_sid.reversed(), sid); - - const sid_t sid2 = sid_t(sid.get_sid()); - BOOST_CHECK_EQUAL(sid2, sid); - - // In-place - sid.reverse(); - BOOST_CHECK_EQUAL(sid.get(), (uint32_t)0x0cbc0a0b); -} - -BOOST_AUTO_TEST_CASE(test_sid_t_from_str) -{ - sid_t sid("1.2>3.4"); - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)4); - - sid = "01:02>03:10"; - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16); - - sid = "01:06/03:10"; - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)6); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)3); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16); - - sid = "01:02:04:10"; - BOOST_CHECK_EQUAL(sid.get_src_addr(), (uint32_t)1); - BOOST_CHECK_EQUAL(sid.get_src_endpoint(), (uint32_t)2); - BOOST_CHECK_EQUAL(sid.get_dst_addr(), (uint32_t)4); - BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), (uint32_t)16); - - BOOST_REQUIRE_THROW(sid_t fail_sid("foobar"), uhd::value_error); - BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:4"), uhd::value_error); - BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:004"), uhd::value_error); - BOOST_REQUIRE_THROW(sid_t fail_sid("1.2.3.0004"), uhd::value_error); -} diff --git a/host/tests/stream_sig_test.cpp b/host/tests/stream_sig_test.cpp deleted file mode 100644 index 41c07c14f..000000000 --- a/host/tests/stream_sig_test.cpp +++ /dev/null @@ -1,75 +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/stream_sig.hpp> -#include <boost/test/unit_test.hpp> -#include <iostream> - -using namespace uhd::rfnoc; - -BOOST_AUTO_TEST_CASE(test_stream_sig) -{ - stream_sig_t stream_sig; - - BOOST_CHECK_EQUAL(stream_sig.item_type, ""); - BOOST_CHECK_EQUAL(stream_sig.vlen, 0); - BOOST_CHECK_EQUAL(stream_sig.packet_size, 0); - BOOST_CHECK_EQUAL(stream_sig.is_bursty, false); - - std::stringstream ss; - ss << stream_sig; - // Eventually actually test the contents - std::cout << ss.str() << std::endl; -} - -BOOST_AUTO_TEST_CASE(test_stream_sig_compat) -{ - stream_sig_t upstream_sig; - stream_sig_t downstream_sig; - - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.vlen = 32; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - downstream_sig.vlen = 32; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.vlen = 16; - BOOST_CHECK(not stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.vlen = 32; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.packet_size = 8; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - downstream_sig.packet_size = 12; - BOOST_CHECK(not stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.packet_size = 0; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - downstream_sig.item_type = ""; - BOOST_CHECK(stream_sig_t::is_compatible(upstream_sig, downstream_sig)); - upstream_sig.item_type = "sc16"; - downstream_sig.item_type = "s8"; - BOOST_CHECK(not stream_sig_t::is_compatible(upstream_sig, downstream_sig)); -} - -BOOST_AUTO_TEST_CASE(test_stream_sig_types) -{ - stream_sig_t stream_sig; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 0); - stream_sig.item_type = "sc16"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 4); - stream_sig.item_type = "sc12"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 3); - stream_sig.item_type = "sc8"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 2); - stream_sig.item_type = "s16"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 2); - stream_sig.item_type = "s8"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 1); - stream_sig.item_type = "fc32"; - BOOST_CHECK_EQUAL(stream_sig.get_bytes_per_item(), 8); - stream_sig.item_type = "not_a_type"; - BOOST_REQUIRE_THROW(stream_sig.get_bytes_per_item(), uhd::key_error); -} diff --git a/host/tests/tick_node_test.cpp b/host/tests/tick_node_test.cpp deleted file mode 100644 index ccec67c43..000000000 --- a/host/tests/tick_node_test.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "graph.hpp" -#include <uhd/rfnoc/tick_node_ctrl.hpp> -#include <boost/test/unit_test.hpp> -#include <iostream> - -using namespace uhd::rfnoc; - -// test class derived, knows about rates -class tick_aware_node : public test_node, public tick_node_ctrl -{ -public: - typedef boost::shared_ptr<tick_aware_node> sptr; - - tick_aware_node(const std::string& test_id) : test_node(test_id){}; - -}; /* class tick_aware_node */ - -// test class derived, sets rates -class tick_setting_node : public test_node, public tick_node_ctrl -{ -public: - typedef boost::shared_ptr<tick_setting_node> sptr; - - tick_setting_node(const std::string& test_id, double tick_rate) - : test_node(test_id), _tick_rate(tick_rate){}; - -protected: - double _get_tick_rate() - { - return _tick_rate; - }; - -private: - const double _tick_rate; - -}; /* class tick_setting_node */ - -#define MAKE_TICK_NODE(name) tick_aware_node::sptr name(new tick_aware_node(#name)); -#define MAKE_TICK_SETTING_NODE(name, rate) \ - tick_setting_node::sptr name(new tick_setting_node(#name, rate)); - -BOOST_AUTO_TEST_CASE(test_simplest_downstream_search) -{ - const double test_rate = 0.25; - MAKE_TICK_NODE(node_A); - MAKE_TICK_SETTING_NODE(node_B, test_rate); - - // Simplest possible scenario: Connect B downstream of A and let - // it find B - connect_nodes(node_A, node_B); - node_A->set_tx_streamer(true, 0); - node_B->set_rx_streamer(true, 0); - - double result_rate = node_A->get_tick_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_both_ways_search) -{ - const double test_rate = 0.25; - MAKE_TICK_SETTING_NODE(node_A, tick_node_ctrl::RATE_UNDEFINED); - MAKE_TICK_NODE(node_B); - MAKE_TICK_SETTING_NODE(node_C, test_rate); - - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - node_A->set_tx_streamer(true, 0); - node_B->set_tx_streamer(true, 0); - node_B->set_rx_streamer(true, 0); - node_C->set_rx_streamer(true, 0); - - double result_rate = node_B->get_tick_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_both_ways_search_reversed) -{ - const double test_rate = 0.25; - MAKE_TICK_SETTING_NODE(node_A, test_rate); - MAKE_TICK_NODE(node_B); - MAKE_TICK_SETTING_NODE(node_C, tick_node_ctrl::RATE_UNDEFINED); - - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - node_A->set_tx_streamer(true, 0); - node_B->set_tx_streamer(true, 0); - node_B->set_rx_streamer(true, 0); - node_C->set_rx_streamer(true, 0); - - double result_rate = node_B->get_tick_rate(); - BOOST_CHECK_EQUAL(result_rate, test_rate); -} - -BOOST_AUTO_TEST_CASE(test_both_ways_search_fail) -{ - const double test_rate = 0.25; - MAKE_TICK_SETTING_NODE(node_A, test_rate); - MAKE_TICK_NODE(node_B); - MAKE_TICK_SETTING_NODE(node_C, 2 * test_rate); - - connect_nodes(node_A, node_B); - connect_nodes(node_B, node_C); - node_A->set_tx_streamer(true, 0); - node_B->set_tx_streamer(true, 0); - node_B->set_rx_streamer(true, 0); - node_C->set_rx_streamer(true, 0); - - BOOST_CHECK_THROW(node_B->get_tick_rate(), uhd::runtime_error); -} diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 834c69c19..8542f30bb 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -165,7 +165,7 @@ add_subdirectory(rfnoc) set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/build/timestamp") set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py") -set(CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/share/uhd") +set(CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/${PKG_DATA_DIR}") # construct site-package folder from install prefix execute_process(COMMAND ${PYTHON_EXECUTABLE} -c diff --git a/host/utils/rfnoc/image_builder.py b/host/utils/rfnoc/image_builder.py index 0ed75dcc2..df3cfc3f1 100755 --- a/host/utils/rfnoc/image_builder.py +++ b/host/utils/rfnoc/image_builder.py @@ -449,7 +449,7 @@ def collect_module_paths(config_path): :return: list of noc block directories """ # rfnoc blocks - result = [os.path.join(config_path, 'erfnoc', 'blocks')] + result = [os.path.join(config_path, 'rfnoc', 'blocks')] # additional OOT blocks # TODO parse modules from external includes as well return result @@ -675,7 +675,7 @@ def get_core_config_path(config_path): """ returns the path where core configuration files are stored """ - return os.path.join(config_path, 'erfnoc', 'core') + return os.path.join(config_path, 'rfnoc', 'core') def generate_image_core_path(output_path, source): """ diff --git a/host/utils/rfnoc_blocktool/templates/Makefile b/host/utils/rfnoc_blocktool/templates/Makefile index 25e61c05b..ca397bf7d 100644 --- a/host/utils/rfnoc_blocktool/templates/Makefile +++ b/host/utils/rfnoc_blocktool/templates/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2019 Ettus Research, A National Instruments Company +# Copyright 2019 Ettus Research, A National Instruments Brand # # SPDX-License-Identifier: LGPL-3.0-or-later # @@ -16,26 +16,26 @@ include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak # Design Specific #------------------------------------------------- # Include makefiles and sources for the DUT and its dependencies -include $(BASE_DIR)/../lib/erfnoc/core/Makefile.srcs -include $(BASE_DIR)/../lib/erfnoc/utils/Makefile.srcs +include $(BASE_DIR)/../lib/rfnoc/core/Makefile.srcs +include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs include Makefile.srcs DESIGN_SRCS += $(abspath ${"\\"} $(RFNOC_CORE_SRCS) ${"\\"} $(RFNOC_UTIL_SRCS) ${"\\"} -$(RFNOC_BLOCK_${config.module_name.upper()}_SRCS) ${"\\"} +$(RFNOC_BLOCK_${config['module_name'].upper()}_SRCS) ${"\\"} ) #------------------------------------------------- # Testbench Specific #------------------------------------------------- -include $(BASE_DIR)/../sim/erfnoc/Makefile.srcs +include $(BASE_DIR)/../sim/rfnoc/Makefile.srcs -SIM_TOP = rfnoc_block_${config.module_name}_tb +SIM_TOP = rfnoc_block_${config['module_name']}_tb SIM_SRCS = ${"\\"} -$(abspath rfnoc_block_${config.module_name}_tb.sv) ${"\\"} -$(SIM_ERFNOC_SRCS) +$(abspath rfnoc_block_${config['module_name']}_tb.sv) ${"\\"} +$(SIM_RFNOC_SRCS) # MODELSIM_USER_DO = $(abspath wave.do) diff --git a/host/utils/rfnoc_blocktool/templates/Makefile.srcs b/host/utils/rfnoc_blocktool/templates/Makefile.srcs index f346007af..67fcb1ccc 100644 --- a/host/utils/rfnoc_blocktool/templates/Makefile.srcs +++ b/host/utils/rfnoc_blocktool/templates/Makefile.srcs @@ -7,7 +7,7 @@ ${'##################################################'} # RFNoC Utility Sources ${'##################################################'} -RFNOC_BLOCK_${config.module_name.upper()}_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/erfnoc/blocks/${destination}/, ${"\\"} -rfnoc_block_${config.module_name}.v ${"\\"} -noc_shell_${config.module_name}.v ${"\\"} +RFNOC_BLOCK_${config['module_name'].upper()}_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/rfnoc/blocks/${destination}/, ${"\\"} +rfnoc_block_${config['module_name']}.v ${"\\"} +noc_shell_${config['module_name']}.v ${"\\"} )) diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp index c35a5af23..7fd42941e 100644 --- a/host/utils/uhd_usrp_probe.cpp +++ b/host/utils/uhd_usrp_probe.cpp @@ -6,7 +6,6 @@ // #include <uhd/device.hpp> -#include <uhd/device3.hpp> #include <uhd/property_tree.hpp> #include <uhd/types/ranges.hpp> #include <uhd/types/sensors.hpp> diff --git a/mpm/include/mpm/CMakeLists.txt b/mpm/include/mpm/CMakeLists.txt index f3637c913..d4caff1c4 100644 --- a/mpm/include/mpm/CMakeLists.txt +++ b/mpm/include/mpm/CMakeLists.txt @@ -4,7 +4,6 @@ # SPDX-License-Identifier: GPL-3.0-or-later # install(FILES - xbar_iface.hpp exception.hpp DESTINATION ${INCLUDE_DIR}/mpm ) diff --git a/mpm/include/mpm/xbar_iface.hpp b/mpm/include/mpm/xbar_iface.hpp deleted file mode 100644 index bf4399593..000000000 --- a/mpm/include/mpm/xbar_iface.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright 2017 Ettus Research, a National Instruments Company -// Copyright 2019 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: GPL-3.0-or-later -// -#pragma once -#include <boost/noncopyable.hpp> -#include <cstdint> -#include <memory> -#include <mutex> - -namespace mpm { - -/*! - * Crossbar route command - */ -using rfnoc_crossbar_cmd = struct rfnoc_crossbar_cmd -{ - /*! destination address */ - uint8_t dest_addr; - /*! destination port */ - uint8_t dest_port; -}; - -#define RFNCBWROUTIOC _IOW('R', 1, struct rfnoc_crossbar_cmd) -#define RFNCDELROUTIOC _IOW('D', 1, struct rfnoc_crossbar_cmd) - -/*! - * Crossbar interface class holding a crossbar context - */ -class xbar_iface : boost::noncopyable -{ -public: - // use static mutex! lock_guard - using sptr = std::shared_ptr<xbar_iface>; - static sptr make(const std::string& device); - void set_route(uint8_t dst_addr, uint8_t dst_port); - void del_route(uint8_t dst_addr, uint8_t dst_port); - ~xbar_iface(); - xbar_iface(const std::string& device); - -private: - static std::mutex _lock; - int _fd; -}; -} // namespace mpm - - -#ifdef LIBMPM_PYTHON -void export_xbar(py::module& top_module) -{ - auto m = top_module.def_submodule("xbar"); - - py::class_<mpm::xbar_iface, std::shared_ptr<mpm::xbar_iface>>(m, "xbar") - .def(py::init(&mpm::xbar_iface::make)) - .def("set_route", &mpm::xbar_iface::set_route) - .def("del_route", &mpm::xbar_iface::del_route); -} -#endif diff --git a/mpm/lib/CMakeLists.txt b/mpm/lib/CMakeLists.txt index 82a5d8e16..940a23138 100644 --- a/mpm/lib/CMakeLists.txt +++ b/mpm/lib/CMakeLists.txt @@ -20,7 +20,6 @@ endif(ENABLE_MYKONOS) USRP_PERIPHS_ADD_OBJECT(periphs exception.cpp - xbar_iface.cpp ${UHD_HOST_ROOT}/lib/exception.cpp ) diff --git a/mpm/lib/xbar_iface.cpp b/mpm/lib/xbar_iface.cpp deleted file mode 100644 index 05d1e2053..000000000 --- a/mpm/lib/xbar_iface.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright 2017 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "mpm/xbar_iface.hpp" -#include <fcntl.h> -#include <mpm/exception.hpp> -#include <sys/ioctl.h> -#include <boost/format.hpp> - -using namespace mpm; - -std::mutex xbar_iface::_lock; // Initialize lock for all objects - -xbar_iface::xbar_iface(const std::string& device) -{ - _fd = open(device.c_str(), O_RDWR); -} - -xbar_iface::~xbar_iface() -{ - close(_fd); -} - -void xbar_iface::set_route(uint8_t dst_addr, uint8_t dst_port) -{ - std::lock_guard<std::mutex> lock(_lock); - rfnoc_crossbar_cmd cmd = {.dest_addr = dst_addr, .dest_port = dst_port}; - int err = ioctl(_fd, RFNCBWROUTIOC, &cmd); - if (err < 0) { - throw mpm::os_error( - str(boost::format("setting crossbar route failed! Error: %d") % err)); - } -} - -void xbar_iface::del_route(uint8_t dst_addr, uint8_t dst_port) -{ - std::lock_guard<std::mutex> lock(_lock); - rfnoc_crossbar_cmd cmd = {.dest_addr = dst_addr, .dest_port = dst_port}; - int err = ioctl(_fd, RFNCDELROUTIOC, &cmd); - if (err < 0) { - throw mpm::os_error( - str(boost::format("deleting crossbar route failed! Error: %d") % err)); - } -} - -xbar_iface::sptr xbar_iface::make(const std::string& device) -{ - return std::make_shared<xbar_iface>(device); -} diff --git a/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp index b7971407c..ffd32edbf 100644 --- a/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp +++ b/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp @@ -18,13 +18,11 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, boost::shared_ptr<T>); #include <mpm/dboards/e31x_db_manager.hpp> #include <mpm/spi/spi_python.hpp> #include <mpm/types/types_python.hpp> -#include <mpm/xbar_iface.hpp> PYBIND11_MODULE(libpyusrp_periphs, m) { export_types(m); export_spi(m); - export_xbar(m); export_catalina(m); export_e31x_db(m); } diff --git a/mpm/python/pyusrp_periphs/e320/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs/e320/pyusrp_periphs.cpp index 74a3647db..2a3c01064 100644 --- a/mpm/python/pyusrp_periphs/e320/pyusrp_periphs.cpp +++ b/mpm/python/pyusrp_periphs/e320/pyusrp_periphs.cpp @@ -18,13 +18,11 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, boost::shared_ptr<T>); #include <mpm/dboards/neon_manager.hpp> #include <mpm/spi/spi_python.hpp> #include <mpm/types/types_python.hpp> -#include <mpm/xbar_iface.hpp> PYBIND11_MODULE(libpyusrp_periphs, m) { export_types(m); export_spi(m); - export_xbar(m); export_catalina(m); export_neon(m); } diff --git a/mpm/python/pyusrp_periphs/n3xx/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs/n3xx/pyusrp_periphs.cpp index d4c430f72..4719f486e 100644 --- a/mpm/python/pyusrp_periphs/n3xx/pyusrp_periphs.cpp +++ b/mpm/python/pyusrp_periphs/n3xx/pyusrp_periphs.cpp @@ -19,7 +19,6 @@ PYBIND11_DECLARE_HOLDER_TYPE(T, boost::shared_ptr<T>); #include <mpm/i2c/i2c_python.hpp> #include <mpm/spi/spi_python.hpp> #include <mpm/types/types_python.hpp> -#include <mpm/xbar_iface.hpp> PYBIND11_MODULE(libpyusrp_periphs, m) { @@ -27,6 +26,5 @@ PYBIND11_MODULE(libpyusrp_periphs, m) export_spi(m); export_i2c(m); export_mykonos(m); - export_xbar(m); export_magnesium(m); } |