1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
|
//
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: GPL-3.0-or-later
//
#include <uhd/exception.hpp>
#include <uhd/rfnoc/defaults.hpp>
#include <uhd/rfnoc/fosphor_block_control.hpp>
#include <uhd/rfnoc/property.hpp>
#include <uhd/rfnoc/registry.hpp>
#include <string>
using namespace uhd::rfnoc;
// Register offsets
const uint32_t fosphor_block_control::REG_ENABLE_ADDR = 0x00;
const uint32_t fosphor_block_control::REG_CLEAR_ADDR = 0x04;
const uint32_t fosphor_block_control::REG_RANDOM_ADDR = 0x08;
const uint32_t fosphor_block_control::REG_DECIM_ADDR = 0x0c;
const uint32_t fosphor_block_control::REG_OFFSET_ADDR = 0x10;
const uint32_t fosphor_block_control::REG_SCALE_ADDR = 0x14;
const uint32_t fosphor_block_control::REG_TRISE_ADDR = 0x18;
const uint32_t fosphor_block_control::REG_TDECAY_ADDR = 0x1c;
const uint32_t fosphor_block_control::REG_ALPHA_ADDR = 0x20;
const uint32_t fosphor_block_control::REG_EPSILON_ADDR = 0x24;
const uint32_t fosphor_block_control::REG_WF_CTRL_ADDR = 0x28;
const uint32_t fosphor_block_control::REG_WF_DECIM_ADDR = 0x2c;
// Mask bits
constexpr uint32_t RESET_HISTORY_BIT = 0;
constexpr uint32_t RESET_HISTORY_MASK = (1 << RESET_HISTORY_BIT);
constexpr uint32_t RESET_CORE_BIT = 1;
constexpr uint32_t RESET_CORE_MASK = (1 << RESET_CORE_BIT);
constexpr uint32_t HISTOGRAM_ENABLE_BIT = 0;
constexpr uint32_t HISTOGRAM_ENABLE_MASK = (1 << HISTOGRAM_ENABLE_BIT);
constexpr uint32_t WATERFALL_ENABLE_BIT = 1;
constexpr uint32_t WATERFALL_ENABLE_MASK = (1 << WATERFALL_ENABLE_BIT);
constexpr uint32_t DITHER_ENABLE_BIT = 0;
constexpr uint32_t DITHER_ENABLE_MASK = (1 << DITHER_ENABLE_BIT);
constexpr uint32_t NOISE_ENABLE_BIT = 1;
constexpr uint32_t NOISE_ENABLE_MASK = (1 << NOISE_ENABLE_BIT);
constexpr uint32_t WATERFALL_MODE_BIT = 7;
constexpr uint32_t WATERFALL_MODE_MASK = (1 << WATERFALL_MODE_BIT);
constexpr uint32_t PREDIV_RATIO_MASK = (1 << 0) | (1 << 1);
// User property names
const char* const PROP_KEY_ENABLE_HISTOGRAM = "enable_histogram";
const char* const PROP_KEY_ENABLE_WATERFALL = "enable_waterfall";
const char* const PROP_KEY_CLEAR_HISTORY = "clear_history";
const char* const PROP_KEY_ENABLE_DITHER = "enable_dither";
const char* const PROP_KEY_ENABLE_NOISE = "enable_noise";
const char* const PROP_KEY_HIST_DECIMATION = "hist_decimation";
const char* const PROP_KEY_OFFSET = "offset";
const char* const PROP_KEY_SCALE = "scale";
const char* const PROP_KEY_RISE_TIME = "trise";
const char* const PROP_KEY_DECAY_TIME = "tdecay";
const char* const PROP_KEY_ALPHA = "alpha";
const char* const PROP_KEY_EPSILON = "epsilon";
const char* const PROP_KEY_WF_PREDIVISION_RATIO = "wf_predivision_ratio";
const char* const PROP_KEY_WF_MODE = "wf_mode";
const char* const PROP_KEY_WF_DECIMATION = "wf_decimation";
// Edge property details
constexpr uint32_t HISTOGRAM_PORT = 0;
constexpr uint32_t WATERFALL_PORT = 1;
class fosphor_block_control_impl : public fosphor_block_control
{
public:
RFNOC_BLOCK_CONSTRUCTOR(fosphor_block_control)
{
// reset the core upon block construction
this->regs().poke32(REG_CLEAR_ADDR, RESET_CORE_MASK);
_register_props();
}
void set_enable_histogram(const bool enable_histogram) override
{
set_property<bool>(PROP_KEY_ENABLE_HISTOGRAM, enable_histogram);
}
bool get_enable_histogram() const override
{
return _prop_enable_histogram.get();
}
void set_enable_waterfall(const bool enable_waterfall) override
{
set_property<bool>(PROP_KEY_ENABLE_WATERFALL, enable_waterfall);
}
bool get_enable_waterfall() const override
{
return _prop_enable_waterfall.get();
}
void clear_history() override
{
set_property<bool>(PROP_KEY_CLEAR_HISTORY, true);
}
void set_enable_dither(const bool enable_dither) override
{
set_property<bool>(PROP_KEY_ENABLE_DITHER, enable_dither);
}
bool get_enable_dither() const override
{
return _prop_enable_dither.get();
}
void set_enable_noise(const bool enable_noise) override
{
set_property<bool>(PROP_KEY_ENABLE_NOISE, enable_noise);
}
bool get_enable_noise() const override
{
return _prop_enable_noise.get();
}
void set_histogram_decimation(const uint16_t decimation) override
{
set_property<int>(PROP_KEY_HIST_DECIMATION, decimation);
}
uint16_t get_histogram_decimation() const override
{
return _prop_hist_decimation.get();
}
void set_histogram_offset(const uint16_t offset) override
{
set_property<int>(PROP_KEY_OFFSET, offset);
}
uint16_t get_histogram_offset() const override
{
return _prop_offset.get();
}
void set_histogram_scale(const uint16_t scale) override
{
set_property<int>(PROP_KEY_SCALE, scale);
}
uint16_t get_histogram_scale() const override
{
return _prop_scale.get();
}
void set_histogram_rise_rate(const uint16_t rise_rate) override
{
set_property<int>(PROP_KEY_RISE_TIME, rise_rate);
}
uint16_t get_histogram_rise_rate() const override
{
return _prop_trise.get();
}
void set_histogram_decay_rate(const uint16_t decay_rate) override
{
set_property<int>(PROP_KEY_DECAY_TIME, decay_rate);
}
uint16_t get_histogram_decay_rate() const override
{
return _prop_tdecay.get();
}
void set_spectrum_alpha(const uint16_t alpha) override
{
set_property<int>(PROP_KEY_ALPHA, alpha);
}
uint16_t get_spectrum_alpha() const override
{
return _prop_alpha.get();
}
void set_spectrum_max_hold_decay(const uint16_t epsilon) override
{
set_property<int>(PROP_KEY_EPSILON, epsilon);
}
uint16_t get_spectrum_max_hold_decay() const override
{
return _prop_epsilon.get();
}
void set_waterfall_predivision(
const fosphor_waterfall_predivision_ratio waterfall_predivision) override
{
set_property<int>(
PROP_KEY_WF_PREDIVISION_RATIO, static_cast<int>(waterfall_predivision));
}
fosphor_waterfall_predivision_ratio get_waterfall_predivision() const override
{
return static_cast<fosphor_waterfall_predivision_ratio>(
_prop_wf_prediv_ratio.get());
}
void set_waterfall_mode(const fosphor_waterfall_mode waterfall_mode) override
{
set_property<int>(PROP_KEY_WF_MODE, static_cast<int>(waterfall_mode));
}
fosphor_waterfall_mode get_waterfall_mode() const override
{
return static_cast<fosphor_waterfall_mode>(_prop_wf_mode.get());
}
void set_waterfall_decimation(const uint16_t waterfall_decimation) override
{
set_property<int>(PROP_KEY_WF_DECIMATION, waterfall_decimation);
}
uint16_t get_waterfall_decimation() const override
{
return _prop_wf_decim.get();
}
/**************************************************************************
* Initialization
*************************************************************************/
private:
void _register_props()
{
// register user properties
register_property(&_prop_enable_histogram, [this]() { _program_enables(); });
register_property(&_prop_enable_waterfall, [this]() { _program_enables(); });
register_property(&_prop_clear_history,
[this]() { this->regs().poke32(REG_CLEAR_ADDR, RESET_HISTORY_MASK); });
register_property(
&_prop_enable_dither, [this]() { _program_randomness_enables(); });
register_property(
&_prop_enable_noise, [this]() { _program_randomness_enables(); });
register_property(&_prop_hist_decimation, [this]() {
int decim = _prop_hist_decimation.get();
if (decim < 2 || decim > 1024) {
throw uhd::value_error(
"Histogram decimation value must be in [2, 1024]");
}
this->regs().poke32(REG_DECIM_ADDR, uint32_t(decim - 2));
});
register_property(&_prop_offset, [this]() {
int offset = _prop_offset.get();
if (offset < 0 || offset > 65535) {
throw uhd::value_error("Offset value must be in [0, 65535]");
}
this->regs().poke32(REG_OFFSET_ADDR, uint32_t(offset));
});
register_property(&_prop_scale, [this]() {
int scale = _prop_scale.get();
if (scale < 0 || scale > 65535) {
throw uhd::value_error("Scale value must be in [0, 65535]");
}
this->regs().poke32(REG_SCALE_ADDR, uint32_t(scale));
});
register_property(&_prop_trise, [this]() {
int trise = _prop_trise.get();
if (trise < 0 || trise > 65535) {
throw uhd::value_error("Rise rate value must be in [0, 65535]");
}
this->regs().poke32(REG_TRISE_ADDR, uint32_t(trise));
});
register_property(&_prop_tdecay, [this]() {
int tdecay = _prop_tdecay.get();
if (tdecay < 0 || tdecay > 65535) {
throw uhd::value_error("Decay rate value must be in [0, 65535]");
}
this->regs().poke32(REG_TDECAY_ADDR, uint32_t(tdecay));
});
register_property(&_prop_alpha, [this]() {
int alpha = _prop_alpha.get();
if (alpha < 0 || alpha > 65535) {
throw uhd::value_error("Alpha value must be in [0, 65535]");
}
this->regs().poke32(REG_ALPHA_ADDR, uint32_t(alpha));
});
register_property(&_prop_epsilon, [this]() {
int epsilon = _prop_epsilon.get();
if (epsilon < 0 || epsilon > 65535) {
throw uhd::value_error("Max hold decay rate must be in [0, 65535]");
}
this->regs().poke32(REG_EPSILON_ADDR, uint32_t(epsilon));
});
register_property(&_prop_wf_prediv_ratio, [this]() {
int prediv_ratio = _prop_wf_prediv_ratio.get();
if (prediv_ratio
< static_cast<int>(fosphor_waterfall_predivision_ratio::RATIO_1_1)
|| prediv_ratio > static_cast<int>(
fosphor_waterfall_predivision_ratio::RATIO_1_256)) {
throw uhd::value_error(
"Waterfall predivision ratio value must be in [0, 3]");
}
_program_waterfall_mode();
});
register_property(&_prop_wf_mode, [this]() {
int wf_mode = _prop_wf_mode.get();
if (wf_mode < static_cast<int>(fosphor_waterfall_mode::MAX_HOLD)
|| wf_mode > static_cast<int>(fosphor_waterfall_mode::AVERAGE)) {
throw uhd::value_error("Waterfall mode value must be 0 or 1");
}
_program_waterfall_mode();
});
register_property(&_prop_wf_decim, [this]() {
int wf_decim = _prop_wf_decim.get();
if (wf_decim < 2 || wf_decim > 257) {
throw uhd::value_error(
"Waterfall decimation value must be in [2, 257]");
}
this->regs().poke32(REG_WF_DECIM_ADDR, uint32_t(wf_decim - 2));
});
// register edge properties
register_property(&_prop_type_in);
register_property(&_prop_type_out_histogram);
register_property(&_prop_type_out_wf);
// add resolvers for type
add_property_resolver({&_prop_type_in}, {&_prop_type_in}, [this]() {
_prop_type_in.set(IO_TYPE_SC16);
});
add_property_resolver({&_prop_type_out_histogram},
{&_prop_type_out_histogram},
[this]() { _prop_type_out_histogram.set(IO_TYPE_U8); });
add_property_resolver({&_prop_type_out_wf}, {&_prop_type_out_wf}, [this]() {
_prop_type_out_wf.set(IO_TYPE_U8);
});
}
void _program_enables()
{
uint32_t reg_value = this->regs().peek32(REG_ENABLE_ADDR)
& ~(HISTOGRAM_ENABLE_MASK | WATERFALL_ENABLE_MASK);
uint32_t histogram_enable_bit =
(_prop_enable_histogram.get()) ? HISTOGRAM_ENABLE_MASK : 0;
uint32_t waterfall_enable_bit =
(_prop_enable_waterfall.get()) ? WATERFALL_ENABLE_MASK : 0;
this->regs().poke32(
REG_ENABLE_ADDR, reg_value | histogram_enable_bit | waterfall_enable_bit);
}
void _program_randomness_enables()
{
uint32_t reg_value = this->regs().peek32(REG_RANDOM_ADDR)
& ~(DITHER_ENABLE_MASK | NOISE_ENABLE_MASK);
uint32_t dither_enable_bit = (_prop_enable_dither.get()) ? DITHER_ENABLE_MASK : 0;
uint32_t noise_enable_bit = (_prop_enable_noise.get()) ? NOISE_ENABLE_MASK : 0;
this->regs().poke32(
REG_RANDOM_ADDR, reg_value | dither_enable_bit | noise_enable_bit);
}
void _program_waterfall_mode()
{
uint32_t reg_value = this->regs().peek32(REG_WF_CTRL_ADDR)
& ~(WATERFALL_MODE_MASK | PREDIV_RATIO_MASK);
int prediv_ratio = _prop_wf_prediv_ratio.get();
int wf_mode = _prop_wf_mode.get();
uint32_t wf_mode_bits = (wf_mode << WATERFALL_MODE_BIT) | prediv_ratio;
this->regs().poke32(REG_WF_CTRL_ADDR, reg_value | wf_mode_bits);
}
/**************************************************************************
* Attributes
*************************************************************************/
property_t<std::string> _prop_type_in = property_t<std::string>{
PROP_KEY_TYPE, IO_TYPE_SC16, {res_source_info::INPUT_EDGE}};
property_t<std::string> _prop_type_out_histogram = property_t<std::string>{
PROP_KEY_TYPE, IO_TYPE_U8, {res_source_info::OUTPUT_EDGE, HISTOGRAM_PORT}};
property_t<std::string> _prop_type_out_wf = property_t<std::string>{
PROP_KEY_TYPE, IO_TYPE_U8, {res_source_info::OUTPUT_EDGE, WATERFALL_PORT}};
property_t<bool> _prop_enable_histogram =
property_t<bool>{PROP_KEY_ENABLE_HISTOGRAM, true, {res_source_info::USER}};
property_t<bool> _prop_enable_waterfall =
property_t<bool>{PROP_KEY_ENABLE_WATERFALL, true, {res_source_info::USER}};
property_t<bool> _prop_clear_history =
property_t<bool>{PROP_KEY_CLEAR_HISTORY, false, {res_source_info::USER}};
property_t<bool> _prop_enable_dither =
property_t<bool>{PROP_KEY_ENABLE_DITHER, true, {res_source_info::USER}};
property_t<bool> _prop_enable_noise =
property_t<bool>{PROP_KEY_ENABLE_NOISE, true, {res_source_info::USER}};
property_t<int> _prop_hist_decimation =
property_t<int>{PROP_KEY_HIST_DECIMATION, 2, {res_source_info::USER}};
property_t<int> _prop_offset =
property_t<int>{PROP_KEY_OFFSET, 0, {res_source_info::USER}};
property_t<int> _prop_scale =
property_t<int>{PROP_KEY_SCALE, 256, {res_source_info::USER}};
property_t<int> _prop_trise =
property_t<int>{PROP_KEY_RISE_TIME, 4096, {res_source_info::USER}};
property_t<int> _prop_tdecay =
property_t<int>{PROP_KEY_DECAY_TIME, 16384, {res_source_info::USER}};
property_t<int> _prop_alpha =
property_t<int>{PROP_KEY_ALPHA, 65280, {res_source_info::USER}};
property_t<int> _prop_epsilon =
property_t<int>{PROP_KEY_EPSILON, 1, {res_source_info::USER}};
property_t<int> _prop_wf_prediv_ratio = property_t<int>{PROP_KEY_WF_PREDIVISION_RATIO,
static_cast<int>(fosphor_waterfall_predivision_ratio::RATIO_1_1),
{res_source_info::USER}};
property_t<int> _prop_wf_mode = property_t<int>{PROP_KEY_WF_MODE,
static_cast<int>(fosphor_waterfall_mode::MAX_HOLD),
{res_source_info::USER}};
property_t<int> _prop_wf_decim =
property_t<int>{PROP_KEY_WF_DECIMATION, 8, {res_source_info::USER}};
};
UHD_RFNOC_BLOCK_REGISTER_DIRECT(
fosphor_block_control, FOSPHOR_BLOCK, "Fosphor", CLOCK_KEY_GRAPH, "bus_clk")
|