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