diff options
Diffstat (limited to 'host')
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_base.hpp | 10 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_make_args.hpp | 7 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/registry.hpp | 23 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/rfnoc/clock_iface.hpp | 3 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/rfnoc/factory.hpp | 13 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/rfnoc/mb_iface.hpp | 5 | ||||
| -rw-r--r-- | host/lib/rfnoc/block_control.cpp | 3 | ||||
| -rw-r--r-- | host/lib/rfnoc/client_zero.cpp | 5 | ||||
| -rw-r--r-- | host/lib/rfnoc/ddc_block_control.cpp | 3 | ||||
| -rw-r--r-- | host/lib/rfnoc/noc_block_base.cpp | 50 | ||||
| -rw-r--r-- | host/lib/rfnoc/null_block_control.cpp | 3 | ||||
| -rw-r--r-- | host/lib/rfnoc/registry_factory.cpp | 18 | ||||
| -rw-r--r-- | host/lib/rfnoc/rfnoc_graph.cpp | 36 | ||||
| -rw-r--r-- | host/tests/rfnoc_blocks_test.cpp | 17 | 
14 files changed, 133 insertions, 63 deletions
| diff --git a/host/include/uhd/rfnoc/noc_block_base.hpp b/host/include/uhd/rfnoc/noc_block_base.hpp index 45a1f5738..d9659862c 100644 --- a/host/include/uhd/rfnoc/noc_block_base.hpp +++ b/host/include/uhd/rfnoc/noc_block_base.hpp @@ -100,7 +100,7 @@ public:       *       * Note there is only ever one time base (or tick rate) per block.       */ -    double get_tick_rate() const { return _tick_rate; } +    double get_tick_rate() const;      /*! Return the arguments that were passed into this block from the framework       */ @@ -215,11 +215,11 @@ private:      // for all in- and output edges.      std::vector<property_t<double>> _tick_rate_props; -    //! The actual tick rate of the current time base -    double _tick_rate; +    //! Reference to the ctrlport clock_iface object shared with the register_iface +    std::shared_ptr<clock_iface> _ctrlport_clock_iface; -    //! Reference to the clock_iface object shared with the register_iface -    std::shared_ptr<clock_iface> _clock_iface; +    //! Reference to the timebase clock_iface object shared with the register_iface +    std::shared_ptr<clock_iface> _tb_clock_iface;      //! Stores a reference to this block's motherboard's controller, if this      // block had requested and was granted access diff --git a/host/include/uhd/rfnoc/noc_block_make_args.hpp b/host/include/uhd/rfnoc/noc_block_make_args.hpp index 8a5fbd46f..7ed191079 100644 --- a/host/include/uhd/rfnoc/noc_block_make_args.hpp +++ b/host/include/uhd/rfnoc/noc_block_make_args.hpp @@ -40,8 +40,11 @@ struct noc_block_base::make_args_t      //! Register interface to this block's register space      register_iface::sptr reg_iface; -    //! Clock interface object that is shared with the reg_iface -    std::shared_ptr<clock_iface> clk_iface; +    //! Timebase clock interface object that is shared with the reg_iface +    std::shared_ptr<clock_iface> tb_clk_iface; + +    //! Controlport clock interface object that is shared with the reg_iface +    std::shared_ptr<clock_iface> ctrlport_clk_iface;      //! Reference to the motherboard controller associated with this block.      // diff --git a/host/include/uhd/rfnoc/registry.hpp b/host/include/uhd/rfnoc/registry.hpp index cc07d5c65..9815ce3c6 100644 --- a/host/include/uhd/rfnoc/registry.hpp +++ b/host/include/uhd/rfnoc/registry.hpp @@ -15,16 +15,17 @@  //! 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);                      \ +#define UHD_RFNOC_BLOCK_REGISTER_DIRECT(                                   \ +    CLASS_NAME, NOC_ID, BLOCK_NAME, TB_CLOCK, CTRL_CLOCK)                  \ +    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, TB_CLOCK, CTRL_CLOCK, &CLASS_NAME##_make); \      }  #define UHD_RFNOC_BLOCK_REQUEST_MB_ACCESS(NOC_ID)              \ @@ -62,6 +63,8 @@ public:       */      static void register_block_direct(noc_block_base::noc_id_t noc_id,          const std::string& block_name, +        const std::string& timebase_clock, +        const std::string& ctrlport_clock,          factory_t factory_fn);      /*! Register a block that does use a block descriptor file diff --git a/host/lib/include/uhdlib/rfnoc/clock_iface.hpp b/host/lib/include/uhdlib/rfnoc/clock_iface.hpp index ae61a645e..06e54e67c 100644 --- a/host/lib/include/uhdlib/rfnoc/clock_iface.hpp +++ b/host/lib/include/uhdlib/rfnoc/clock_iface.hpp @@ -12,12 +12,15 @@  #include <uhd/utils/log.hpp>  #include <atomic>  #include <string> +#include <memory>  namespace uhd { namespace rfnoc {  class clock_iface  {  public: +    using sptr = std::shared_ptr<clock_iface>; +      clock_iface(const std::string& name) : _name(name), _is_mutable(true)      {          _is_running = false; diff --git a/host/lib/include/uhdlib/rfnoc/factory.hpp b/host/lib/include/uhdlib/rfnoc/factory.hpp index 8d1fb27a0..be42a57e5 100644 --- a/host/lib/include/uhdlib/rfnoc/factory.hpp +++ b/host/lib/include/uhdlib/rfnoc/factory.hpp @@ -12,6 +12,14 @@  namespace uhd { namespace rfnoc { +struct block_factory_info_t +{ +    std::string block_name; +    std::string timebase_clk; +    std::string ctrlport_clk; +    registry::factory_t factory_fn; +}; +  /*! Container for factory functionality   */  class factory @@ -19,11 +27,10 @@ class factory  public:      /*! Return a factory function for an RFNoC block based on the Noc-ID       * -     * \returns a pair: factory function, and block name +     * \returns a block_factory_info_t object       * \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); +    static block_factory_info_t get_block_factory(noc_block_base::noc_id_t noc_id);      /*! Check if this block has requested access to the motherboard controller       */ diff --git a/host/lib/include/uhdlib/rfnoc/mb_iface.hpp b/host/lib/include/uhdlib/rfnoc/mb_iface.hpp index cca8dcab8..0a2790a34 100644 --- a/host/lib/include/uhdlib/rfnoc/mb_iface.hpp +++ b/host/lib/include/uhdlib/rfnoc/mb_iface.hpp @@ -9,6 +9,7 @@  #include <uhdlib/rfnoc/chdr_ctrl_xport.hpp>  #include <uhdlib/rfnoc/rfnoc_common.hpp> +#include <uhdlib/rfnoc/clock_iface.hpp>  #include <memory>  namespace uhd { namespace rfnoc { @@ -67,6 +68,10 @@ public:       */      virtual void reset_network() = 0; +    /*! Return a reference to a clock iface +     */ +    virtual std::shared_ptr<clock_iface> get_clock_iface(const std::string& clock_name) = 0; +      /*! Create a control transport       *       * This is usually called once per motherboard, since there is only one diff --git a/host/lib/rfnoc/block_control.cpp b/host/lib/rfnoc/block_control.cpp index 78c390001..e6d5cd31d 100644 --- a/host/lib/rfnoc/block_control.cpp +++ b/host/lib/rfnoc/block_control.cpp @@ -21,4 +21,5 @@ public:      }  }; -UHD_RFNOC_BLOCK_REGISTER_DIRECT(block_control, DEFAULT_NOC_ID, DEFAULT_BLOCK_NAME) +UHD_RFNOC_BLOCK_REGISTER_DIRECT( +    block_control, DEFAULT_NOC_ID, DEFAULT_BLOCK_NAME, CLOCK_KEY_GRAPH, "bus_clk") diff --git a/host/lib/rfnoc/client_zero.cpp b/host/lib/rfnoc/client_zero.cpp index aaecdcbf5..6d0e47203 100644 --- a/host/lib/rfnoc/client_zero.cpp +++ b/host/lib/rfnoc/client_zero.cpp @@ -220,9 +220,10 @@ client_zero::sptr client_zero::make(chdr_ctrl_endpoint& chdr_ctrl_ep, sep_id_t d      static constexpr uint16_t CLIENT_ZERO_PORT         = 0;      static constexpr size_t CLIENT_ZERO_BUFF_CAPACITY  = 32;      static constexpr size_t CLIENT_ZERO_MAX_ASYNC_MSGS = 0; -    static clock_iface client_zero_clk{"client_zero"}; +    // This clock_iface doesn't really matter because client_zero doesn't do timed +    // commands +    static clock_iface client_zero_clk("client_zero", 100e6, true);      client_zero_clk.set_running(true); // Client zero clock must be always-on. -    client_zero_clk.set_freq(100e6); // The freq is unused. No timed ops or sleeps.      return std::make_shared<client_zero>(chdr_ctrl_ep.get_ctrlport_ep(dst_epid,          CLIENT_ZERO_PORT, diff --git a/host/lib/rfnoc/ddc_block_control.cpp b/host/lib/rfnoc/ddc_block_control.cpp index 0b6fd7d89..56bb8cc5a 100644 --- a/host/lib/rfnoc/ddc_block_control.cpp +++ b/host/lib/rfnoc/ddc_block_control.cpp @@ -516,4 +516,5 @@ private:      std::vector<property_t<double>> _freq;  }; -UHD_RFNOC_BLOCK_REGISTER_DIRECT(ddc_block_control, 0xDDC00000, "DDC") +UHD_RFNOC_BLOCK_REGISTER_DIRECT( +    ddc_block_control, 0xDDC00000, "DDC", CLOCK_KEY_GRAPH, "bus_clk") diff --git a/host/lib/rfnoc/noc_block_base.cpp b/host/lib/rfnoc/noc_block_base.cpp index c0d8cf2a9..68093d9b1 100644 --- a/host/lib/rfnoc/noc_block_base.cpp +++ b/host/lib/rfnoc/noc_block_base.cpp @@ -23,21 +23,28 @@ noc_block_base::noc_block_base(make_args_ptr make_args)      , _block_id(make_args->block_id)      , _num_input_ports(make_args->num_input_ports)      , _num_output_ports(make_args->num_output_ports) -    , _clock_iface(make_args->clk_iface) +    , _ctrlport_clock_iface(make_args->ctrlport_clk_iface) +    , _tb_clock_iface(make_args->tb_clk_iface)      , _mb_controller(std::move(make_args->mb_control))      , _block_args(make_args->args)      , _tree(make_args->tree)  { +    RFNOC_LOG_TRACE( +        "Using timebase clock: `" << _tb_clock_iface->get_name() << "'. Current frequency: " +                                 << (_tb_clock_iface->get_freq() / 1e6) << " MHz"); +    RFNOC_LOG_TRACE("Using ctrlport clock: `" +                    << _ctrlport_clock_iface->get_name() << "'. Current frequency: " +                    << (_ctrlport_clock_iface->get_freq() / 1e6) << " MHz");      // First, create one tick_rate property for every port      _tick_rate_props.reserve(get_num_input_ports() + get_num_output_ports());      for (size_t input_port = 0; input_port < get_num_input_ports(); input_port++) {          _tick_rate_props.push_back(property_t<double>(PROP_KEY_TICK_RATE, -            DEFAULT_TICK_RATE, +            _tb_clock_iface->get_freq(),              {res_source_info::INPUT_EDGE, input_port}));      }      for (size_t output_port = 0; output_port < get_num_output_ports(); output_port++) {          _tick_rate_props.push_back(property_t<double>(PROP_KEY_TICK_RATE, -            DEFAULT_TICK_RATE, +            _tb_clock_iface->get_freq(),              {res_source_info::OUTPUT_EDGE, output_port}));      }      // Register all the tick_rate properties and create a default resolver @@ -51,14 +58,16 @@ noc_block_base::noc_block_base(make_args_ptr make_args)          auto prop_refs_copy = prop_refs;          add_property_resolver(              {&prop}, std::move(prop_refs_copy), [this, source_prop = &prop]() { +                // _set_tick_rate() will update _tick_rate, but only if that's +                // a valid operation for this block +                this->_set_tick_rate(source_prop->get()); +                // Now, _tick_rate is valid and we will pass its value to all +                // tick_rate properties                  for (property_t<double>& tick_rate_prop : _tick_rate_props) { -                    tick_rate_prop = source_prop->get(); +                    tick_rate_prop = get_tick_rate();                  } -                this->_set_tick_rate(source_prop->get());              });      } -    // Now enable this clock iface -    _clock_iface->set_running(true);  }  noc_block_base::~noc_block_base() @@ -89,13 +98,19 @@ void noc_block_base::set_num_output_ports(const size_t num_ports)  } +double noc_block_base::get_tick_rate() const +{ +    return _tb_clock_iface->get_freq(); +} +  void noc_block_base::set_tick_rate(const double tick_rate)  { -    if (_tick_rate == tick_rate) { +    if (tick_rate == get_tick_rate()) {          return;      }      // Update this node -    _set_tick_rate(tick_rate); +    RFNOC_LOG_TRACE("Setting tb clock freq to " << tick_rate/1e6 << " MHz"); +    _tb_clock_iface->set_freq(tick_rate);      // Now trigger property propagation      if (!_tick_rate_props.empty()) {          auto src_info = _tick_rate_props.at(0).get_src_info(); @@ -105,12 +120,21 @@ void noc_block_base::set_tick_rate(const double tick_rate)  void noc_block_base::_set_tick_rate(const double tick_rate)  { -    if (tick_rate == _tick_rate) { +    if (tick_rate == get_tick_rate()) { +        return; +    } +    if (tick_rate <= 0) { +        RFNOC_LOG_WARNING("Attempting to set tick rate to 0. Skipping.")          return;      } -    RFNOC_LOG_TRACE("Updating tick rate to " << (tick_rate / 1e6) << " MHz"); -    _clock_iface->set_freq(tick_rate); -    _tick_rate = tick_rate; +    if (_tb_clock_iface->get_name() == CLOCK_KEY_GRAPH) { +        RFNOC_LOG_TRACE("Updating tick rate to " << (tick_rate / 1e6) << " MHz"); +        _tb_clock_iface->set_freq(tick_rate); +    } else { +        RFNOC_LOG_WARNING("Cannot change tick rate to " +                          << (tick_rate / 1e6) +                          << " MHz, this clock is not configurable by the graph!"); +    }  }  void noc_block_base::shutdown() diff --git a/host/lib/rfnoc/null_block_control.cpp b/host/lib/rfnoc/null_block_control.cpp index 21042453d..443c2f3d7 100644 --- a/host/lib/rfnoc/null_block_control.cpp +++ b/host/lib/rfnoc/null_block_control.cpp @@ -181,4 +181,5 @@ private:      uint32_t _item_width;  }; -UHD_RFNOC_BLOCK_REGISTER_DIRECT(null_block_control, 0x00000001, "NullSrcSink") +UHD_RFNOC_BLOCK_REGISTER_DIRECT( +    null_block_control, 0x00000001, "NullSrcSink", CLOCK_KEY_GRAPH, "bus_clk") diff --git a/host/lib/rfnoc/registry_factory.cpp b/host/lib/rfnoc/registry_factory.cpp index d03cb183a..117b60e96 100644 --- a/host/lib/rfnoc/registry_factory.cpp +++ b/host/lib/rfnoc/registry_factory.cpp @@ -24,9 +24,8 @@ using namespace uhd::rfnoc;  //   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>>; +using block_direct_reg_t = +    std::unordered_map<noc_block_base::noc_id_t, block_factory_info_t>;  UHD_SINGLETON_FCN(block_direct_reg_t, get_direct_block_registry);  //  // This is the descriptor registry: @@ -54,6 +53,8 @@ UHD_SINGLETON_FCN(   *****************************************************************************/  void registry::register_block_direct(noc_block_base::noc_id_t noc_id,      const std::string& block_name, +    const std::string& timebase_clock, +    const std::string& ctrlport_clock,      factory_t factory_fn)  {      if (get_direct_block_registry().count(noc_id)) { @@ -63,8 +64,9 @@ void registry::register_block_direct(noc_block_base::noc_id_t noc_id,              << 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))); +    get_direct_block_registry().emplace(noc_id, +        block_factory_info_t{ +            block_name, timebase_clock, ctrlport_clock, std::move(factory_fn)});  }  void registry::register_block_descriptor( @@ -96,8 +98,7 @@ void registry::request_mb_access(const std::string& block_key)  /******************************************************************************   * Factory functions   *****************************************************************************/ -std::pair<registry::factory_t, std::string> factory::get_block_factory( -    noc_block_base::noc_id_t noc_id) +block_factory_info_t factory::get_block_factory(noc_block_base::noc_id_t noc_id)  {      // First, check the descriptor registry      // FIXME TODO @@ -109,8 +110,7 @@ std::pair<registry::factory_t, std::string> factory::get_block_factory(                  << std::hex << std::setw(sizeof(noc_block_base::noc_id_t) * 2) << noc_id);          noc_id = DEFAULT_NOC_ID;      } -    auto& block_info = get_direct_block_registry().at(noc_id); -    return {std::get<1>(block_info), std::get<0>(block_info)}; +    return get_direct_block_registry().at(noc_id);  }  bool factory::has_requested_mb_access(noc_block_base::noc_id_t noc_id) diff --git a/host/lib/rfnoc/rfnoc_graph.cpp b/host/lib/rfnoc/rfnoc_graph.cpp index 5b2277284..04b13a374 100644 --- a/host/lib/rfnoc/rfnoc_graph.cpp +++ b/host/lib/rfnoc/rfnoc_graph.cpp @@ -184,27 +184,47 @@ private:              // Iterate through and register each of the blocks in this mboard              for (size_t portno = 0; portno < num_blocks; ++portno) {                  auto noc_id = mb_cz->get_noc_id(portno + first_block_port); -                auto block_factory_pair = factory::get_block_factory(noc_id); +                auto block_factory_info = factory::get_block_factory(noc_id);                  auto block_info = mb_cz->get_block_info(portno + first_block_port);                  block_id_t block_id(mb_idx, -                    block_factory_pair.second, -                    block_count_map[block_factory_pair.second]++); -                auto clk_iface = std::make_shared<clock_iface>(block_id.to_string() + "_clock"); +                    block_factory_info.block_name, +                    block_count_map[block_factory_info.block_name]++); +                // Get access to the clock interface objects. We have some rules +                // here: +                // - The ctrlport clock must always be provided through the +                //   BSP via mb_iface +                // - The timebase clock can be set to "graph", which means the +                //   block takes care of the timebase itself (via property +                //   propagation). In that case, we generate a clock iface +                //   object on the fly here. +                // - In all other cases, the BSP must provide us that clock +                //   iface object through the mb_iface +                auto ctrlport_clk_iface = +                    mb.get_clock_iface(block_factory_info.ctrlport_clk); +                auto tb_clk_iface = (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) ? +                    std::make_shared<clock_iface>(CLOCK_KEY_GRAPH) : +                    mb.get_clock_iface(block_factory_info.timebase_clk); +                // A "graph" clock is always "running" +                if (block_factory_info.timebase_clk == CLOCK_KEY_GRAPH) { +                    tb_clk_iface->set_running(true); +                }                  auto block_reg_iface = _gsm->get_block_register_iface(ctrl_sep_addr,                      portno, -                    *clk_iface.get(), -                    *clk_iface.get()); +                    *ctrlport_clk_iface.get(), +                    *tb_clk_iface.get());                  auto make_args_uptr = std::make_unique<noc_block_base::make_args_t>();                  make_args_uptr->noc_id = noc_id;                  make_args_uptr->block_id = block_id;                  make_args_uptr->num_input_ports = block_info.num_inputs;                  make_args_uptr->num_output_ports = block_info.num_outputs;                  make_args_uptr->reg_iface = block_reg_iface; -                make_args_uptr->clk_iface = clk_iface; +                make_args_uptr->tb_clk_iface = tb_clk_iface; +                make_args_uptr->ctrlport_clk_iface = ctrlport_clk_iface;                  make_args_uptr->mb_control = (factory::has_requested_mb_access(noc_id) ? _mb_controllers.at(mb_idx) : nullptr);                  make_args_uptr->tree = _tree->subtree("/mboards/0"); /* FIXME Get the block's subtree */                  make_args_uptr->args = dev_addr; // TODO filter the device args -                _block_registry->register_block(block_factory_pair.first(std::move(make_args_uptr))); +                _block_registry->register_block( +                    block_factory_info.factory_fn(std::move(make_args_uptr)));                  _xbar_block_config[block_id.to_string()] = {                      portno, noc_id, block_id.get_block_count()};              } diff --git a/host/tests/rfnoc_blocks_test.cpp b/host/tests/rfnoc_blocks_test.cpp index b69b6f9f8..13fc15848 100644 --- a/host/tests/rfnoc_blocks_test.cpp +++ b/host/tests/rfnoc_blocks_test.cpp @@ -24,14 +24,15 @@ noc_block_base::make_args_ptr make_make_args(noc_block_base::noc_id_t noc_id,      const size_t n_inputs,      const size_t n_outputs)  { -    auto make_args              = std::make_unique<noc_block_base::make_args_t>(); -    make_args->noc_id           = noc_id; -    make_args->num_input_ports  = n_inputs; -    make_args->num_output_ports = n_outputs; -    make_args->reg_iface        = std::make_shared<mock_reg_iface_t>(); -    make_args->block_id         = block_id; -    make_args->clk_iface        = std::make_shared<clock_iface>("MOCK_CLOCK"); -    make_args->tree             = uhd::property_tree::make(); +    auto make_args                = std::make_unique<noc_block_base::make_args_t>(); +    make_args->noc_id             = noc_id; +    make_args->num_input_ports    = n_inputs; +    make_args->num_output_ports   = n_outputs; +    make_args->reg_iface          = std::make_shared<mock_reg_iface_t>(); +    make_args->block_id           = block_id; +    make_args->ctrlport_clk_iface = std::make_shared<clock_iface>("MOCK_CLOCK"); +    make_args->tb_clk_iface       = std::make_shared<clock_iface>("MOCK_CLOCK"); +    make_args->tree               = uhd::property_tree::make();      return make_args;  } | 
