USRP Hardware Driver and USRP Manual  Version: 4.7.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>
11 #include <uhd/types/wb_iface.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 
41 namespace uhd {
42 
43 // TODO: These hints were added to boost 1.53.
44 
46 UHD_INLINE bool likely(bool expr)
47 {
48 #ifdef __GNUC__
49  return __builtin_expect(expr, true);
50 #else
51  return expr;
52 #endif
53 }
54 
56 UHD_INLINE bool unlikely(bool expr)
57 {
58 #ifdef __GNUC__
59  return __builtin_expect(expr, false);
60 #else
61  return expr;
62 #endif
63 }
64 
72 typedef uint32_t soft_reg_field_t;
73 
74 namespace soft_reg_field {
75 UHD_INLINE size_t width(const soft_reg_field_t field)
76 {
77  return (field & 0xFF);
78 }
79 
80 UHD_INLINE size_t shift(const soft_reg_field_t field)
81 {
82  return ((field >> 8) & 0xFF);
83 }
84 
85 template <typename data_t>
86 UHD_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 {
103 public:
104  virtual ~soft_register_base() {}
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 
135 template <typename reg_data_t, bool readable, bool writable>
137 {
138 public:
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 
148  wb_iface::wb_addr_type rd_addr,
149  soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
150  : _iface(NULL)
151  , _wr_addr(wr_addr)
152  , _rd_addr(rd_addr)
153  , _soft_copy(0)
154  , _flush_mode(mode)
155  {
156  }
157 
162  explicit soft_register_t(
163  wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
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 
296 private:
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 
308 template <typename reg_data_t, bool readable, bool writable>
310  : public soft_register_t<reg_data_t, readable, writable>
311 {
312 public:
313  typedef std::shared_ptr<soft_register_sync_t<reg_data_t, readable, writable>> sptr;
314 
316  wb_iface::wb_addr_type rd_addr,
317  soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
318  : soft_register_t<reg_data_t, readable, writable>(wr_addr, rd_addr, mode)
319  , _mutex()
320  {
321  }
322 
324  wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode = ALWAYS_FLUSH)
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 
371 private:
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 
440 namespace uhd {
441 
443 {
444 public:
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 {
465 public:
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 
544 protected:
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) {
561  throw uhd::assertion_error(
562  "cannot add two registers with the same name to regmap: " + name);
563  }
564  }
565  _reglist.push_back(&reg);
566  }
567 
568 private:
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 {
587 public:
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 
696 private:
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
void refresh()
Definition: soft_register.hpp:509
uint32_t soft_reg_field_t
Definition: soft_register.hpp:72
UHD_INLINE bool is_writable() override
Definition: soft_register.hpp:291
std::shared_ptr< soft_register_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:139
Definition: soft_register.hpp:128
soft_reg_flush_mode_t
Definition: soft_register.hpp:128
UHD_INLINE void initialize(wb_iface &iface, bool sync=false) override
Definition: soft_register.hpp:173
Definition: soft_register.hpp:309
Definition: exception.hpp:156
soft_regmap_t(const std::string &name)
Definition: soft_register.hpp:466
UHD_INLINE bool unlikely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:56
std::vector< std::string > enumerate() const override
Definition: soft_register.hpp:535
soft_register_t< uint64_t, false, true > soft_reg64_wo_t
Definition: soft_register.hpp:395
soft_register_t(wb_iface::wb_addr_type addr, soft_reg_flush_mode_t mode=ALWAYS_FLUSH)
Definition: soft_register.hpp:162
boost::noncopyable noncopyable
Definition: noncopyable.hpp:45
#define UHD_DEFINE_SOFT_REG_FIELD(name, width, shift)
Definition: soft_register.hpp:38
soft_register_t< uint32_t, true, false > soft_reg32_ro_t
Definition: soft_register.hpp:389
UHD_INLINE const std::string & get_name() const override
Definition: soft_register.hpp:472
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< uint64_t, true, true > soft_reg64_rw_sync_t
Definition: soft_register.hpp:400
Definition: exception.hpp:131
Definition: soft_register.hpp:585
UHD_INLINE void flush() override
Definition: soft_register.hpp:209
soft_register_sync_t< uint32_t, false, true > soft_reg32_wo_sync_t
Definition: soft_register.hpp:391
soft_register_t< uint32_t, false, true > soft_reg32_wo_t
Definition: soft_register.hpp:388
UHD_INLINE size_t width(const soft_reg_field_t field)
Definition: soft_register.hpp:75
Definition: soft_register.hpp:546
UHD_INLINE void set(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:189
soft_regmap_db_t(const std::string &name)
Definition: soft_register.hpp:598
virtual ~soft_regmap_accessor_t()
Definition: soft_register.hpp:447
Definition: soft_register.hpp:136
UHD_INLINE reg_data_t get(const soft_reg_field_t field)
Definition: soft_register.hpp:200
Definition: build_info.hpp:12
soft_regmap_db_t()
Definition: soft_register.hpp:593
UHD_INLINE void write(const soft_reg_field_t field, const reg_data_t value)
Definition: soft_register.hpp:359
virtual ~soft_register_base()
Definition: soft_register.hpp:104
void flush()
Definition: soft_register.hpp:496
~soft_regmap_t() override
Definition: soft_register.hpp:467
std::shared_ptr< soft_regmap_db_t > sptr
Definition: soft_register.hpp:588
visibility_t
Definition: soft_register.hpp:545
const std::string & get_name() const override
Definition: soft_register.hpp:603
void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:483
soft_register_sync_t< uint64_t, true, false > soft_reg64_ro_sync_t
Definition: soft_register.hpp:399
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
Definition: soft_register.hpp:442
#define UHD_INLINE
Definition: config.h:65
UHD_INLINE void flush()
Definition: soft_register.hpp:347
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:265
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
soft_register_t< uint64_t, true, false > soft_reg64_ro_t
Definition: soft_register.hpp:396
Definition: soft_register.hpp:463
Definition: soft_register.hpp:101
soft_register_sync_t< uint32_t, true, false > soft_reg32_ro_sync_t
Definition: soft_register.hpp:392
std::vector< std::string > enumerate() const override
Definition: soft_register.hpp:682
Definition: exception.hpp:47
#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 bool is_readable() override
Definition: soft_register.hpp:283
void add(soft_regmap_t &regmap)
Definition: soft_register.hpp:611
soft_register_base & lookup(const std::string &name) const override
Definition: soft_register.hpp:521
UHD_INLINE reg_data_t read(const soft_reg_field_t field)
Definition: soft_register.hpp:365
UHD_INLINE void refresh()
Definition: soft_register.hpp:353
soft_register_t< uint64_t, true, true > soft_reg64_rw_t
Definition: soft_register.hpp:397
soft_register_base & lookup(const std::string &path) const override
Definition: soft_register.hpp:640
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
Definition: exception.hpp:95
void add(soft_regmap_db_t &db)
Definition: soft_register.hpp:620
std::shared_ptr< soft_regmap_accessor_t > sptr
Definition: soft_register.hpp:445
UHD_INLINE size_t get_bitwidth() override
Definition: soft_register.hpp:274
soft_register_sync_t< uint64_t, false, true > soft_reg64_wo_sync_t
Definition: soft_register.hpp:398
std::shared_ptr< soft_register_sync_t< reg_data_t, readable, writable > > sptr
Definition: soft_register.hpp:313
UHD_INLINE void initialize(wb_iface &iface, bool sync=false)
Definition: soft_register.hpp:329
UHD_INLINE bool likely(bool expr)
hint for the branch prediction
Definition: soft_register.hpp:46
soft_register_sync_t< uint32_t, true, true > soft_reg32_rw_sync_t
Definition: soft_register.hpp:393
UHD_INLINE void add_to_map(soft_register_base &reg, const std::string &name, const visibility_t visible=PRIVATE)
Definition: soft_register.hpp:553
UHD_INLINE size_t shift(const soft_reg_field_t field)
Definition: soft_register.hpp:80
Definition: soft_register.hpp:128
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:117
Definition: wb_iface.hpp:17
soft_register_t< uint32_t, true, true > soft_reg32_rw_t
Definition: soft_register.hpp:390