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