diff options
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_base.hpp | 32 | ||||
| -rw-r--r-- | host/include/uhd/rfnoc/noc_block_make_args.hpp | 4 | ||||
| -rw-r--r-- | host/lib/rfnoc/ddc_block_control.cpp | 40 | ||||
| -rw-r--r-- | host/lib/rfnoc/noc_block_base.cpp | 62 | ||||
| -rw-r--r-- | host/tests/rfnoc_blocks_test.cpp | 1 | 
5 files changed, 99 insertions, 40 deletions
diff --git a/host/include/uhd/rfnoc/noc_block_base.hpp b/host/include/uhd/rfnoc/noc_block_base.hpp index b671e6525..0959e5bdd 100644 --- a/host/include/uhd/rfnoc/noc_block_base.hpp +++ b/host/include/uhd/rfnoc/noc_block_base.hpp @@ -22,6 +22,8 @@  namespace uhd { namespace rfnoc { +class clock_iface; +  /*!   * The primary interface to a NoC block in the FPGA   * @@ -83,10 +85,30 @@ public:       */      const block_id_t& get_block_id() const { return _block_id; } +    /*! Returns the tick rate of the current time base +     * +     * Note there is only ever one time base (or tick rate) per block. +     */ +    double get_tick_rate() const { return _tick_rate; } +  protected:      noc_block_base(make_args_ptr make_args); +    /*! Update tick rate for this node and all the connected nodes +     * +     * Careful: Calling this function will trigger a property propagation to any +     * block this block is connected to. +     */ +    void set_tick_rate(const double tick_rate); +  private: +    /*! Update the tick rate of this block +     * +     * This will make sure that the underlying register_iface is notified of the +     * change in timebase. +     */ +    void _set_tick_rate(const double tick_rate); +      //! This block's Noc-ID      noc_id_t _noc_id; @@ -100,6 +122,16 @@ private:      //! Number of output ports      size_t _num_output_ports; + +    //! Container for the 'tick rate' property. This will hold one edge property +    // 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; + +    std::shared_ptr<clock_iface> _clock_iface; +  }; // class noc_block_base  }} /* namespace uhd::rfnoc */ diff --git a/host/include/uhd/rfnoc/noc_block_make_args.hpp b/host/include/uhd/rfnoc/noc_block_make_args.hpp index c9b530589..d3679f973 100644 --- a/host/include/uhd/rfnoc/noc_block_make_args.hpp +++ b/host/include/uhd/rfnoc/noc_block_make_args.hpp @@ -14,6 +14,7 @@  namespace uhd { namespace rfnoc {  class clock_iface; +  /*! 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. @@ -21,6 +22,8 @@ class clock_iface;   */  struct noc_block_base::make_args_t  { +    ~make_args_t(); +      //! Noc-ID      noc_id_t noc_id; @@ -38,6 +41,7 @@ struct noc_block_base::make_args_t      //! Clock interface object that is shared with the reg_iface      std::shared_ptr<clock_iface> clk_iface; +      //! The subtree for this block      uhd::property_tree::sptr tree;  }; diff --git a/host/lib/rfnoc/ddc_block_control.cpp b/host/lib/rfnoc/ddc_block_control.cpp index 4562585d8..0b6fd7d89 100644 --- a/host/lib/rfnoc/ddc_block_control.cpp +++ b/host/lib/rfnoc/ddc_block_control.cpp @@ -56,8 +56,7 @@ public:      , _fpga_compat(regs().peek32(RB_COMPAT_NUM)),          _num_halfbands(regs().peek32(RB_NUM_HB)),          _cic_max_decim(regs().peek32(RB_CIC_MAX_DECIM)), -        _residual_scaling(get_num_input_ports(), DEFAULT_SCALING), -        _tick_rate(get_num_input_ports(), DEFAULT_RATE) +        _residual_scaling(get_num_input_ports(), DEFAULT_SCALING)      {          UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports());          UHD_ASSERT_THROW(_cic_max_decim > 0 && _cic_max_decim <= 0xFF); @@ -87,8 +86,6 @@ public:          // space, because we use push_back() further down, and properties must          // not change their base address after registration and resolver          // creation. -        _tick_rate_in.reserve(get_num_ports()); -        _tick_rate_out.reserve(get_num_ports());          _samp_rate_in.reserve(get_num_ports());          _samp_rate_out.reserve(get_num_ports());          _scaling_in.reserve(get_num_ports()); @@ -194,10 +191,6 @@ private:      void _register_props(const size_t chan)      {          // Create actual properties and store them -        _tick_rate_in.push_back(property_t<double>( -            PROP_KEY_TICK_RATE, DEFAULT_RATE, {res_source_info::INPUT_EDGE, chan})); -        _tick_rate_out.push_back(property_t<double>( -            PROP_KEY_TICK_RATE, DEFAULT_RATE, {res_source_info::OUTPUT_EDGE, chan}));          _samp_rate_in.push_back(property_t<double>(              PROP_KEY_SAMP_RATE, DEFAULT_RATE, {res_source_info::INPUT_EDGE, chan}));          _samp_rate_out.push_back(property_t<double>( @@ -214,8 +207,6 @@ private:              PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE, chan}));          _type_out.emplace_back(property_t<std::string>(              PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::OUTPUT_EDGE, chan})); -        UHD_ASSERT_THROW(_tick_rate_in.size() == chan + 1); -        UHD_ASSERT_THROW(_tick_rate_out.size() == chan + 1);          UHD_ASSERT_THROW(_samp_rate_in.size() == chan + 1);          UHD_ASSERT_THROW(_samp_rate_out.size() == chan + 1);          UHD_ASSERT_THROW(_scaling_in.size() == chan + 1); @@ -226,8 +217,6 @@ private:          UHD_ASSERT_THROW(_type_out.size() == chan + 1);          // give us some shorthands for the rest of this function -        property_t<double>* tick_rate_in  = &_tick_rate_in.back(); -        property_t<double>* tick_rate_out = &_tick_rate_out.back();          property_t<double>* samp_rate_in  = &_samp_rate_in.back();          property_t<double>* samp_rate_out = &_samp_rate_out.back();          property_t<double>* scaling_in    = &_scaling_in.back(); @@ -238,8 +227,6 @@ private:          property_t<std::string>* type_out = &_type_out.back();          // register them -        register_property(tick_rate_in); -        register_property(tick_rate_out);          register_property(samp_rate_in);          register_property(samp_rate_out);          register_property(scaling_in); @@ -252,24 +239,6 @@ private:          /**********************************************************************           * Add resolvers           *********************************************************************/ -        // Resolver for the tick rate: The input and output edges can have -        // different time bases. However, we might want to forward the time base, -        // e.g., if the upstream block is a radio, but the downstream block is a -        // streamer and wouldn't know about time bases itself. -        // We therefore propagate tick rates only if the opposite edge has the -        // same tick rate as we do. For the output, we accept any tick rate, -        // so it gets no resolver. -        add_property_resolver({tick_rate_in}, -            {tick_rate_out}, -            [this, -                chan, -                &tick_rate_in  = *tick_rate_in, -                &tick_rate_out = *tick_rate_out]() { -                if (tick_rate_out.get() == _tick_rate.at(chan)) { -                    tick_rate_out = tick_rate_in.get(); -                } -                _tick_rate[chan] = tick_rate_in.get(); -            });          // Resolver for the output scaling: This cannot be updated, we reset it          // to its previous value.          add_property_resolver({scaling_out}, @@ -529,17 +498,10 @@ private:      //! Cache the current residual scaling      std::vector<double> _residual_scaling; -    //! Tick rate for every input channel -    std::vector<double> _tick_rate; -      //! Properties for type_in (one per port)      std::vector<property_t<std::string>> _type_in;      //! Properties for type_out (one per port)      std::vector<property_t<std::string>> _type_out; -    //! Properties for tick_rate_in (one per port) -    std::vector<property_t<double>> _tick_rate_in; -    //! Properties for tick_rate_out (one per port) -    std::vector<property_t<double>> _tick_rate_out;      //! Properties for samp_rate_in (one per port)      std::vector<property_t<double>> _samp_rate_in;      //! Properties for samp_rate_out (one per port) diff --git a/host/lib/rfnoc/noc_block_base.cpp b/host/lib/rfnoc/noc_block_base.cpp index 838e05e74..2bbf52928 100644 --- a/host/lib/rfnoc/noc_block_base.cpp +++ b/host/lib/rfnoc/noc_block_base.cpp @@ -4,12 +4,16 @@  // SPDX-License-Identifier: GPL-3.0-or-later  // +#include <uhd/exception.hpp> +#include <uhd/rfnoc/defaults.hpp>  #include <uhd/rfnoc/noc_block_base.hpp>  #include <uhd/rfnoc/register_iface.hpp> -#include <uhd/exception.hpp> +#include <uhdlib/rfnoc/clock_iface.hpp>  using namespace uhd::rfnoc; +noc_block_base::make_args_t::~make_args_t() = default; +  /******************************************************************************   * Structors   *****************************************************************************/ @@ -19,7 +23,39 @@ 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)  { +    // 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, +            {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, +            {res_source_info::OUTPUT_EDGE, output_port})); +    } +    // Register all the tick_rate properties and create a default resolver +    prop_ptrs_t prop_refs; +    prop_refs.reserve(_tick_rate_props.size()); +    for (auto& prop : _tick_rate_props) { +        prop_refs.insert(&prop); +        register_property(&prop); +    } +    for (auto& prop : _tick_rate_props) { +        auto prop_refs_copy = prop_refs; +        add_property_resolver( +            {&prop}, std::move(prop_refs_copy), [this, source_prop = &prop]() { +                for (property_t<double>& tick_rate_prop : _tick_rate_props) { +                    tick_rate_prop = source_prop->get(); +                } +                this->_set_tick_rate(source_prop->get()); +            }); +    } +    // Now enable this clock iface +    _clock_iface->set_running(true);  }  noc_block_base::~noc_block_base() @@ -27,3 +63,27 @@ noc_block_base::~noc_block_base()      // nop  } + +void noc_block_base::set_tick_rate(const double tick_rate) +{ +    if (_tick_rate == tick_rate) { +        return; +    } +    // Update this node +    _set_tick_rate(tick_rate); +    // Now trigger property propagation +    if (!_tick_rate_props.empty()) { +        auto src_info = _tick_rate_props.at(0).get_src_info(); +        set_property<double>(PROP_KEY_TICK_RATE, tick_rate, src_info); +    } +} + +void noc_block_base::_set_tick_rate(const double tick_rate) +{ +    if (tick_rate == _tick_rate) { +        return; +    } +    RFNOC_LOG_TRACE("Updating tick rate to " << (tick_rate / 1e6) << " MHz"); +    _clock_iface->set_freq(tick_rate); +    _tick_rate = tick_rate; +} diff --git a/host/tests/rfnoc_blocks_test.cpp b/host/tests/rfnoc_blocks_test.cpp index b9ffcb5f9..113fbf630 100644 --- a/host/tests/rfnoc_blocks_test.cpp +++ b/host/tests/rfnoc_blocks_test.cpp @@ -8,6 +8,7 @@  #include <uhd/rfnoc/ddc_block_control.hpp>  #include <uhdlib/rfnoc/clock_iface.hpp>  #include <uhdlib/rfnoc/node_accessor.hpp> +#include <uhdlib/rfnoc/clock_iface.hpp>  #include <boost/test/unit_test.hpp>  #include <iostream>  | 
