diff options
| author | Martin Braun <martin.braun@ettus.com> | 2019-05-24 14:46:39 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:16 -0800 | 
| commit | 1ed37cdfda93e430037ee4028ec5ac70ab223b1b (patch) | |
| tree | 16c20409cf18b0747b107092ed64c3beab4f6e89 | |
| parent | de6dfccc835ad46b5f4362caae66a37651716ab2 (diff) | |
| download | uhd-1ed37cdfda93e430037ee4028ec5ac70ab223b1b.tar.gz uhd-1ed37cdfda93e430037ee4028ec5ac70ab223b1b.tar.bz2 uhd-1ed37cdfda93e430037ee4028ec5ac70ab223b1b.zip | |
rfnoc: Add block registry/factory and make_args
- noc_block_base now has a ctor defined
- The registry stores factory functions to the individual Noc-Block
  implementations
| -rw-r--r-- | host/include/uhd/rfnoc/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_base.hpp | 21 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_make_args.hpp | 44 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/registry.hpp | 78 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/rfnoc/factory.hpp | 32 | ||||
| -rw-r--r-- | host/lib/rfnoc/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | host/lib/rfnoc/noc_block_base.cpp | 18 | ||||
| -rw-r--r-- | host/lib/rfnoc/registry_factory.cpp | 88 | 
8 files changed, 283 insertions, 2 deletions
| diff --git a/host/include/uhd/rfnoc/CMakeLists.txt b/host/include/uhd/rfnoc/CMakeLists.txt index 319240578..41826a9cb 100644 --- a/host/include/uhd/rfnoc/CMakeLists.txt +++ b/host/include/uhd/rfnoc/CMakeLists.txt @@ -16,11 +16,13 @@ if(ENABLE_RFNOC)          defaults.hpp          dirtifier.hpp          graph.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 diff --git a/host/include/uhd/rfnoc/noc_block_base.hpp b/host/include/uhd/rfnoc/noc_block_base.hpp index 0adcfdafb..b671e6525 100644 --- a/host/include/uhd/rfnoc/noc_block_base.hpp +++ b/host/include/uhd/rfnoc/noc_block_base.hpp @@ -13,8 +13,12 @@  #include <uhd/rfnoc/register_iface_holder.hpp>  //! Shorthand for block constructor -#define UHD_RFNOC_BLOCK_CONSTRUCTOR(CLASS_NAME) \ -    CLASS_NAME##_impl(make_args_ptr make_args) : noc_block_base(std::move(make_args)) +#define RFNOC_BLOCK_CONSTRUCTOR(CLASS_NAME) \ +    CLASS_NAME##_impl(make_args_ptr make_args) : CLASS_NAME(std::move(make_args)) + +#define RFNOC_DECLARE_BLOCK(CLASS_NAME) \ +    using sptr = std::shared_ptr<CLASS_NAME>;\ +    CLASS_NAME(make_args_ptr make_args) : noc_block_base(std::move(make_args)) {}  namespace uhd { namespace rfnoc { @@ -42,6 +46,14 @@ public:       */      using noc_id_t = uint32_t; +    //! Forward declaration for the constructor arguments +    struct make_args_t; + +    //! Opaque pointer to the constructor arguments +    using make_args_ptr = std::unique_ptr<make_args_t>; + +    virtual ~noc_block_base(); +      /**************************************************************************       * node_t API calls       *************************************************************************/ @@ -71,6 +83,9 @@ public:       */      const block_id_t& get_block_id() const { return _block_id; } +protected: +    noc_block_base(make_args_ptr make_args); +  private:      //! This block's Noc-ID      noc_id_t _noc_id; @@ -89,4 +104,6 @@ private:  }} /* namespace uhd::rfnoc */ +#include <uhd/rfnoc/noc_block_make_args.hpp> +  #endif /* INCLUDED_LIBUHD_NOC_BLOCK_BASE_HPP */ diff --git a/host/include/uhd/rfnoc/noc_block_make_args.hpp b/host/include/uhd/rfnoc/noc_block_make_args.hpp new file mode 100644 index 000000000..8a4b1f5ad --- /dev/null +++ b/host/include/uhd/rfnoc/noc_block_make_args.hpp @@ -0,0 +1,44 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_NOC_BLOCK_MAKE_ARGS_HPP +#define INCLUDED_LIBUHD_NOC_BLOCK_MAKE_ARGS_HPP + +#include <uhd/rfnoc/noc_block_base.hpp> +#include <uhd/rfnoc/register_iface.hpp> +#include <uhd/property_tree.hpp> + +namespace uhd { namespace rfnoc { + +/*! Data structure to hold the arguments passed into the noc_block_base ctor + * + * We want to hide these from the user, so she can't futz around with them. + * Hence the opaque pointer, and non-UHD_API implementation. + */ +struct noc_block_base::make_args_t +{ +    //! Noc-ID +    noc_id_t noc_id; + +    //! Block ID (e.g. 0/Radio#0) +    block_id_t block_id; + +    //! Number of input ports (gets reported from the FPGA) +    size_t num_input_ports; + +    //! Number of output ports (gets reported from the FPGA) +    size_t num_output_ports; + +    //! Register interface to this block's register space +    register_iface::sptr reg_iface; + +    //! The subtree for this block +    uhd::property_tree::sptr tree; +}; + +}} /* namespace uhd::rfnoc */ + +#endif /* INCLUDED_LIBUHD_NOC_BLOCK_MAKE_ARGS_HPP */ diff --git a/host/include/uhd/rfnoc/registry.hpp b/host/include/uhd/rfnoc/registry.hpp new file mode 100644 index 000000000..18d896205 --- /dev/null +++ b/host/include/uhd/rfnoc/registry.hpp @@ -0,0 +1,78 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_RFNOC_REGISTRY_HPP +#define INCLUDED_LIBUHD_RFNOC_REGISTRY_HPP + +#include <uhd/config.hpp> +#include <uhd/rfnoc/noc_block_base.hpp> +#include <uhd/utils/static.hpp> +#include <functional> +#include <string> + +//! This macro must be placed inside a block implementation file +// after the class definition +#define UHD_RFNOC_BLOCK_REGISTER_DIRECT(CLASS_NAME, NOC_ID, BLOCK_NAME)   \ +    uhd::rfnoc::noc_block_base::sptr CLASS_NAME##_make(                   \ +        uhd::rfnoc::noc_block_base::make_args_ptr make_args)              \ +    {                                                                     \ +        return std::make_shared<CLASS_NAME##_impl>(std::move(make_args)); \ +    }                                                                     \ +    UHD_STATIC_BLOCK(register_rfnoc_##CLASS_NAME)                         \ +    {                                                                     \ +        uhd::rfnoc::registry::register_block_direct(                      \ +            NOC_ID, BLOCK_NAME, &CLASS_NAME##_make);                      \ +    } + +namespace uhd { namespace rfnoc { + +/*! RFNoC Block Registry + * + * A container for various functions to register blocks + */ +class UHD_API registry +{ +public: +    using factory_t = std::function<noc_block_base::sptr(noc_block_base::make_args_ptr)>; + +    /*! Register a block that does not use a block descriptor file +     * +     * Note: It is highly recommended to use the UHD_RFNOC_BLOCK_REGISTER_DIRECT() +     * macro instead of calling this function. +     * +     * Use this registry function for blocks that do not read from a textual +     * description (block descriptor file). +     * +     * If the Noc-ID is already registered, it will print an error to stderr and +     * ignore the new block. +     * +     * \param noc_id The 32-bit Noc-ID for this block (e.g. 0xDDC00000) +     * \param block_name The name used for the block ID (e.g. "Radio") +     * \param factory_fn A factory function that returns a reference to the +     *                   block +     */ +    static void register_block_direct(noc_block_base::noc_id_t noc_id, +        const std::string& block_name, +        factory_t factory_fn); + +    /*! Register a block that does use a block descriptor file +     * +     * Use this registry function for blocks that also have a textual +     * description (block descriptor file). +     * +     * For these blocks, the framework will first look up the Noc-ID from the +     * blocks on the FPGA, and then find the corresponding block key by +     * searching all the availble block descriptor files. When such a key is +     * found, it will be used to find a block that was previously registered +     * here. +     */ +    static void register_block_descriptor(const std::string& block_key, +        factory_t factory_fn); +}; + +}} /* namespace uhd::rfnoc */ + +#endif /* INCLUDED_LIBUHD_RFNOC_REGISTRY_HPP */ diff --git a/host/lib/include/uhdlib/rfnoc/factory.hpp b/host/lib/include/uhdlib/rfnoc/factory.hpp new file mode 100644 index 000000000..3305dda3e --- /dev/null +++ b/host/lib/include/uhdlib/rfnoc/factory.hpp @@ -0,0 +1,32 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_RFNOC_FACTORY_HPP +#define INCLUDED_LIBUHD_RFNOC_FACTORY_HPP + +#include <uhd/rfnoc/registry.hpp> +#include <uhd/rfnoc/noc_block_base.hpp> + +namespace uhd { namespace rfnoc { + +/*! Container for factory functionality + */ +class factory +{ +public: +    /*! Return a factory function for an RFNoC block based on the Noc-ID +     * +     * \returns a pair: factory function, and block name +     * \throws uhd::lookup_error if no block is found +     */ +    static std::pair<registry::factory_t, std::string> +    get_block_factory(noc_block_base::noc_id_t noc_id); +}; + + +}} /* namespace uhd::rfnoc */ + +#endif /* INCLUDED_LIBUHD_RFNOC_FACTORY_HPP */ diff --git a/host/lib/rfnoc/CMakeLists.txt b/host/lib/rfnoc/CMakeLists.txt index 2c13c1819..57a5253a7 100644 --- a/host/lib/rfnoc/CMakeLists.txt +++ b/host/lib/rfnoc/CMakeLists.txt @@ -1,6 +1,7 @@  #  # Copyright 2014-2015,2017 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  # @@ -30,6 +31,7 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/rate_node_ctrl.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}/rx_stream_terminator.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/scalar_node_ctrl.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/sink_block_ctrl_base.cpp diff --git a/host/lib/rfnoc/noc_block_base.cpp b/host/lib/rfnoc/noc_block_base.cpp index 3cacc455b..838e05e74 100644 --- a/host/lib/rfnoc/noc_block_base.cpp +++ b/host/lib/rfnoc/noc_block_base.cpp @@ -5,7 +5,25 @@  //  #include <uhd/rfnoc/noc_block_base.hpp> +#include <uhd/rfnoc/register_iface.hpp>  #include <uhd/exception.hpp>  using namespace uhd::rfnoc; +/****************************************************************************** + * Structors + *****************************************************************************/ +noc_block_base::noc_block_base(make_args_ptr make_args) +    : register_iface_holder(std::move(make_args->reg_iface)) +    , _noc_id(make_args->noc_id) +    , _block_id(make_args->block_id) +    , _num_input_ports(make_args->num_input_ports) +    , _num_output_ports(make_args->num_output_ports) +{ +} + +noc_block_base::~noc_block_base() +{ +    // nop +} + diff --git a/host/lib/rfnoc/registry_factory.cpp b/host/lib/rfnoc/registry_factory.cpp new file mode 100644 index 000000000..cf7b897f7 --- /dev/null +++ b/host/lib/rfnoc/registry_factory.cpp @@ -0,0 +1,88 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/exception.hpp> +#include <uhd/rfnoc/registry.hpp> +#include <uhd/utils/static.hpp> +#include <uhdlib/rfnoc/factory.hpp> +#include <unordered_map> +#include <iomanip> +#include <iostream> +#include <sstream> + +using namespace uhd::rfnoc; + +/////////////////////////////////////////////////////////////////////////////// +// There are two registries: +// - The "direct" registry, which is for blocks that do not have a block +//   descriptor file +// - The "descriptor" registry, which is for blocks that *do* have a block +//   descriptor file +// +// This is the direct registry: +using block_direct_reg_t = std::unordered_map<noc_block_base::noc_id_t, +    std::tuple<std::string /* block_name */, +        registry::factory_t>>; +UHD_SINGLETON_FCN(block_direct_reg_t, get_direct_block_registry); +// +// This is the descriptor registry: +using block_descriptor_reg_t = +    std::unordered_map<std::string /* block_key */, registry::factory_t>; +UHD_SINGLETON_FCN(block_descriptor_reg_t, get_descriptor_block_registry); +/////////////////////////////////////////////////////////////////////////////// + +/****************************************************************************** + * Registry functions + * + * Note: Don't use UHD_LOG_*, since all of this can be executed in a static + * fashion. + *****************************************************************************/ +void registry::register_block_direct(noc_block_base::noc_id_t noc_id, +    const std::string& block_name, +    factory_t factory_fn) +{ +    if (get_direct_block_registry().count(noc_id)) { +        std::cerr +            << "[REGISTRY] WARNING: Attempting to overwrite previously registered RFNoC " +               "block with Noc-ID 0x" +            << std::hex << noc_id << std::dec << std::endl; +        return; +    } +    get_direct_block_registry().emplace( +        noc_id, std::make_tuple(block_name, std::move(factory_fn))); +} + +void registry::register_block_descriptor( +    const std::string& block_key, factory_t factory_fn) +{ +    if (get_descriptor_block_registry().count(block_key)) { +        std::cerr << "WARNING: Attempting to overwriting previously registered RFNoC " +                     "block with block key" +                  << block_key << std::endl; +        return; +    } +    get_descriptor_block_registry().emplace(block_key, std::move(factory_fn)); +} + +/****************************************************************************** + * Factory functions + *****************************************************************************/ +std::pair<registry::factory_t, std::string> factory::get_block_factory( +    noc_block_base::noc_id_t noc_id) +{ +    // First, check the descriptor registry +    // FIXME TODO + +    // Second, check the direct registry +    if (!get_direct_block_registry().count(noc_id)) { +        UHD_LOG_WARNING("RFNOC::BLOCK_FACTORY", +            "Could not find block with Noc-ID " +                << std::hex << std::setw(sizeof(noc_block_base::noc_id_t) * 2) << noc_id); +        throw uhd::key_error("Block not found!"); +    } +    auto& block_info = get_direct_block_registry().at(noc_id); +    return {std::get<1>(block_info), std::get<0>(block_info)}; +} | 
