scc 2025.09
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#ifdef _MSC_VER
31#include <functional>
32#else
33#include "util/delegate.h"
34#endif
35#include <functional>
36#include <limits>
37#include <sstream>
38
39namespace scc {
40
41namespace impl {
45template <typename T, bool = std::is_integral<T>::value> class helper {};
46
47template <typename T> class helper<T, true> {
48public:
49 using Type = T;
50 template <typename Type> constexpr Type get_max_uval() const {
51 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
52 }
53};
54
55template <typename T> class helper<T, false> {
56public:
57 using Type = typename T::StorageType;
58 template <typename Type> constexpr Type get_max_uval() const {
59 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
60 }
61};
62
63template <typename Type> constexpr Type get_max_uval() {
64 return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
65}
66
77template <typename DATATYPE> class sc_register : public sc_core::sc_object, public resource_access_if, public traceable {
78public:
79 using this_type = sc_register<DATATYPE>;
80
81 cci::cci_param<bool> enable_tracing;
94 sc_register(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner,
95 DATATYPE rdmask = get_max_uval<DATATYPE>(), DATATYPE wrmask = get_max_uval<DATATYPE>())
96 : sc_core::sc_object(nm)
97 , enable_tracing{std::string(name()) + ".enableTracing", scc::tracer_base::get_default_trace_enable(),
98 "enables tracing of this register", cci::CCI_ABSOLUTE_NAME}
99 , res_val(reset_val)
100 , rdmask(rdmask)
101 , wrmask(wrmask)
102 , storage(storage) {
103 owner.register_resource(this);
104 }
105
110 ~sc_register() = default;
117 bool is_trace_enabled() const override { return enable_tracing.get_value(); }
124 size_t size() const override { return sizeof(DATATYPE); }
130 void reset() override {
131 DATATYPE r(res_val);
132 if(wr_cb) {
133 sc_core::sc_time d;
134 wr_cb(*this, r, d);
135 }
136 storage = r;
137 }
138
149 bool write(const uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) override {
150 SCC_ASSERT("Access out of range" && offset + length <= sizeof(DATATYPE));
151 auto temp(storage);
152 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
153 std::copy(data, data + length, beg);
154 if(wr_cb)
155 return wr_cb(*this, temp, d);
156 storage = (temp & wrmask) | (storage & ~wrmask);
157 return true;
158 }
159
170 bool read(uint8_t* data, size_t length, uint64_t offset, sc_core::sc_time& d) const override {
171 SCC_ASSERT("Access out of range" && offset + length <= sizeof(DATATYPE));
172 auto temp(storage);
173 if(rd_cb) {
174 if(!rd_cb(*this, temp, d))
175 return false;
176 } else
177 temp &= rdmask;
178 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
179 std::copy(beg, beg + length, data);
180 return true;
181 }
182
193 bool write_dbg(const uint8_t* data, size_t length, uint64_t offset = 0) override {
194 SCC_ASSERT("Offset out of range" && offset == 0);
195 if(length != sizeof(DATATYPE))
196 return false;
197 storage = *reinterpret_cast<const DATATYPE*>(data);
198 return true;
199 }
200
211 bool read_dbg(uint8_t* data, size_t length, uint64_t offset = 0) const override {
212 SCC_ASSERT("Offset out of range" && offset == 0);
213 if(length != sizeof(DATATYPE))
214 return false;
215 *reinterpret_cast<DATATYPE*>(data) = storage;
216 return true;
217 }
218
223 operator DATATYPE() const { return storage; }
230 DATATYPE get() const { return storage; }
237 void put(DATATYPE data) const { storage = data; }
245 this_type& operator=(DATATYPE other) {
246 storage = other;
247 return *this;
248 }
249
255 this_type& operator|=(DATATYPE other) {
256 storage |= other;
257 return *this;
258 }
259
265 this_type& operator&=(DATATYPE other) {
266 storage &= other;
267 return *this;
268 }
269
277 void set_read_cb(std::function<bool(const this_type&, DATATYPE&)> read_cb) {
278 rd_cb = [read_cb](const this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return read_cb(reg, data); };
279 }
280
287 void set_read_cb(std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> read_cb) { rd_cb = read_cb; }
296 void set_write_cb(std::function<bool(this_type&, const DATATYPE&)> write_cb) {
297 wr_cb = [write_cb](this_type& reg, DATATYPE& data, sc_core::sc_time& delay) { return write_cb(reg, data); };
298 }
299
306 void set_write_cb(std::function<bool(this_type&, const DATATYPE&, sc_core::sc_time&)> write_cb) { wr_cb = write_cb; }
313 void trace(sc_core::sc_trace_file* trf) const override { sc_core::sc_trace(trf, storage, this->name()); }
315 const DATATYPE res_val;
317 const DATATYPE rdmask;
319 const DATATYPE wrmask;
320
321private:
322 const char* kind() const override { return "sc_register"; }
323
324 DATATYPE& storage;
325 std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_cb;
326 std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_cb;
327
328#ifdef _MSC_VER
329 std::function<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
330 std::function<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
331#else
332 util::delegate<bool(const this_type&, DATATYPE&, sc_core::sc_time&)> rd_dlgt;
333 util::delegate<bool(this_type&, DATATYPE&, sc_core::sc_time&)> wr_dlgt;
334#endif
335};
336} // namespace impl
342template <typename DATATYPE, size_t SIZE, size_t START = 0> class sc_register_indexed : public indexed_resource_access_if {
343public:
344 using BASE_DATA_TYPE = typename impl::helper<DATATYPE>::Type;
345
346 using value_type = sc_register<DATATYPE>;
347 using pointer = value_type*;
359 sc_core::sc_module_name nm, std::array<DATATYPE, SIZE>& storage, const DATATYPE reset_val, resetable& owner,
360 BASE_DATA_TYPE rdmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max(),
361 BASE_DATA_TYPE wrmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed ? -1 : std::numeric_limits<BASE_DATA_TYPE>::max()) {
362
363 _reg_field.init(START + SIZE, [&](const char* name, size_t idx) -> pointer {
364 return new sc_register<DATATYPE>(name, storage[idx], reset_val, owner, rdmask, wrmask);
365 });
366 }
367
377 size_t size() override { return SIZE; };
384 void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&)> read_cb) {
385 rd_cb = read_cb;
386 for(size_t idx = START; idx < SIZE + START; ++idx)
387 _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt) { return this->rd_cb(idx, reg, dt); });
388 }
389
394 void set_read_cb(std::function<bool(size_t, const sc_register<DATATYPE>&, DATATYPE&, sc_core::sc_time&)> read_cb) {
395 rd_time_cb = read_cb;
396 for(size_t idx = START; idx < SIZE + START; ++idx)
397 _reg_field[idx].set_read_cb([this, idx](const sc_register<DATATYPE>& reg, DATATYPE& dt, sc_core::sc_time& delay) {
398 return this->rd_time_cb(idx, reg, dt, delay);
399 });
400 }
401
407 void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> write_cb) {
408 wr_cb = write_cb;
409 for(size_t idx = START; idx < SIZE + START; ++idx)
410 _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt) { return this->wr_cb(idx, reg, dt); });
411 }
412
417 void set_write_cb(std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> write_cb) {
418 wr_time_cb = write_cb;
419 for(size_t idx = START; idx < SIZE + START; ++idx)
420 _reg_field[idx].set_write_cb([this, idx](sc_register<DATATYPE>& reg, const DATATYPE& dt, sc_core::sc_time& delay) {
421 return this->wr_time_cb(idx, reg, dt, delay);
422 });
423 }
424
430 reference operator[](size_t idx) noexcept override { return _reg_field[idx]; }
437 const_reference operator[](size_t idx) const noexcept override { return _reg_field[idx]; }
444 reference at(size_t idx) override {
445 assert("access out of bound" && idx < SIZE);
446 return _reg_field[idx];
447 }
448
454 const_reference at(size_t idx) const override {
455 assert("access out of bound" && idx < SIZE);
456 return _reg_field[idx];
457 }
458
459private:
460 sc_core::sc_vector<value_type> _reg_field;
461 std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&)> wr_cb;
462 std::function<bool(size_t, sc_register<DATATYPE>&, DATATYPE const&, sc_core::sc_time&)> wr_time_cb;
463 std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE&)> rd_cb;
464 std::function<bool(size_t, sc_register<DATATYPE> const&, DATATYPE&, sc_core::sc_time&)> rd_time_cb;
465};
466
469template <typename DATATYPE, DATATYPE WRMASK = impl::get_max_uval<DATATYPE>(), DATATYPE RDMASK = impl::get_max_uval<DATATYPE>()>
470class sc_register_masked : public sc_register<DATATYPE> {
471public:
472 sc_register_masked(sc_core::sc_module_name nm, DATATYPE& storage, const DATATYPE reset_val, resetable& owner)
473 : sc_register<DATATYPE>(nm, storage, reset_val, owner, RDMASK, WRMASK) {}
474};
475
479template <typename DATATYPE, size_t SIZE> struct sc_register_mem : public indexed_resource_access_if {
480 using this_type = sc_register_mem<DATATYPE, SIZE>;
481 using store_t = DATATYPE;
482
483private:
484 struct mem_wrapper : public resource_access_if {
485 ~mem_wrapper() = default;
486 std::size_t size() const override { return sizeof(DATATYPE); };
487 void reset() override { elem = 0; };
488 bool write(const uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) override {
489 assert("Access out of range" && offset + length <= sizeof(DATATYPE));
490 auto temp(elem);
491 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
492 std::copy(data, data + length, beg);
493 if(owner.wr_cb)
494 return owner.wr_cb(owner, this->offset + offset, temp, d);
495 elem = temp;
496 return true;
497 };
498 bool read(uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) const override {
499 assert("Access out of range" && offset + length <= sizeof(DATATYPE));
500 auto temp(elem);
501 if(owner.rd_cb) {
502 if(!owner.rd_cb(owner, this->offset + offset, temp, d))
503 return false;
504 }
505 auto beg = reinterpret_cast<uint8_t*>(&temp) + offset;
506 std::copy(beg, beg + length, data);
507 return true;
508 };
509 bool write_dbg(const uint8_t* data, std::size_t length, uint64_t offset = 0) override {
510 assert("Offset out of range" && offset == 0);
511 if(length != sizeof(DATATYPE))
512 return false;
513 elem = *reinterpret_cast<const DATATYPE*>(data);
514 return true;
515 };
516 bool read_dbg(uint8_t* data, std::size_t length, uint64_t offset = 0) const override {
517 assert("Offset out of range" && offset == 0);
518 if(length != sizeof(DATATYPE))
519 return false;
520 *reinterpret_cast<DATATYPE*>(data) = elem;
521 return true;
522 };
523
524 mem_wrapper(sc_register_mem& owner, DATATYPE& e, size_t of)
525 : owner(owner)
526 , elem{e}
527 , offset(of) {}
528
529 sc_register_mem& owner;
530 DATATYPE& elem;
531 size_t offset;
532 };
533
534public:
545 sc_register_mem(sc_core::sc_module_name nm, std::array<DATATYPE, SIZE>& storage, const DATATYPE reset_val, resetable& owner) {
546 _reg_field.init(SIZE,
547 [this, &storage](const char* name, size_t idx) -> pointer { return new mem_wrapper(*this, storage[idx], idx); });
548 }
549
552 ~sc_register_mem() override {}
558 size_t size() override { return SIZE; };
565 reference operator[](size_t idx) noexcept override { return _reg_field[idx]; }
572 const_reference operator[](size_t idx) const noexcept override { return _reg_field[idx]; }
579 reference at(size_t idx) override {
580 assert("access out of bound" && idx < SIZE);
581 return _reg_field[idx];
582 }
583
589 const_reference const at(size_t idx) const override {
590 assert("access out of bound" && idx < SIZE);
591 return _reg_field[idx];
592 }
593
600 void set_read_cb(std::function<bool(const this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> read_cb) { rd_cb = read_cb; }
608 void set_write_cb(std::function<bool(this_type&, size_t offset, const DATATYPE&, sc_core::sc_time&)> write_cb) { wr_cb = write_cb; }
609
610private:
611 sc_core::sc_vector<value_type> _reg_field;
612 std::function<bool(const this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> rd_cb;
613 std::function<bool(this_type&, size_t offset, DATATYPE&, sc_core::sc_time&)> wr_cb;
614};
615} // namespace scc
616
617#endif /* _SYSC_REGISTER_H_ */
a simple register implementation
Definition register.h:77
void reset() override
reset the register
Definition register.h:130
void set_write_cb(std::function< bool(this_type &, const DATATYPE &)> write_cb)
set the write callback
Definition register.h:296
void set_read_cb(std::function< bool(const this_type &, DATATYPE &)> read_cb)
set the read callback
Definition register.h:277
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:211
DATATYPE get() const
get the underlying storage
Definition register.h:230
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:170
void put(DATATYPE data) const
write to the underlying storage
Definition register.h:237
this_type & operator&=(DATATYPE other)
unary and
Definition register.h:265
this_type & operator|=(DATATYPE other)
unary or
Definition register.h:255
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:193
void trace(sc_core::sc_trace_file *trf) const override
trace the register value to the given trace file
Definition register.h:313
void set_read_cb(std::function< bool(const this_type &, DATATYPE &, sc_core::sc_time &)> read_cb)
set the read callback
Definition register.h:287
bool is_trace_enabled() const override
returns of this component shall be traced
Definition register.h:117
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:94
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:306
~sc_register()=default
desctructor
this_type & operator=(DATATYPE other)
assignment operator
Definition register.h:245
size_t size() const override
get the size of this register in bytes
Definition register.h:124
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:149
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
const_reference operator[](size_t idx) const noexcept override
Definition register.h:437
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &, sc_core::sc_time &)> write_cb)
Definition register.h:417
reference operator[](size_t idx) noexcept override
Definition register.h:430
size_t size() override
Definition register.h:377
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &)> read_cb)
Definition register.h:384
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:358
const_reference at(size_t idx) const override
Definition register.h:454
void set_write_cb(std::function< bool(size_t, sc_register< DATATYPE > &, DATATYPE const &)> write_cb)
Definition register.h:407
~sc_register_indexed() override
Definition register.h:371
reference at(size_t idx) override
Definition register.h:444
void set_read_cb(std::function< bool(size_t, const sc_register< DATATYPE > &, DATATYPE &, sc_core::sc_time &)> read_cb)
Definition register.h:394
SCC TLM utilities.
impl::sc_register< typename impl::helper< DATATYPE >::Type > sc_register
import the implementation into the scc namespace
Definition register.h:338
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:608
const_reference const at(size_t idx) const override
Definition register.h:589
const_reference operator[](size_t idx) const noexcept override
Definition register.h:572
sc_register_mem(sc_core::sc_module_name nm, std::array< DATATYPE, SIZE > &storage, const DATATYPE reset_val, resetable &owner)
Definition register.h:545
~sc_register_mem() override
Definition register.h:552
reference operator[](size_t idx) noexcept override
Definition register.h:565
size_t size() override
Definition register.h:558
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:600
reference at(size_t idx) override
Definition register.h:579
base class for automatic tracer
Definition tracer_base.h:80