USRP Hardware Driver and USRP Manual Version: 4.2.0.0
UHD and USRP Manual
soft_register.hpp
Go to the documentation of this file.
1//
2// Copyright 2014 Ettus Research LLC
3// Copyright 2018 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
7
8#pragma once
9
10#include <uhd/exception.hpp>
14#include <unordered_map>
15#include <boost/tokenizer.hpp>
16#include <cstdint>
17#include <list>
18#include <mutex>
19
34//==================================================================
35// Soft Register Definition
36//==================================================================
37
38#define UHD_DEFINE_SOFT_REG_FIELD(name, width, shift) \
39 static const uhd::soft_reg_field_t name = (((shift & 0xFF) << 8) | (width & 0xFF))
40
41namespace uhd {
42
43// TODO: These hints were added to boost 1.53.
44
46UHD_INLINE bool likely(bool expr)
47{
48#ifdef __GNUC__
49 return __builtin_expect(expr, true);
50#else
51 return expr;
52#endif
53}
54
56UHD_INLINE bool unlikely(bool expr)
57{
58#ifdef __GNUC__
59 return __builtin_expect(expr, false);
60#else
61 return expr;
62#endif
63}
64
72typedef uint32_t soft_reg_field_t;
73
74namespace soft_reg_field {
76{
77 return (field & 0xFF);
78}
79
81{
82 return ((field >> 8) & 0xFF);
83}
84
85template <typename data_t>
86UHD_INLINE data_t mask(const soft_reg_field_t field)
87{
88 constexpr data_t ONE = static_cast<data_t>(1);
89 constexpr data_t ALL_ONES = ~static_cast<data_t>(0);
90 // Behavior for the left shift operation is undefined in C++
91 // if the shift amount is >= bitwidth of the datatype
92 // So we treat that as a special case with a branch predicition hint
93 if (likely((sizeof(data_t) * 8) != width(field))) {
94 return ((ONE << width(field)) - ONE) << shift(field);
95 } else {
96 return ALL_ONES << shift(field);
97 }
98}
99} // namespace soft_reg_field
100
102{
103public:
105
106 virtual void initialize(wb_iface& iface, bool sync = false) = 0;
107 virtual void flush() = 0;
108 virtual void refresh() = 0;
109 virtual size_t get_bitwidth() = 0;
110 virtual bool is_readable() = 0;
111 virtual bool is_writable() = 0;
112
116 template <typename soft_reg_t>
117 UHD_INLINE static soft_reg_t& cast(soft_register_base& reg)
118 {
119 soft_reg_t* ptr = dynamic_cast<soft_reg_t*>(&reg);
120 if (ptr) {
121 return *ptr;
122 } else {
123 throw uhd::type_error("failed to cast register to specified type");
124 }
125 }
126};
127
129
135template <typename reg_data_t, bool readable, bool writable>
137{
138public:
139 typedef std::shared_ptr<soft_register_t<reg_data_t, readable, writable>> sptr;
140
141 // Reserved field. Represents all bits in the register.
142 UHD_DEFINE_SOFT_REG_FIELD(REGISTER, sizeof(reg_data_t) * 8, 0); //[WIDTH-1:0]
143
150 : _iface(NULL)
151 , _wr_addr(wr_addr)
152 , _rd_addr(rd_addr)
153 , _soft_copy(0)
154 , _flush_mode(mode)
155 {
156 }
157
164 : _iface(NULL), _wr_addr(addr), _rd_addr(addr), _soft_copy(0), _flush_mode(mode)
165 {
166 }
167
173 UHD_INLINE void initialize(wb_iface& iface, bool sync = false) override
174 {
175 _iface = &iface;
176
177 // Synchronize with hardware. For RW register, flush THEN refresh.
178 if (sync && writable)
179 flush();
180 if (sync && readable)
181 refresh();
182 }
183
189 UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
190 {
191 _soft_copy = (_soft_copy & ~soft_reg_field::mask<reg_data_t>(field))
192 | ((value << soft_reg_field::shift(field))
193 & soft_reg_field::mask<reg_data_t>(field));
194 }
195
200 UHD_INLINE reg_data_t get(const soft_reg_field_t field)
201 {
202 return (_soft_copy & soft_reg_field::mask<reg_data_t>(field))
203 >> soft_reg_field::shift(field);
204 }
205
209 UHD_INLINE void flush() override
210 {
211 if (writable && _iface) {
212 // If optimized flush then poke only if soft copy is dirty
213 // If flush mode is ALWAYS, the dirty flag should get optimized
214 // out by the compiler because it is never read
215 if (_flush_mode == ALWAYS_FLUSH || _soft_copy.is_dirty()) {
216 if (get_bitwidth() <= 32) {
217 _iface->poke32(_wr_addr, static_cast<uint32_t>(_soft_copy));
218 } else if (get_bitwidth() <= 64) {
219 _iface->poke64(_wr_addr, static_cast<uint64_t>(_soft_copy));
220 } else {
222 "soft_register only supports up to 64 bits.");
223 }
224 _soft_copy.mark_clean();
225 }
226 } else {
228 "soft_register is not writable or uninitialized.");
229 }
230 }
231
235 UHD_INLINE void refresh() override
236 {
237 if (readable && _iface) {
238 if (get_bitwidth() <= 32) {
239 _soft_copy = static_cast<reg_data_t>(_iface->peek32(_rd_addr));
240 } else if (get_bitwidth() <= 64) {
241 _soft_copy = static_cast<reg_data_t>(_iface->peek64(_rd_addr));
242 } else {
244 "soft_register only supports up to 64 bits.");
245 }
246 _soft_copy.mark_clean();
247 } else {
249 "soft_register is not readable or uninitialized.");
250 }
251 }
252
256 UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
257 {
258 set(field, value);
259 flush();
260 }
261
265 UHD_INLINE reg_data_t read(const soft_reg_field_t field)
266 {
267 refresh();
268 return get(field);
269 }
270
274 UHD_INLINE size_t get_bitwidth() override
275 {
276 static const size_t BITS_IN_BYTE = 8;
277 return sizeof(reg_data_t) * BITS_IN_BYTE;
278 }
279
283 UHD_INLINE bool is_readable() override
284 {
285 return readable;
286 }
287
291 UHD_INLINE bool is_writable() override
292 {
293 return writable;
294 }
295
296private:
297 wb_iface* _iface;
298 const wb_iface::wb_addr_type _wr_addr;
299 const wb_iface::wb_addr_type _rd_addr;
300 dirty_tracked<reg_data_t> _soft_copy;
301 const soft_reg_flush_mode_t _flush_mode;
302};
303
308template <typename reg_data_t, bool readable, bool writable>
310 : public soft_register_t<reg_data_t, readable, writable>
311{
312public:
313 typedef std::shared_ptr<soft_register_sync_t<reg_data_t, readable, writable>> sptr;
314
318 : soft_register_t<reg_data_t, readable, writable>(wr_addr, rd_addr, mode)
319 , _mutex()
320 {
321 }
322
325 : soft_register_t<reg_data_t, readable, writable>(addr, mode), _mutex()
326 {
327 }
328
329 UHD_INLINE void initialize(wb_iface& iface, bool sync = false)
330 {
331 std::lock_guard<std::mutex> lock(_mutex);
333 }
334
335 UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
336 {
337 std::lock_guard<std::mutex> lock(_mutex);
339 }
340
341 UHD_INLINE reg_data_t get(const soft_reg_field_t field)
342 {
343 std::lock_guard<std::mutex> lock(_mutex);
345 }
346
348 {
349 std::lock_guard<std::mutex> lock(_mutex);
351 }
352
354 {
355 std::lock_guard<std::mutex> lock(_mutex);
357 }
358
359 UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
360 {
361 std::lock_guard<std::mutex> lock(_mutex);
363 }
364
365 UHD_INLINE reg_data_t read(const soft_reg_field_t field)
366 {
367 std::lock_guard<std::mutex> lock(_mutex);
369 }
370
371private:
372 std::mutex _mutex;
373};
374
375/*
376 * Register Shortcut Formats:
377 * - soft_reg<bits>_<mode>_t: Soft register object with an unsynchronized soft-copy.
378 * Thread unsafe but lightweight. Mostly const propagated.
379 * - soft_reg<bits>_<mode>_sync_t: Soft register object with a synchronized soft-copy.
380 * Thread safe but with memory/speed overhead.
381 * where:
382 * - <bits> = {32 or 64}
383 * - <mode> = {wo(write-only), rw(read-write) or ro(read-only)}
384 *
385 */
386
387// 32-bit shortcuts
394// 64-bit shortcuts
401
402
403/*
404 * Usage example
405 *
406 //===Define bit width, RW mode, and synchronization using base class===
407 class example_reg_t : public soft_reg32_wo_sync_t (or soft_reg32_wo_t) {
408 public:
409 //===Define all the fields===
410 UHD_DEFINE_SOFT_REG_FIELD(FIELD0, 1, 0); //[0]
411 UHD_DEFINE_SOFT_REG_FIELD(FIELD1, 15, 1); //[15:1]
412 UHD_DEFINE_SOFT_REG_FIELD(FIELD2, 16, 16); //[31:16]
413
414 example_reg_t(): //ctor with no args
415 soft_reg32_wo_t(SR_CORE_EXAMPLE_REG_OFFSET)) //===Bind to offset===
416 {
417 //===Set Initial values===
418 set(FIELD0, 0);
419 set(FIELD1, 1);
420 set(FIELD2, 0xFFFF);
421 }
422 }; //===Full register definition encapsulated in one class===
423
424 void main() {
425 example_reg_t reg_obj;
426 reg_obj.initialize(iface);
427 reg_obj.write(example_reg_t::FIELD2, 0x1234);
428
429 example_reg_t::sptr reg_sptr = std::make_shared<example_reg_t>();
430 reg_obj->initialize(iface);
431 reg_obj->write(example_reg_t::FIELD2, 0x1234);
432 }
433*/
434} // namespace uhd
435
436//==================================================================
437// Soft Register Map and Database Definition
438//==================================================================
439
440namespace uhd {
441
443{
444public:
445 typedef std::shared_ptr<soft_regmap_accessor_t> sptr;
446
448 virtual soft_register_base& lookup(const std::string& path) const = 0;
449 virtual std::vector<std::string> enumerate() const = 0;
450 virtual const std::string& get_name() const = 0;
451};
452
464{
465public:
466 soft_regmap_t(const std::string& name) : _name(name) {}
467 ~soft_regmap_t() override{};
468
472 UHD_INLINE const std::string& get_name() const override
473 {
474 return _name;
475 }
476
483 void initialize(wb_iface& iface, bool sync = false)
484 {
485 std::lock_guard<std::mutex> lock(_mutex);
486 for (soft_register_base* reg : _reglist) {
487 reg->initialize(iface, sync);
488 }
489 }
490
496 void flush()
497 {
498 std::lock_guard<std::mutex> lock(_mutex);
499 for (soft_register_base* reg : _reglist) {
500 reg->flush();
501 }
502 }
503
509 void refresh()
510 {
511 std::lock_guard<std::mutex> lock(_mutex);
512 for (soft_register_base* reg : _reglist) {
513 reg->refresh();
514 }
515 }
516
521 soft_register_base& lookup(const std::string& name) const override
522 {
523 regmap_t::const_iterator iter = _regmap.find(name);
524 if (iter != _regmap.end()) {
525 return *(iter->second);
526 } else {
527 throw uhd::runtime_error("register not found in map: " + name);
528 }
529 }
530
535 std::vector<std::string> enumerate() const override
536 {
537 std::vector<std::string> temp;
538 for (const regmap_t::value_type& reg : _regmap) {
539 temp.push_back(_name + "/" + reg.first);
540 }
541 return temp;
542 }
543
544protected:
546 PUBLIC, // Is accessible through the soft_regmap_accessor_t interface
547 PRIVATE // Is NOT accessible through the soft_regmap_accessor_t interface
548 };
549
554 const std::string& name,
555 const visibility_t visible = PRIVATE)
556 {
557 std::lock_guard<std::mutex> lock(_mutex);
558 if (visible == PUBLIC) {
559 // Only add to the map if this register is publicly visible
560 if (not _regmap.insert(regmap_t::value_type(name, &reg)).second) {
562 "cannot add two registers with the same name to regmap: " + name);
563 }
564 }
565 _reglist.push_back(&reg);
566 }
567
568private:
569 typedef std::unordered_map<std::string, soft_register_base*> regmap_t;
570 typedef std::list<soft_register_base*> reglist_t;
571
572 const std::string _name;
573 regmap_t _regmap; // For lookups
574 reglist_t _reglist; // To maintain order
575 std::mutex _mutex;
576};
577
578
586{
587public:
588 typedef std::shared_ptr<soft_regmap_db_t> sptr;
589
593 soft_regmap_db_t() : _name("") {}
594
598 soft_regmap_db_t(const std::string& name) : _name(name) {}
599
603 const std::string& get_name() const override
604 {
605 return _name;
606 }
607
611 void add(soft_regmap_t& regmap)
612 {
613 std::lock_guard<std::mutex> lock(_mutex);
614 _regmaps.push_back(&regmap);
615 }
616
621 {
622 std::lock_guard<std::mutex> lock(_mutex);
623 if (&db == this) {
624 throw uhd::assertion_error("cannot add regmap db to itself" + _name);
625 } else {
626 _regmap_dbs.push_back(&db);
627 }
628 }
629
640 soft_register_base& lookup(const std::string& path) const override
641 {
642 // Turn the slash separated path string into tokens
643 std::list<std::string> tokens;
644 for (const std::string& node : boost::tokenizer<boost::char_separator<char>>(
645 path, boost::char_separator<char>("/"))) {
646 tokens.push_back(node);
647 }
648 if ((tokens.size() > 2 && tokens.front() == _name) || // If this is a nested DB
649 (tokens.size() > 1 && _name.empty())) { // If this is a top-level DB
650 if (!_name.empty())
651 tokens.pop_front();
652 if (tokens.size() == 2) { // 2 tokens => regmap/register path
653 for (const soft_regmap_accessor_t* regmap : _regmaps) {
654 if (regmap->get_name() == tokens.front()) {
655 return regmap->lookup(tokens.back());
656 }
657 }
658 throw uhd::runtime_error("could not find register map: " + path);
659 } else if (not _regmap_dbs
660 .empty()) { //>2 tokens => <1 or more dbs>/regmap/register
661 // Reconstruct path from tokens
662 std::string newpath;
663 for (const std::string& node : tokens) {
664 newpath += ("/" + node);
665 }
666 // Dispatch path to hierarchical DB
667 for (const soft_regmap_accessor_t* db : _regmap_dbs) {
668 try {
669 return db->lookup(newpath.substr(1));
670 } catch (std::exception&) {
671 continue;
672 }
673 }
674 }
675 }
676 throw uhd::runtime_error("could not find register: " + path);
677 }
678
682 std::vector<std::string> enumerate() const override
683 {
684 std::vector<std::string> paths;
685 for (const soft_regmap_accessor_t* regmap : _regmaps) {
686 const std::vector<std::string>& regs = regmap->enumerate();
687 paths.insert(paths.end(), regs.begin(), regs.end());
688 }
689 for (const soft_regmap_accessor_t* db : _regmap_dbs) {
690 const std::vector<std::string>& regs = db->enumerate();
691 paths.insert(paths.end(), regs.begin(), regs.end());
692 }
693 return paths;
694 }
695
696private:
697 typedef std::list<soft_regmap_accessor_t*> db_t;
698
699 const std::string _name;
700 db_t _regmaps;
701 db_t _regmap_dbs;
702 std::mutex _mutex;
703};
704
705} // namespace uhd
Definition: soft_register.hpp:102
virtual bool is_writable()=0
virtual void initialize(wb_iface &iface, bool sync=false)=0
static UHD_INLINE soft_reg_t & cast(soft_register_base &reg)
Definition: soft_register.hpp:117
virtual bool is_readable()=0
virtual void refresh()=0
virtual void flush()=0
virtual size_t get_bitwidth()=0
virtual ~soft_register_base()
Definition: soft_register.hpp:104
Definition: soft_register.hpp:311
soft_register_sync_t(wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:323
soft_register_sync_t(wb_iface::wb_addr_type wr_addr, wb_iface::wb_addr_type rd_addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:315
UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:335
UHD_INLINE void refresh()
Definition: soft_register.hpp:353
UHD_INLINE void flush()
Definition: soft_register.hpp:347
UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:359
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:365
UHD_INLINE void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:329
UHD_INLINE reg_data_t get(const soft_reg_field_t field)
Definition: soft_register.hpp:341
std::shared_ptr< soft_register_sync_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:313
Definition: soft_register.hpp:137
soft_register_t(wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:162
UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:256
UHD_INLINE void refresh() override
Definition: soft_register.hpp:235
UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:189
UHD_INLINE void flush() override
Definition: soft_register.hpp:209
UHD_INLINE size_t get_bitwidth() override
Definition: soft_register.hpp:274
UHD_INLINE bool is_writable() override
Definition: soft_register.hpp:291
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:265
UHD_INLINE reg_data_t get(const soft_reg_field_t field)
Definition: soft_register.hpp:200
std::shared_ptr< soft_register_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:139
soft_register_t(wb_iface::wb_addr_type wr_addr, wb_iface::wb_addr_type rd_addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:147
UHD_INLINE bool is_readable() override
Definition: soft_register.hpp:283
UHD_INLINE void initialize(wb_iface &iface, bool sync=false) override
Definition: soft_register.hpp:173
Definition: soft_register.hpp:443
virtual ~soft_regmap_accessor_t()
Definition: soft_register.hpp:447
std::shared_ptr< soft_regmap_accessor_t > sptr
Definition: soft_register.hpp:445
virtual soft_register_base & lookup(const std::string &path) const =0
virtual std::vector< std::string > enumerate() const =0
virtual const std::string & get_name() const =0
Definition: soft_register.hpp:586
soft_register_base & lookup(const std::string &path) const override
Definition: soft_register.hpp:640
void add(soft_regmap_t &regmap)
Definition: soft_register.hpp:611
std::vector< std::string > enumerate() const override
Definition: soft_register.hpp:682
std::shared_ptr< soft_regmap_db_t > sptr
Definition: soft_register.hpp:588
soft_regmap_db_t(const std::string &name)
Definition: soft_register.hpp:598
void add(soft_regmap_db_t &db)
Definition: soft_register.hpp:620
const std::string & get_name() const override
Definition: soft_register.hpp:603
soft_regmap_db_t()
Definition: soft_register.hpp:593
Definition: soft_register.hpp:464
void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:483
UHD_INLINE const std::string & get_name() const override
Definition: soft_register.hpp:472
std::vector< std::string > enumerate() const override
Definition: soft_register.hpp:535
soft_regmap_t(const std::string &name)
Definition: soft_register.hpp:466
~soft_regmap_t() override
Definition: soft_register.hpp:467
soft_register_base & lookup(const std::string &name) const override
Definition: soft_register.hpp:521
void flush()
Definition: soft_register.hpp:496
visibility_t
Definition: soft_register.hpp:545
@ PUBLIC
Definition: soft_register.hpp:546
UHD_INLINE void add_to_map(soft_register_base &reg, const std::string &name, const visibility_t visible=PRIVATE)
Definition: soft_register.hpp:553
void refresh()
Definition: soft_register.hpp:509
Definition: wb_iface.hpp:18
uint32_t wb_addr_type
Definition: wb_iface.hpp:21
#define UHD_INLINE
Definition: config.h:65
#define UHD_API
Definition: config.h:87
UHD_INLINE data_t mask(const soft_reg_field_t field)
Definition: soft_register.hpp:86
UHD_INLINE size_t shift(const soft_reg_field_t field)
Definition: soft_register.hpp:80
UHD_INLINE size_t width(const soft_reg_field_t field)
Definition: soft_register.hpp:75
Definition: build_info.hpp:12
UHD_INLINE bool likely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:46
soft_register_t< uint64_t, false, true > soft_reg64_wo_t
Definition: soft_register.hpp:395
soft_register_sync_t< uint64_t, true, false > soft_reg64_ro_sync_t
Definition: soft_register.hpp:399
UHD_INLINE bool unlikely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:56
soft_register_sync_t< uint32_t, true, false > soft_reg32_ro_sync_t
Definition: soft_register.hpp:392
boost::noncopyable noncopyable
Definition: noncopyable.hpp:45
uint32_t soft_reg_field_t
Definition: soft_register.hpp:72
soft_register_t< uint32_t, true, false > soft_reg32_ro_t
Definition: soft_register.hpp:389
soft_register_t< uint32_t, true, true > soft_reg32_rw_t
Definition: soft_register.hpp:390
soft_register_sync_t< uint32_t, true, true > soft_reg32_rw_sync_t
Definition: soft_register.hpp:393
soft_register_t< uint64_t, true, false > soft_reg64_ro_t
Definition: soft_register.hpp:396
soft_register_sync_t< uint64_t, true, true > soft_reg64_rw_sync_t
Definition: soft_register.hpp:400
soft_register_sync_t< uint32_t, false, true > soft_reg32_wo_sync_t
Definition: soft_register.hpp:391
soft_reg_flush_mode_t
Definition: soft_register.hpp:128
@ OPTIMIZED_FLUSH
Definition: soft_register.hpp:128
@ ALWAYS_FLUSH
Definition: soft_register.hpp:128
soft_register_t< uint64_t, true, true > soft_reg64_rw_t
Definition: soft_register.hpp:397
soft_register_t< uint32_t, false, true > soft_reg32_wo_t
Definition: soft_register.hpp:388
soft_register_sync_t< uint64_t, false, true > soft_reg64_wo_sync_t
Definition: soft_register.hpp:398
#define UHD_DEFINE_SOFT_REG_FIELD(name, width, shift)
Definition: soft_register.hpp:38
Definition: exception.hpp:48
Definition: exception.hpp:157
Definition: exception.hpp:132
Definition: exception.hpp:96