scc 2026.07
SystemC components library
tlm_target_bfs_register_base.h
1/*******************************************************************************
2 * Copyright 2021, 2021 Chair of Electronic Design Automation, TU Munich
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 *******************************************************************************/
23
24#ifndef __SCC_TLM_TARGET_BFS_REGISTER_BASE_H__
25#define __SCC_TLM_TARGET_BFS_REGISTER_BASE_H__
26
27#include <algorithm>
28#include <cstddef>
29#include <functional>
30#include <string>
31#include <vector>
32
33#include <boost/preprocessor/arithmetic/add.hpp>
34#include <boost/preprocessor/arithmetic/mul.hpp>
35#include <boost/preprocessor/cat.hpp>
36#include <boost/preprocessor/facilities/overload.hpp>
37#include <boost/preprocessor/punctuation/comma_if.hpp>
38#include <boost/preprocessor/repetition/repeat.hpp>
39#include <boost/preprocessor/stringize.hpp>
40#include <boost/preprocessor/tuple/elem.hpp>
41
42#include "resetable.h"
43#include "resource_access_if.h"
44#include "sysc/kernel/sc_module_name.h"
45#include "sysc/kernel/sc_object.h"
46#include "tlm_target.h"
47
48#define ID_SCC_TLM_TARGET_BFS_REGISTER_BASE "scc: tlm target bitfield support register base"
49
50namespace scc {
51
57template <typename datatype_t> class abstract_bitfield {
58public:
59 abstract_bitfield(std::string name, size_t bitOffset, size_t bitSize, std::string urid)
60 : bitOffset{bitOffset}
61 , bitSize{bitSize}
62 , name{std::move(name)}
63 , urid{std::move(urid)} {}
64
65 virtual void write(datatype_t& valueToWrite) = 0;
66 virtual datatype_t read() = 0;
67 virtual ~abstract_bitfield() = default;
68
69 constexpr bool affected(size_t byteOffset, size_t byteLength) const noexcept {
70 return (byteOffset * 8 < bitOffset + bitSize) && (bitOffset < (byteOffset + byteLength) * 8);
71 }
72
73 constexpr datatype_t mask() const noexcept { return ((1ULL << bitSize) - 1) << bitOffset; }
74
75 const size_t bitOffset;
76 const size_t bitSize;
77 const std::string name;
78 const std::string urid;
79};
80
86template <typename datatype_t> class bitfield_register : public sc_core::sc_object, public scc::resource_access_if {
87public:
99 bitfield_register(sc_core::sc_module_name name, size_t offset, datatype_t resetValue = 0, datatype_t writeMask = -1,
100 datatype_t readMask = -1)
101 : sc_core::sc_object{name}
102 , offset{offset}
103 , resetValue{resetValue}
104 , writeMask{writeMask}
105 , readMask{readMask} {}
106
110 char const* full_name() const override { return name(); };
114 size_t size() const noexcept override { return sizeof(datatype_t); }
115
116 void reset() override { storage = resetValue; }
117
118 bool write(const uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) override {
119 assert("Access out of range" && offset + length <= this->size());
120 auto valueToWrite{storage};
121 std::copy(data, data + length, reinterpret_cast<uint8_t*>(&valueToWrite) + offset);
122 for(auto&& bitfield : bitfields) {
123 if(bitfield.get().affected(offset, length)) {
124 auto mask = bitfield.get().mask();
125 auto bits = (valueToWrite & mask) >> bitfield.get().bitOffset;
126 bitfield.get().write(bits);
127 valueToWrite = (valueToWrite & ~mask) | ((bits << bitfield.get().bitOffset) & mask);
128 }
129 }
130 if(writeCallback)
131 writeCallback(*this, valueToWrite);
132 storage = (valueToWrite & writeMask) | (storage & ~writeMask);
133 return true;
134 }
135
136 bool read(uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) const override {
137 assert("Access out of range" && offset + length <= this->size());
138 auto result{storage};
139 result &= readMask;
140 for(auto&& bitfield : bitfields) {
141 if(bitfield.get().affected(offset, length)) {
142 auto bitfieldValue = bitfield.get().read();
143 auto mask = bitfield.get().mask();
144 result = (result & ~mask) | ((bitfieldValue << bitfield.get().bitOffset) & mask);
145 }
146 }
147 if(readCallback)
148 readCallback(*this, result);
149 auto begin = reinterpret_cast<const uint8_t*>(&result) + offset;
150 std::copy(begin, begin + length, data);
151 return true;
152 }
153
154 bool write_dbg(const uint8_t* data, std::size_t length, uint64_t offset = 0) override {
155 assert("Offset out of range" && offset == 0);
156 if(length != this->size())
157 return false;
158 std::copy(data, data + length, reinterpret_cast<uint8_t*>(&storage));
159 return true;
160 }
161
162 bool read_dbg(uint8_t* data, std::size_t length, uint64_t offset = 0) const override {
163 assert("Offset out of range" && offset == 0);
164 if(length != this->size())
165 return false;
166 auto storagePtr = reinterpret_cast<const uint8_t*>(&storage);
167 std::copy(storagePtr, storagePtr + length, data);
168 return true;
169 }
170
174 constexpr datatype_t get() const { return storage; }
178 void put(datatype_t value) { storage = value; }
179
180 void registerBitfield(abstract_bitfield<datatype_t>& bitfield) { bitfields.push_back(bitfield); }
181
185 constexpr operator datatype_t() const { return storage; }
190 storage = other;
191 return *this;
192 }
193
205 void setWriteCallback(std::function<void(bitfield_register<datatype_t>&, datatype_t& valueToWrite)> callback) {
206 writeCallback = std::move(callback);
207 }
208
215 void setReadCallback(std::function<void(const bitfield_register<datatype_t>&, datatype_t& result)> callback) {
216 readCallback = std::move(callback);
217 }
218
219 const size_t offset;
220
221protected:
222 const datatype_t resetValue;
223 const datatype_t writeMask;
224 const datatype_t readMask;
225 datatype_t storage;
226
227 std::function<void(bitfield_register<datatype_t>&, datatype_t&)> writeCallback;
228 std::function<void(const bitfield_register<datatype_t>&, datatype_t&)> readCallback;
229 std::vector<std::reference_wrapper<abstract_bitfield<datatype_t>>> bitfields;
230};
231
232template <typename datatype_t> class bitfield : public abstract_bitfield<datatype_t> {
233public:
234 enum Access { RW, ReadOnly };
235 using abstract_bitfield<datatype_t>::mask;
236 using abstract_bitfield<datatype_t>::bitOffset;
237
247 // constexpr //TODO: requires c++14
248 bitfield(bitfield_register<datatype_t>& reg, std::string name, size_t bitOffset, size_t bitSize, std::string urid, Access access = RW)
249 : reg{reg}
250 , abstract_bitfield<datatype_t>{std::move(name), bitOffset, bitSize, std::move(urid)}
251 , access{access} {
252 reg.registerBitfield(*this);
253 }
254 bitfield(const bitfield&) = delete;
255 bitfield& operator=(const bitfield&) = delete;
256
257 void write(datatype_t& valueToWrite) override {
258 if(writeCallback)
259 writeCallback(*this, valueToWrite);
260 if(access == ReadOnly)
261 valueToWrite = get();
262 }
263 datatype_t read() override {
264 if(readCallback)
265 return readCallback(*this);
266 else
267 return get();
268 }
269
273 constexpr datatype_t get() const { return (reg.get() & mask()) >> bitOffset; }
277 void put(datatype_t value) { reg.put((reg.get() & ~mask()) | ((value << bitOffset) & mask())); }
278
282 constexpr operator datatype_t() const { return get(); }
286 bitfield<datatype_t>& operator=(datatype_t other) {
287 put(other);
288 return *this;
289 }
290
302 void setWriteCallback(std::function<void(bitfield<datatype_t>&, datatype_t& valueToWrite)> callback) {
303 writeCallback = std::move(callback);
304 }
305
312 void setReadCallback(std::function<datatype_t(const bitfield<datatype_t>&)> callback) { readCallback = std::move(callback); }
313
315 Access access;
316
317protected:
318 std::function<void(bitfield<datatype_t>&, datatype_t&)> writeCallback;
319 std::function<datatype_t(const bitfield<datatype_t>&)> readCallback;
320};
321
330template <typename derived_t, bool use_URID = false> class tlm_target_bfs_register_base : public sc_core::sc_object, public scc::resetable {
331public:
332 tlm_target_bfs_register_base(sc_core::sc_module_name name)
333 : sc_core::sc_object{name} {}
334
335 template <unsigned buswidth> void registerResources(scc::tlm_target<buswidth>& target) {
336 for(auto&& reg : asDerived().registers) {
337 target.addResource(reg, reg.offset);
338 this->register_resource(&reg);
339 }
340 }
341
347 bitfield_register<uint32_t>& getRegister(const std::string& name) {
348 auto found = std::find_if(asDerived().registers.begin(), asDerived().registers.end(),
349 [name](const bitfield_register<uint32_t>& reg) { return name.compare(reg.basename()) == 0; });
350 if(found == asDerived().registers.end()) {
351 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Register " + name + " not found").c_str());
352 }
353 return *found;
354 }
355
363 bitfield<uint32_t>& getBitfieldByName(const std::string& regname, const std::string& name) {
364 auto found =
365 std::find_if(asDerived().bitfields.begin(), asDerived().bitfields.end(), [regname, name](const bitfield<uint32_t>& bf) {
366 return regname.compare(bf.reg.basename()) == 0 && name == bf.name;
367 });
368 if(found == asDerived().bitfields.end()) {
369 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Bitfield " + name + " in register " + regname + " not found").c_str());
370 }
371 return *found;
372 }
373
380 bitfield<uint32_t>& getBitfieldById(const std::string& urid) {
381 auto found = std::find_if(asDerived().bitfields.begin(), asDerived().bitfields.end(),
382 [urid](const bitfield<uint32_t>& bf) { return urid == bf.urid; });
383 if(found == asDerived().bitfields.end()) {
384 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Bitfield with urid " + urid + " not found").c_str());
385 }
386 return *found;
387 }
388
399 bitfield<uint32_t>& getBitfield(const std::string& regname, const std::string& name, const std::string& urid) {
400 if(use_URID) {
401 return getBitfieldById(urid);
402 } else {
403 bitfield<uint32_t>& result = getBitfieldByName(regname, name);
404 if(result.urid != urid) {
405 SC_REPORT_WARNING(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE,
406 ("URID of register is " + result.urid + " but " + urid + " was passed").c_str());
407 }
408 return result;
409 }
410 }
411
412private:
413 derived_t& asDerived() { return static_cast<derived_t&>(*this); }
414};
415
416} // namespace scc
417
429#define BITFIELD_ARRAY_ELEMENT(z, i, elem) \
430 BOOST_PP_COMMA_IF(i) { \
431 getRegister(BOOST_PP_TUPLE_ELEM(0, elem)), \
432 BOOST_PP_TUPLE_ELEM(1, elem) \
433 BOOST_PP_STRINGIZE(i), BOOST_PP_TUPLE_ELEM(2, elem) + i *BOOST_PP_TUPLE_ELEM(3, elem), BOOST_PP_TUPLE_ELEM(3, elem), \
434 BOOST_PP_TUPLE_ELEM(4, elem) BOOST_PP_STRINGIZE(i) BOOST_PP_TUPLE_ELEM(5, elem) \
435 }
436
453#define BITFIELD_ARRAY(regname, basename, offset, size, uridbase, count) \
454 BOOST_PP_REPEAT(count, BITFIELD_ARRAY_ELEMENT, (regname, basename, offset, size, uridbase, ))
455
463#define BITFIELD_ARRAY_POSTFIX(regname, basename, offset, size, uridbase, uridpostfix, count) \
464 BOOST_PP_REPEAT(count, BITFIELD_ARRAY_ELEMENT, (regname, basename, offset, size, uridbase, uridpostfix))
465
477#define REGISTER_ARRAY_ELEMENT(z, i, elem) \
478 BOOST_PP_COMMA_IF(i) { \
479 BOOST_PP_TUPLE_ELEM(0, elem) \
480 BOOST_PP_STRINGIZE(i), BOOST_PP_TUPLE_ELEM(1, elem) + i* BOOST_PP_TUPLE_ELEM(2, elem) \
481 }
482
497#define REGISTER_ARRAY(basename, offset, size, count) BOOST_PP_REPEAT(count, REGISTER_ARRAY_ELEMENT, (basename, offset, size))
498
499#endif // __SCC_TLM_TARGET_BFS_REGISTER_BASE_H__
Abstract baseclass for bitfield.
Register that can contain bitfields.
void setWriteCallback(std::function< void(bitfield_register< datatype_t > &, datatype_t &valueToWrite)> callback)
bool write_dbg(const uint8_t *data, std::size_t length, uint64_t offset=0) override
debug write to the resource
void reset() override
reset the resource
char const * full_name() const override
size_t size() const noexcept override
bool read_dbg(uint8_t *data, std::size_t length, uint64_t offset=0) const override
debug read the data from the resource
bitfield_register< datatype_t > & operator=(datatype_t other)
constexpr datatype_t get() const
bitfield_register(sc_core::sc_module_name name, size_t offset, datatype_t resetValue=0, datatype_t writeMask=-1, datatype_t readMask=-1)
void setReadCallback(std::function< void(const bitfield_register< datatype_t > &, datatype_t &result)> callback)
void put(datatype_t value)
void setReadCallback(std::function< datatype_t(const bitfield< datatype_t > &)> callback)
bitfield(bitfield_register< datatype_t > &reg, std::string name, size_t bitOffset, size_t bitSize, std::string urid, Access access=RW)
void setWriteCallback(std::function< void(bitfield< datatype_t > &, datatype_t &valueToWrite)> callback)
constexpr datatype_t get() const
bitfield< datatype_t > & operator=(datatype_t other)
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
bitfield_register< uint32_t > & getRegister(const std::string &name)
Search for a register by name.
bitfield< uint32_t > & getBitfieldById(const std::string &urid)
Search for a bitfield by urid.
bitfield< uint32_t > & getBitfieldByName(const std::string &regname, const std::string &name)
Search for a bitfield by name and register name.
bitfield< uint32_t > & getBitfield(const std::string &regname, const std::string &name, const std::string &urid)
Preferred way to get access to a bitfield.
a simple access-width based bus interface (no DMI support)
Definition tlm_target.h:44
void addResource(resource_access_if &rai, uint64_t base_addr)
add a resource to this target at a certain address within the socket address range
Definition tlm_target.h:80
SCC TLM utilities.