scc 2026.07
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 <cstddef>
21#include <memory>
22
23#include "resetable.h"
24#include "resource_access_if.h"
25#include "scc/report.h"
26#include <cci_configuration>
27#include <scc/traceable.h>
28#include <scc/tracer_base.h>
29#include <scc/utilities.h>
30#include <sysc/kernel/sc_object.h>
31#ifdef _MSC_VER
32#include <functional>
33#else
34#include "util/delegate.h"
35#endif
36#include <functional>
37#include <limits>
38#include <sstream>
39
40namespace scc {
41
42namespace impl {
46template <typename T, bool = std::is_integral<T>::value> class helper {};
47
48template <typename T> class helper<T, true> {
49public:
50 using Type = T;
51 template <typename Type> constexpr Type get_max_uval() const {
52 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
53 }
54};
55
56template <typename T> class helper<T, false> {
57public:
58 using Type = typename T::StorageType;
59 template <typename Type> constexpr Type get_max_uval() const {
60 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
61 }
62};
63
64template <typename Type> constexpr Type get_max_uval() {
65 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
66}
67
78template <typename DATATYPE> class sc_register : public sc_core::sc_object, public resource_access_if, public traceable {
79public:
80 using this_type = sc_register<DATATYPE>;
81
82 cci::cci_param<bool> enable_tracing;
83 cci::cci_param<bool> enable_side_effect;
96 sc_register(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner,
97 DATATYPE rdmask = get_max_uval<DATATYPE>(), DATATYPE wrmask = get_max_uval<DATATYPE>())
98 : sc_core::sc_object(nm)
99 , enable_tracing{std::string(name()) + ".enableTracing", scc::tracer_base::get_default_trace_enable(),
100 "enables tracing of this register", cci::CCI_ABSOLUTE_NAME}
101 , enable_side_effect{std::string(name()) + ".enableSideEffect", true, "enables side effect in debug read/write operations",
102 cci::CCI_ABSOLUTE_NAME}
103 , res_val(reset_val)
104 , rdmask(rdmask)
105 , wrmask(wrmask)
106 , storage(storage) {
107 owner.register_resource(this);
108 }
109
114 ~sc_register() = default;
121 bool is_trace_enabled() const override { return enable_tracing.get_value(); }
127 char const* full_name() const override { return name(); };
134 size_t size() const override { return sizeof(DATATYPE); }
140 void reset() override {
141 DATATYPE r(res_val);
142 if(wr_cb) {
143 sc_core::sc_time d;
144 wr_cb(*this, r, d);
145 }
146 storage = r;
147 }
148
159 bool write(const uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) override {
160 SCC_ASSERT("Access out of range" && offset + length <= sizeof(DATATYPE));
161 auto temp(storage);
162 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
163 std::copy(data, data + length, beg);
164 if(wr_cb)
165 return wr_cb(*this, temp, d);
166 storage = (temp & wrmask) | (storage & ~wrmask);
167 return true;
168 }
169
180 bool read(uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) const override {
181 SCC_ASSERT("Access out of range" && offset + length <= sizeof(DATATYPE));
182 auto temp(storage);
183 if(rd_cb) {
184 if(!rd_cb(*this, temp, d))
185 return false;
186 } else
187 temp &= rdmask;
188 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
189 std::copy(beg, beg + length, data);
190 return true;
191 }
192
201 bool write_dbg(const uint8_t* data, size_t length, uint64_t offset = 0) override {
202 if(enable_side_effect.get_value()) {
203 sc_core::sc_time d;
204 return write(data, length, offset, d);
205 }
206
207 SCC_ASSERT("Offset out of range" && offset == 0);
208 if(length != sizeof(DATATYPE))
209 return false;
210 storage = *reinterpret_cast<const DATATYPE*>(data);
211 return true;
212 }
213
222 bool read_dbg(uint8_t* data, size_t length, uint64_t offset = 0) const override {
223 if(enable_side_effect.get_value()) {
224 sc_core::sc_time d;
225 return read(data, length, offset, d);
226 }
227
228 SCC_ASSERT("Offset out of range" && offset == 0);
229 if(length != sizeof(DATATYPE))
230 return false;
231 *reinterpret_cast<DATATYPE*>(data) = storage;
232 return true;
233 }
234
239 operator DATATYPE() const { return storage; }
246 DATATYPE get() const { return storage; }
253 void put(DATATYPE data) const { storage = data; }
261 this_type& operator=(DATATYPE other) {
262 storage = other;
263 return *this;
264 }
265
271 this_type& operator|=(DATATYPE other) {
272 storage |= other;
273 return *this;
274 }
275
281 this_type& operator&=(DATATYPE other) {
282 storage &= other;
283 return *this;
284 }
285
293 void set_read_cb(std::function<bool(const this_type&, DATATYPE&)> read_cb) {
294 rd_cb = [read_cb](const this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return read_cb(reg, data); };
295 }
296
303 void set_read_cb(std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> read_cb) { rd_cb = read_cb; }
312 void set_write_cb(std::function<bool(this_type&, const DATATYPE&)> write_cb) {
313 wr_cb = [write_cb](this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return write_cb(reg, data); };
314 }
315
322 void set_write_cb(std::function<bool(this_type&, const DATATYPE&, sc_core::sc_time&)> write_cb) { wr_cb = write_cb; }
329 void trace(sc_core::sc_trace_file* trf) const override { sc_core::sc_trace(trf, storage, this->name()); }
331 const DATATYPE res_val;
333 const DATATYPE rdmask;
335 const DATATYPE wrmask;
336
337private:
338 const char* kind() const override { return "sc_register"; }
339
340 DATATYPE& storage;
341 std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_cb;
342 std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_cb;
343
344#ifdef _MSC_VER
345 std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
346 std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
347#else
348 util::delegate<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
349 util::delegate<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
350#endif
351};
352} // namespace impl
358template <typename DATATYPE, size_t SIZE, size_t START = 0> class sc_register_indexed : public indexed_resource_access_if {
359public:
360 using BASE_DATA_TYPE = typename impl::helper<DATATYPE>::Type;
361
362 using value_type = sc_register<DATATYPE>;
363 using pointer = value_type*;
375 sc_core::sc_module_name nm, std::array<DATATYPE, SIZE>& storage, const DATATYPE reset_val, resetable& owner,
376 BASE_DATA_TYPE rdmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max(),
377 BASE_DATA_TYPE wrmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max()) {
378
379 _reg_field.init(START + SIZE, [&](const char* name, size_t idx) -> pointer {
380 return new sc_register<DATATYPE>(name, storage[idx], reset_val, owner, rdmask, wrmask);
381 });
382 }
383
393 size_t size() override { return SIZE; };
400 void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&)> read_cb) {
401 rd_cb = read_cb;
402 for(size_t idx = START; idx < SIZE + START; ++idx)
403 _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt) { return this->rd_cb(idx, reg, dt); });
404 }
405
410 void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&, sc_core::sc_time&)> read_cb) {
411 rd_time_cb = read_cb;
412 for(size_t idx = START; idx < SIZE + START; ++idx)
413 _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt, sc_core::sc_time& delay) {
414 return this->rd_time_cb(idx, reg, dt, delay);
415 });
416 }
417
423 void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> write_cb) {
424 wr_cb = write_cb;
425 for(size_t idx = START; idx < SIZE + START; ++idx)
426 _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt) { return this->wr_cb(idx, reg, dt); });
427 }
428
433 void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> write_cb) {
434 wr_time_cb = write_cb;
435 for(size_t idx = START; idx < SIZE + START; ++idx)
436 _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt, sc_core::sc_time& delay) {
437 return this->wr_time_cb(idx, reg, dt, delay);
438 });
439 }
440
446 reference operator[](size_t idx) noexcept override { return _reg_field[idx]; }
453 const_reference operator[](size_t idx) const noexcept override { return _reg_field[idx]; }
460 reference at(size_t idx) override {
461 assert("access out of bound" && idx < SIZE);
462 return _reg_field[idx];
463 }
464
470 const_reference at(size_t idx) const override {
471 assert("access out of bound" && idx < SIZE);
472 return _reg_field[idx];
473 }
474
475private:
476 sc_core::sc_vector<value_type> _reg_field;
477 std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> wr_cb;
478 std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> wr_time_cb;
479 std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE&)> rd_cb;
480 std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE&, sc_core::sc_time&)> rd_time_cb;
481};
482
485template <typename DATATYPE, DATATYPE WRMASK = impl::get_max_uval<DATATYPE>(), DATATYPE RDMASK = impl::get_max_uval<DATATYPE>()>
486class sc_register_masked : public sc_register<DATATYPE> {
487public:
488 sc_register_masked(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner)
489 : sc_register<DATATYPE>(nm, storage, reset_val, owner, RDMASK, WRMASK) {}
490};
491
495template <typename DATATYPE, size_t SIZE> struct sc_register_mem : public indexed_resource_access_if {
496 using this_type = sc_register_mem<DATATYPE, SIZE>;
497 using store_t = DATATYPE;
498
499private:
500 struct mem_wrapper : public resource_access_if {
501 ~mem_wrapper() = default;
502 char const* full_name() const override { return "memory"; };
503 std::size_t size() const override { return sizeof(DATATYPE); };
504 void reset() override { elem = 0; };
505 bool write(const uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) override {
506 assert("Access out of range" && offset + length <= sizeof(DATATYPE));
507 auto temp(elem);
508 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
509 std::copy(data, data + length, beg);
510 if(owner.wr_cb)
511 return owner.wr_cb(owner, this->offset + offset, temp, d);
512 elem = temp;
513 return true;
514 };
515 bool read(uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) const override {
516 assert("Access out of range" && offset + length <= sizeof(DATATYPE));
517 auto temp(elem);
518 if(owner.rd_cb) {
519 if(!owner.rd_cb(owner, this->offset + offset, temp, d))
520 return false;
521 }
522 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
523 std::copy(beg, beg + length, data);
524 return true;
525 };
526 bool write_dbg(const uint8_t* data, std::size_t length, uint64_t offset = 0) override {
527 assert("Offset out of range" && offset == 0);
528 if(length != sizeof(DATATYPE))
529 return false;
530 elem = *reinterpret_cast<const DATATYPE*>(data);
531 return true;
532 };
533 bool read_dbg(uint8_t* data, std::size_t length, uint64_t offset = 0) const override {
534 assert("Offset out of range" && offset == 0);
535 if(length != sizeof(DATATYPE))
536 return false;
537 *reinterpret_cast<DATATYPE*>(data) = elem;
538 return true;
539 };
540
541 mem_wrapper(sc_register_mem& owner, DATATYPE& e, size_t of)
542 : owner(owner)
543 , elem{e}
544 , offset(of) {}
545
546 sc_register_mem& owner;
547 DATATYPE& elem;
548 size_t offset;
549 };
550
551public:
562 sc_register_mem(sc_core::sc_module_name nm, std::array<DATATYPE, SIZE>& storage, const DATATYPE reset_val, resetable& owner) {
563 _reg_field.init(SIZE,
564 [this, &storage](const char* name, size_t idx) -> pointer { return new mem_wrapper(*this, storage[idx], idx); });
565 }
566
569 ~sc_register_mem() override {}
575 size_t size() override { return SIZE; };
582 reference operator[](size_t idx) noexcept override { return _reg_field[idx]; }
589 const_reference operator[](size_t idx) const noexcept override { return _reg_field[idx]; }
596 reference at(size_t idx) override {
597 assert("access out of bound" && idx < SIZE);
598 return _reg_field[idx];
599 }
600
606 const_reference const at(size_t idx) const override {
607 assert("access out of bound" && idx < SIZE);
608 return _reg_field[idx];
609 }
610
617 void set_read_cb(std::function<bool(const this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> read_cb) { rd_cb = read_cb; }
625 void set_write_cb(std::function<bool(this_type&, size_t offset, const DATATYPE&, sc_core::sc_time&)> write_cb) { wr_cb = write_cb; }
626
627private:
628 sc_core::sc_vector<value_type> _reg_field;
629 std::function<bool(const this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> rd_cb;
630 std::function<bool(this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> wr_cb;
631};
632} // namespace scc
633
634#endif /* _SYSC_REGISTER_H_ */
a simple register implementation
Definition register.h:78
void reset() override
reset the register
Definition register.h:140
void set_write_cb(std::function< bool(this_type &, const DATATYPE &)> write_cb)
set the write callback
Definition register.h:312
void set_read_cb(std::function< bool(const this_type &, DATATYPE &)> read_cb)
set the read callback
Definition register.h:293
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:222
DATATYPE get() const
get the underlying storage
Definition register.h:246
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:180
void put(DATATYPE data) const
write to the underlying storage
Definition register.h:253
this_type & operator&=(DATATYPE other)
unary and
Definition register.h:281
this_type & operator|=(DATATYPE other)
unary or
Definition register.h:271
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:201
void trace(sc_core::sc_trace_file *trf) const override
trace the register value to the given trace file
Definition register.h:329
void set_read_cb(std::function< bool(const this_type &, DATATYPE &, sc_core::sc_time &)> read_cb)
set the read callback
Definition register.h:303
bool is_trace_enabled() const override
returns of this component shall be traced
Definition register.h:121
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:96
void set_write_cb(std::function< bool(this_type &, const DATATYPE &, sc_core::sc_time &)> write_cb)
set the write callback triggered upon a write request
Definition register.h:322
~sc_register()=default
desctructor
char const * full_name() const override
return the name of the resource
Definition register.h:127
this_type & operator=(DATATYPE other)
assignment operator
Definition register.h:261
size_t size() const override
get the size of this register in bytes
Definition register.h:134
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:159
interface defining access to an indexed resource e.g. register file
base class for components having a reset
Definition resetable.h:32
void register_resource(resource_access_if *res)
register a resource with this reset domain
Definition resetable.h:68
interface defining access to a resource e.g. a register
virtual std::size_t size() const =0
return the size of the resource
virtual void reset()=0
reset the resource
virtual char const * full_name() const =0
return the name of the resource
const_reference operator[](size_t idx) const noexcept override
Definition register.h:453
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &, sc_core::sc_time &)> write_cb)
Definition register.h:433
reference operator[](size_t idx) noexcept override
Definition register.h:446
size_t size() override
Definition register.h:393
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &)> read_cb)
Definition register.h:400
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:374
const_reference at(size_t idx) const override
Definition register.h:470
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &)> write_cb)
Definition register.h:423
~sc_register_indexed() override
Definition register.h:387
reference at(size_t idx) override
Definition register.h:460
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &, sc_core::sc_time &)> read_cb)
Definition register.h:410
SCC TLM utilities.
impl::sc_register< typename impl::helper< DATATYPE >::Type > sc_register
import the implementation into the scc namespace
Definition register.h:354
void set_write_cb(std::function< bool(this_type &, size_t offset, const DATATYPE &, sc_core::sc_time &)> write_cb)
set the write callback triggered upon a write request
Definition register.h:625
const_reference const at(size_t idx) const override
Definition register.h:606
const_reference operator[](size_t idx) const noexcept override
Definition register.h:589
sc_register_mem(sc_core::sc_module_name nm, std::array< DATATYPE, SIZE > &storage, const DATATYPE reset_val, resetable &owner)
Definition register.h:562
~sc_register_mem() override
Definition register.h:569
reference operator[](size_t idx) noexcept override
Definition register.h:582
size_t size() override
Definition register.h:575
void set_read_cb(std::function< bool(const this_type &, size_t offset, DATATYPE &, sc_core::sc_time &)> read_cb)
set the read callback
Definition register.h:617
reference at(size_t idx) override
Definition register.h:596
base class for automatic tracer
Definition tracer_base.h:80