USRP Hardware Driver and USRP Manual  Version: 4.0.0.0-304-g65fbf053c
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>
11 #include <uhd/types/wb_iface.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 
42 namespace uhd {
43 
44 // TODO: These hints were added to boost 1.53.
45 
47 UHD_INLINE bool likely(bool expr)
48 {
49 #ifdef __GNUC__
50  return __builtin_expect(expr, true);
51 #else
52  return expr;
53 #endif
54 }
55 
57 UHD_INLINE bool unlikely(bool expr)
58 {
59 #ifdef __GNUC__
60  return __builtin_expect(expr, false);
61 #else
62  return expr;
63 #endif
64 }
65 
73 typedef uint32_t soft_reg_field_t;
74 
75 namespace soft_reg_field {
76 UHD_INLINE size_t width(const soft_reg_field_t field)
77 {
78  return (field & 0xFF);
79 }
80 
81 UHD_INLINE size_t shift(const soft_reg_field_t field)
82 {
83  return ((field >> 8) & 0xFF);
84 }
85 
86 template <typename data_t>
87 UHD_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 {
104 public:
105  virtual ~soft_register_base() {}
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 
136 template <typename reg_data_t, bool readable, bool writable>
138 {
139 public:
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 
149  wb_iface::wb_addr_type rd_addr,
150  soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
151  : _iface(NULL)
152  , _wr_addr(wr_addr)
153  , _rd_addr(rd_addr)
154  , _soft_copy(0)
155  , _flush_mode(mode)
156  {
157  }
158 
163  explicit soft_register_t(
164  wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
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)
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 
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 
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 
276  {
277  static const size_t BITS_IN_BYTE = 8;
278  return sizeof(reg_data_t) * BITS_IN_BYTE;
279  }
280 
285  {
286  return readable;
287  }
288 
293  {
294  return writable;
295  }
296 
297 private:
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 
309 template <typename reg_data_t, bool readable, bool writable>
311  : public soft_register_t<reg_data_t, readable, writable>
312 {
313 public:
314  typedef std::shared_ptr<soft_register_sync_t<reg_data_t, readable, writable>> sptr;
315 
317  wb_iface::wb_addr_type rd_addr,
318  soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
319  : soft_register_t<reg_data_t, readable, writable>(wr_addr, rd_addr, mode)
320  , _mutex()
321  {
322  }
323 
325  wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
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 
372 private:
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 
441 namespace uhd {
442 
444 {
445 public:
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 {
466 public:
467  soft_regmap_t(const std::string& name) : _name(name) {}
468  virtual ~soft_regmap_t(){};
469 
473  virtual UHD_INLINE const std::string& get_name() const
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  virtual soft_register_base& lookup(const std::string& name) const
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  virtual std::vector<std::string> enumerate() const
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 
545 protected:
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) {
562  throw uhd::assertion_error(
563  "cannot add two registers with the same name to regmap: " + name);
564  }
565  }
566  _reglist.push_back(&reg);
567  }
568 
569 private:
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 {
588 public:
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
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
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 == "")) { // If this is a top-level DB
651  if (_name != "")
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  virtual std::vector<std::string> enumerate() const
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 
697 private:
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
void refresh()
Definition: soft_register.hpp:510
uint32_t soft_reg_field_t
Definition: soft_register.hpp:73
UHD_INLINE void flush()
Definition: soft_register.hpp:210
std::shared_ptr< soft_register_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:140
Definition: soft_register.hpp:129
soft_reg_flush_mode_t
Definition: soft_register.hpp:129
Definition: soft_register.hpp:310
Definition: exception.hpp:157
soft_regmap_t(const std::string &name)
Definition: soft_register.hpp:467
UHD_INLINE bool unlikely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:57
UHD_INLINE void refresh()
Definition: soft_register.hpp:236
soft_register_t< uint64_t, false, true > soft_reg64_wo_t
Definition: soft_register.hpp:396
virtual std::vector< std::string > enumerate() const
Definition: soft_register.hpp:536
soft_register_t(wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:163
boost::noncopyable noncopyable
Definition: noncopyable.hpp:45
#define UHD_DEFINE_SOFT_REG_FIELD(name, width, shift)
Definition: soft_register.hpp:39
soft_register_t< uint32_t, true, false > soft_reg32_ro_t
Definition: soft_register.hpp:390
UHD_INLINE size_t get_bitwidth()
Definition: soft_register.hpp:275
virtual soft_register_base & lookup(const std::string &name) const
Definition: soft_register.hpp:522
soft_register_sync_t(wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:324
UHD_INLINE bool is_writable()
Definition: soft_register.hpp:292
soft_register_sync_t< uint64_t, true, true > soft_reg64_rw_sync_t
Definition: soft_register.hpp:401
Definition: exception.hpp:132
Definition: soft_register.hpp:586
virtual std::vector< std::string > enumerate() const
Definition: soft_register.hpp:683
soft_register_sync_t< uint32_t, false, true > soft_reg32_wo_sync_t
Definition: soft_register.hpp:392
soft_register_t< uint32_t, false, true > soft_reg32_wo_t
Definition: soft_register.hpp:389
UHD_INLINE size_t width(const soft_reg_field_t field)
Definition: soft_register.hpp:76
Definition: soft_register.hpp:547
UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:190
soft_regmap_db_t(const std::string &name)
Definition: soft_register.hpp:599
virtual ~soft_regmap_accessor_t()
Definition: soft_register.hpp:448
Definition: soft_register.hpp:137
UHD_INLINE reg_data_t get(const soft_reg_field_t field)
Definition: soft_register.hpp:201
Definition: build_info.hpp:12
soft_regmap_db_t()
Definition: soft_register.hpp:594
UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:360
virtual ~soft_register_base()
Definition: soft_register.hpp:105
void flush()
Definition: soft_register.hpp:497
std::shared_ptr< soft_regmap_db_t > sptr
Definition: soft_register.hpp:589
visibility_t
Definition: soft_register.hpp:546
UHD_INLINE void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:174
void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:484
soft_register_sync_t< uint64_t, true, false > soft_reg64_ro_sync_t
Definition: soft_register.hpp:400
virtual ~soft_regmap_t()
Definition: soft_register.hpp:468
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
Definition: soft_register.hpp:443
UHD_INLINE bool is_readable()
Definition: soft_register.hpp:284
#define UHD_INLINE
Definition: config.h:52
UHD_INLINE void flush()
Definition: soft_register.hpp:348
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:266
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
soft_register_t< uint64_t, true, false > soft_reg64_ro_t
Definition: soft_register.hpp:397
Definition: soft_register.hpp:464
Definition: soft_register.hpp:102
soft_register_sync_t< uint32_t, true, false > soft_reg32_ro_sync_t
Definition: soft_register.hpp:393
Definition: exception.hpp:48
#define UHD_API
Definition: config.h:67
UHD_INLINE data_t mask(const soft_reg_field_t field)
Definition: soft_register.hpp:87
void add(soft_regmap_t &regmap)
Definition: soft_register.hpp:612
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:366
const std::string & get_name() const
Definition: soft_register.hpp:604
UHD_INLINE void refresh()
Definition: soft_register.hpp:354
soft_register_t< uint64_t, true, true > soft_reg64_rw_t
Definition: soft_register.hpp:398
UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:257
Definition: exception.hpp:96
void add(soft_regmap_db_t &db)
Definition: soft_register.hpp:621
std::shared_ptr< soft_regmap_accessor_t > sptr
Definition: soft_register.hpp:446
soft_register_base & lookup(const std::string &path) const
Definition: soft_register.hpp:641
soft_register_sync_t< uint64_t, false, true > soft_reg64_wo_sync_t
Definition: soft_register.hpp:399
std::shared_ptr< soft_register_sync_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:314
UHD_INLINE void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:330
UHD_INLINE bool likely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:47
soft_register_sync_t< uint32_t, true, true > soft_reg32_rw_sync_t
Definition: soft_register.hpp:394
virtual UHD_INLINE const std::string & get_name() const
Definition: soft_register.hpp:473
UHD_INLINE void add_to_map(soft_register_base &reg, const std::string &name, const visibility_t visible=PRIVATE)
Definition: soft_register.hpp:554
UHD_INLINE size_t shift(const soft_reg_field_t field)
Definition: soft_register.hpp:81
Definition: soft_register.hpp:129
uint32_t wb_addr_type
Definition: wb_iface.hpp:21
static UHD_INLINE soft_reg_t & cast(soft_register_base &reg)
Definition: soft_register.hpp:118
Definition: wb_iface.hpp:17
soft_register_t< uint32_t, true, true > soft_reg32_rw_t
Definition: soft_register.hpp:391