scc  2022.4.0
SystemC components library
register.h
1 /*******************************************************************************
2  * Copyright 2016-2021 MINRES Technologies GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *******************************************************************************/
16 
17 #ifndef _SYSC_REGISTER_H_
18 #define _SYSC_REGISTER_H_
19 
20 #include <memory>
21 
22 #include "resetable.h"
23 #include "resource_access_if.h"
24 #include "scc/traceable.h"
25 #include "scc/utilities.h"
26 #ifdef _MSC_VER
27 #include <functional>
28 #else
29 #include "util/delegate.h"
30 #endif
31 #include <functional>
32 #include <limits>
33 #include <sstream>
34 
35 namespace scc {
36 
37 namespace impl {
41 template <typename T, bool = std::is_integral<T>::value> class helper {};
42 
43 template <typename T> class helper<T, true> {
44 public:
45  using Type = T;
46  template <typename Type> constexpr Type get_max_uval() const {
47  return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
48  }
49 };
50 
51 template <typename T> class helper<T, false> {
52 public:
53  using Type = typename T::StorageType;
54  template <typename Type> constexpr Type get_max_uval() const {
55  return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
56  }
57 };
58 
59 template <typename Type> constexpr Type get_max_uval() {
60  return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
61 }
62 
73 template <typename DATATYPE> class sc_register : public sc_core::sc_object, public resource_access_if, public traceable {
74 public:
88  sc_register(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner,
89  DATATYPE rdmask = get_max_uval<DATATYPE>(), DATATYPE wrmask = get_max_uval<DATATYPE>())
90  : sc_core::sc_object(nm)
91  , res_val(reset_val)
92  , rdmask(rdmask)
93  , wrmask(wrmask)
94  , storage(storage) {
95  owner.register_resource(this);
96  }
102  ~sc_register() = default;
109  size_t size() const override { return sizeof(DATATYPE); }
115  void reset() override {
116  DATATYPE r(res_val);
117  if(wr_cb) {
118  sc_core::sc_time d;
119  wr_cb(*this, r, d);
120  }
121  storage = r;
122  }
134  bool write(const uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) override {
135  assert("Access out of range" && offset + length <= sizeof(DATATYPE));
136  auto temp(storage);
137  auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
138  std::copy(data, data + length, beg);
139  if(wr_cb)
140  return wr_cb(*this, temp, d);
141  storage = (temp & wrmask) | (storage & ~wrmask);
142  return true;
143  }
155  bool read(uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) const override {
156  assert("Access out of range" && offset + length <= sizeof(DATATYPE));
157  auto temp(storage);
158  if(rd_cb) {
159  if(!rd_cb(*this, temp, d))
160  return false;
161  } else
162  temp &= rdmask;
163  auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
164  std::copy(beg, beg + length, data);
165  return true;
166  }
178  bool write_dbg(const uint8_t* data, size_t length, uint64_t offset = 0) override {
179  assert("Offset out of range" && offset == 0);
180  if(length != sizeof(DATATYPE))
181  return false;
182  storage = *reinterpret_cast<const DATATYPE*>(data);
183  return true;
184  }
196  bool read_dbg(uint8_t* data, size_t length, uint64_t offset = 0) const override {
197  assert("Offset out of range" && offset == 0);
198  if(length != sizeof(DATATYPE))
199  return false;
200  *reinterpret_cast<DATATYPE*>(data) = storage;
201  return true;
202  }
208  operator DATATYPE() const { return storage; }
215  DATATYPE get() const { return storage; }
222  void put(DATATYPE data) const { storage = data; }
230  this_type& operator=(DATATYPE other) {
231  storage = other;
232  return *this;
233  }
241  this_type& operator|=(DATATYPE other) {
242  storage |= other;
243  return *this;
244  }
252  this_type& operator&=(DATATYPE other) {
253  storage &= other;
254  return *this;
255  }
265  void set_read_cb(std::function<bool(const this_type&, DATATYPE&)> read_cb) {
266  rd_cb = [read_cb](const this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return read_cb(reg, data); };
267  }
276  void set_read_cb(std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> read_cb) { rd_cb = read_cb; }
286  void set_write_cb(std::function<bool(this_type&, const DATATYPE&)> write_cb) {
287  wr_cb = [write_cb](this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return write_cb(reg, data); };
288  }
302  void set_write_cb(std::function<bool(this_type&, const DATATYPE&, sc_core::sc_time&)> write_cb) { wr_cb = write_cb; }
309  void trace(sc_core::sc_trace_file* trf) const override { sc_core::sc_trace(trf, storage, this->name()); }
311  const DATATYPE res_val;
313  const DATATYPE rdmask;
315  const DATATYPE wrmask;
316 
317 private:
318  const char* kind() const override { return "sc_register"; }
319 
320  DATATYPE& storage;
321  std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_cb;
322  std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_cb;
323 
324 #ifdef _MSC_VER
325  std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
326  std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
327 #else
328  util::delegate<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
329  util::delegate<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
330 #endif
331 };
332 } // namespace impl
338 template <typename DATATYPE, size_t SIZE, size_t START = 0> class sc_register_indexed : public indexed_resource_access_if {
339 public:
340  using BASE_DATA_TYPE = typename impl::helper<DATATYPE>::Type;
341 
343  using pointer = value_type*;
355  sc_core::sc_module_name nm, std::array<DATATYPE, SIZE>& storage, const DATATYPE reset_val, resetable& owner,
356  BASE_DATA_TYPE rdmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max(),
357  BASE_DATA_TYPE wrmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max()) {
358 
359  _reg_field.init(START + SIZE, [&](const char* name, size_t idx) -> pointer {
360  return new sc_register<DATATYPE>(name, storage[idx], reset_val, owner, rdmask, wrmask);
361  });
362  }
363 
367  ~sc_register_indexed() override {}
373  size_t size() override { return SIZE; };
380  void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&)> read_cb) {
381  rd_cb = read_cb;
382  for(size_t idx = START; idx < SIZE + START; ++idx)
383  _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt) { return this->rd_cb(idx, reg, dt); });
384  }
390  void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&, sc_core::sc_time&)> read_cb) {
391  rd_time_cb = read_cb;
392  for(size_t idx = START; idx < SIZE + START; ++idx)
393  _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt, sc_core::sc_time& delay) {
394  return this->rd_time_cb(idx, reg, dt, delay);
395  });
396  }
403  void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> write_cb) {
404  wr_cb = write_cb;
405  for(size_t idx = START; idx < SIZE + START; ++idx)
406  _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt) { return this->wr_cb(idx, reg, dt); });
407  }
413  void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> write_cb) {
414  wr_time_cb = write_cb;
415  for(size_t idx = START; idx < SIZE + START; ++idx)
416  _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt, sc_core::sc_time& delay) {
417  return this->wr_time_cb(idx, reg, dt, delay);
418  });
419  }
426  reference operator[](size_t idx) noexcept override { return _reg_field[idx]; }
433  const_reference operator[](size_t idx) const noexcept override { return _reg_field[idx]; }
440  reference at(size_t idx) override {
441  assert("access out of bound" && idx < SIZE);
442  return _reg_field[idx];
443  }
450  const_reference at(size_t idx) const override {
451  assert("access out of bound" && idx < SIZE);
452  return _reg_field[idx];
453  }
454 
455 private:
456  sc_core::sc_vector<value_type> _reg_field;
457  std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> wr_cb;
458  std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> wr_time_cb;
459  std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE const&)> rd_cb;
460  std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE const&, sc_core::sc_time&)> rd_time_cb;
461 };
465 template <typename DATATYPE, DATATYPE WRMASK = impl::get_max_uval<DATATYPE>(), DATATYPE RDMASK = impl::get_max_uval<DATATYPE>()>
466 class sc_register_masked : public sc_register<DATATYPE> {
467 public:
468  sc_register_masked(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner)
469  : sc_register<DATATYPE>(nm, storage, reset_val, owner, RDMASK, WRMASK) {}
470 };
471 } // namespace scc
472 
473 #endif /* _SYSC_REGISTER_H_ */
a simple register implementation
Definition: register.h:73
void reset() override
reset the register
Definition: register.h:115
void set_write_cb(std::function< bool(this_type &, const DATATYPE &)> write_cb)
set the write callback
Definition: register.h:286
void set_read_cb(std::function< bool(const this_type &, DATATYPE &)> read_cb)
set the read callback
Definition: register.h:265
bool read_dbg(uint8_t *data, size_t length, uint64_t offset=0) const override
debug read function from resource_access_if
Definition: register.h:196
DATATYPE get() const
get the underlying storage
Definition: register.h:215
bool read(uint8_t *data, size_t length, uint64_t offset, sc_core::sc_time &d) const override
read function from resource_access_if
Definition: register.h:155
void put(DATATYPE data) const
write to the underlying storage
Definition: register.h:222
this_type & operator&=(DATATYPE other)
unary and
Definition: register.h:252
this_type & operator|=(DATATYPE other)
unary or
Definition: register.h:241
bool write_dbg(const uint8_t *data, size_t length, uint64_t offset=0) override
debug write function from resource_access_if
Definition: register.h:178
void trace(sc_core::sc_trace_file *trf) const override
trace the register value to the given trace file
Definition: register.h:309
sc_register(sc_core::sc_module_name nm, DATATYPE &storage, const DATATYPE reset_val, resetable &owner, DATATYPE rdmask=get_max_uval< DATATYPE >(), DATATYPE wrmask=get_max_uval< DATATYPE >())
the constructor
Definition: register.h:88
const DATATYPE wrmask
the SW write mask
Definition: register.h:315
void set_write_cb(std::function< bool(this_type &, const DATATYPE &, sc_core::sc_time &)> write_cb)
Definition: register.h:302
~sc_register()=default
desctructor
const DATATYPE rdmask
the SW read mask
Definition: register.h:313
const DATATYPE res_val
the reset value
Definition: register.h:311
this_type & operator=(DATATYPE other)
assignment operator
Definition: register.h:230
size_t size() const override
get the size of this register in bytes
Definition: register.h:109
bool write(const uint8_t *data, size_t length, uint64_t offset, sc_core::sc_time &d) override
write function from resource_access_if
Definition: register.h:134
interface defining access to an indexed resource e.g. register file
base class for components having a reset
Definition: resetable.h:32
interface defining access to a resource e.g. a register
const_reference operator[](size_t idx) const noexcept override
Definition: register.h:433
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &, sc_core::sc_time &)> write_cb)
Definition: register.h:413
reference operator[](size_t idx) noexcept override
Definition: register.h:426
size_t size() override
Definition: register.h:373
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &)> read_cb)
Definition: register.h:380
sc_register_indexed(sc_core::sc_module_name nm, std::array< DATATYPE, SIZE > &storage, const DATATYPE reset_val, resetable &owner, BASE_DATA_TYPE rdmask=std::numeric_limits< BASE_DATA_TYPE >::is_signed ? -1 :std::numeric_limits< BASE_DATA_TYPE >::max(), BASE_DATA_TYPE wrmask=std::numeric_limits< BASE_DATA_TYPE >::is_signed ? -1 :std::numeric_limits< BASE_DATA_TYPE >::max())
Definition: register.h:354
const_reference at(size_t idx) const override
Definition: register.h:450
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &)> write_cb)
Definition: register.h:403
~sc_register_indexed() override
Definition: register.h:367
reference at(size_t idx) override
Definition: register.h:440
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &, sc_core::sc_time &)> read_cb)
Definition: register.h:390
interface defining a traceable component
Definition: traceable.h:32
SCC SystemC utilities.