1 // 2 // Copyright 2020 Ettus Research, a National Instruments Brand 3 // 4 // SPDX-License-Identifier: GPL-3.0-or-later 5 // 6 7 #include <uhd/exception.hpp> 8 #include <uhd/rfnoc/defaults.hpp> 9 #include <uhd/rfnoc/multichan_register_iface.hpp> 10 #include <uhd/rfnoc/property.hpp> 11 #include <uhd/rfnoc/registry.hpp> 12 #include <uhd/rfnoc/window_block_control.hpp> 13 14 using namespace uhd::rfnoc; 15 16 const uint32_t window_block_control::REG_WINDOW_BLOCK_SIZE = 1 << 4; 17 const uint32_t window_block_control::REG_WINDOW_LEN_OFFSET = 0x00; 18 const uint32_t window_block_control::REG_WINDOW_MAX_LEN_OFFSET = 0x04; 19 const uint32_t window_block_control::REG_WINDOW_LOAD_COEFF_OFFSET = 0x08; 20 const uint32_t window_block_control::REG_WINDOW_LOAD_COEFF_LAST_OFFSET = 0x0C; 21 22 // User property names 23 const char* const PROP_KEY_MAX_LEN = "max_len"; 24 25 class window_block_control_impl : public window_block_control 26 { 27 public: RFNOC_BLOCK_CONSTRUCTOR(window_block_control)28 RFNOC_BLOCK_CONSTRUCTOR(window_block_control), 29 _window_reg_iface(*this, 0, REG_WINDOW_BLOCK_SIZE) 30 { 31 UHD_ASSERT_THROW(get_num_input_ports() == get_num_output_ports()); 32 _register_props(); 33 } 34 get_max_num_coefficients(const size_t chan) const35 size_t get_max_num_coefficients(const size_t chan) const 36 { 37 return _max_len.at(chan); 38 } 39 set_coefficients(const std::vector<int16_t> & coeffs,const size_t chan)40 void set_coefficients(const std::vector<int16_t>& coeffs, const size_t chan) 41 { 42 if (coeffs.size() > _max_len.at(chan)) { 43 std::string error_msg = "Too many window coefficients specified (max " 44 + std::to_string(_max_len.at(chan)) + ")"; 45 throw uhd::value_error(error_msg); 46 } 47 48 _coeffs[chan] = coeffs; 49 _program_coefficients(chan); 50 } 51 get_coefficients(const size_t chan) const52 std::vector<int16_t> get_coefficients(const size_t chan) const 53 { 54 return _coeffs.at(chan); 55 } 56 57 private: _register_props()58 void _register_props() 59 { 60 const size_t num_chans = get_num_input_ports(); 61 _max_len.reserve(num_chans); 62 _coeffs.reserve(num_chans); 63 _prop_max_len.reserve(num_chans); 64 _prop_type_in.reserve(num_chans); 65 _prop_type_out.reserve(num_chans); 66 67 for (size_t chan = 0; chan < num_chans; chan++) { 68 const uint32_t max_len = 69 _window_reg_iface.peek32(REG_WINDOW_MAX_LEN_OFFSET, chan); 70 _max_len.emplace_back(max_len); 71 72 // set a default rectangular window for each channel 73 std::vector<int16_t> rect_coeffs( 74 max_len, std::numeric_limits<int16_t>::max()); 75 _coeffs.emplace_back(rect_coeffs); 76 _program_coefficients(chan); 77 78 // register user properties 79 _prop_max_len.emplace_back(property_t<int>{PROP_KEY_MAX_LEN, 80 static_cast<int>(max_len), 81 {res_source_info::USER, chan}}); 82 register_property(&_prop_max_len.back()); 83 add_property_resolver({&ALWAYS_DIRTY}, 84 {&_prop_max_len.back()}, 85 [this, chan, max_len]() { _prop_max_len.at(chan).set(max_len); }); 86 87 // register edge properties 88 _prop_type_in.emplace_back(property_t<std::string>{ 89 PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE, chan}}); 90 _prop_type_out.emplace_back(property_t<std::string>{ 91 PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::OUTPUT_EDGE, chan}}); 92 register_property(&_prop_type_in.back()); 93 register_property(&_prop_type_out.back()); 94 95 // add resolvers for type 96 add_property_resolver({&_prop_type_in.back()}, 97 {&_prop_type_in.back()}, 98 [this, chan]() { _prop_type_in.at(chan).set(IO_TYPE_SC16); }); 99 add_property_resolver({&_prop_type_out.back()}, 100 {&_prop_type_out.back()}, 101 [this, chan]() { _prop_type_out.at(chan).set(IO_TYPE_SC16); }); 102 } 103 } 104 _program_coefficients(size_t chan)105 void _program_coefficients(size_t chan) 106 { 107 // Write coefficients [0..num_coeffs-2]... 108 const size_t num_coeffs = _coeffs.at(chan).size(); 109 std::vector<uint32_t> coeffs_addr(num_coeffs - 1, REG_WINDOW_LOAD_COEFF_OFFSET); 110 std::vector<uint32_t> coeffs_minus_last(num_coeffs - 1); 111 std::transform(_coeffs.at(chan).begin(), 112 _coeffs.at(chan).end() - 1, 113 coeffs_minus_last.begin(), 114 [this](int16_t value) -> uint32_t { return static_cast<uint32_t>(value); }); 115 116 _window_reg_iface.multi_poke32(coeffs_addr, coeffs_minus_last, chan); 117 // ...and the final coefficient (num_coeffs-1) 118 _window_reg_iface.poke32(REG_WINDOW_LOAD_COEFF_LAST_OFFSET, 119 static_cast<uint32_t>(_coeffs.at(chan).at(num_coeffs - 1)), 120 chan); 121 } 122 123 //! Maximum length of window 124 std::vector<size_t> _max_len; 125 126 //! Current window coefficients 127 std::vector<std::vector<int16_t>> _coeffs; 128 129 /************************************************************************** 130 * Attributes 131 *************************************************************************/ 132 std::vector<property_t<std::string>> _prop_type_in; 133 std::vector<property_t<std::string>> _prop_type_out; 134 std::vector<property_t<int>> _prop_max_len; 135 136 /************************************************************************** 137 * Register interface 138 *************************************************************************/ 139 multichan_register_iface _window_reg_iface; 140 }; 141 142 UHD_RFNOC_BLOCK_REGISTER_DIRECT( 143 window_block_control, WINDOW_BLOCK, "Window", CLOCK_KEY_GRAPH, "bus_clk") 144