scc 2025.09
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 constexpr size_t size() const noexcept override { return sizeof(datatype_t); }
111
112 void reset() override { storage = resetValue; }
113
114 bool write(const uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) override {
115 assert("Access out of range" && offset + length <= this->size());
116 auto valueToWrite{storage};
117 std::copy(data, data + length, reinterpret_cast<uint8_t*>(&valueToWrite) + offset);
118 for(auto&& bitfield : bitfields) {
119 if(bitfield.get().affected(offset, length)) {
120 auto mask = bitfield.get().mask();
121 auto bits = (valueToWrite & mask) >> bitfield.get().bitOffset;
122 bitfield.get().write(bits);
123 valueToWrite = (valueToWrite & ~mask) | ((bits << bitfield.get().bitOffset) & mask);
124 }
125 }
126 if(writeCallback)
127 writeCallback(*this, valueToWrite);
128 storage = (valueToWrite & writeMask) | (storage & ~writeMask);
129 return true;
130 }
131
132 bool read(uint8_t* data, std::size_t length, uint64_t offset, sc_core::sc_time& d) const override {
133 assert("Access out of range" && offset + length <= this->size());
134 auto result{storage};
135 result &= readMask;
136 for(auto&& bitfield : bitfields) {
137 if(bitfield.get().affected(offset, length)) {
138 auto bitfieldValue = bitfield.get().read();
139 auto mask = bitfield.get().mask();
140 result = (result & ~mask) | ((bitfieldValue << bitfield.get().bitOffset) & mask);
141 }
142 }
143 if(readCallback)
144 readCallback(*this, result);
145 auto begin = reinterpret_cast<const uint8_t*>(&result) + offset;
146 std::copy(begin, begin + length, data);
147 return true;
148 }
149
150 bool write_dbg(const uint8_t* data, std::size_t length, uint64_t offset = 0) override {
151 assert("Offset out of range" && offset == 0);
152 if(length != this->size())
153 return false;
154 std::copy(data, data + length, reinterpret_cast<uint8_t*>(&storage));
155 return true;
156 }
157
158 bool read_dbg(uint8_t* data, std::size_t length, uint64_t offset = 0) const override {
159 assert("Offset out of range" && offset == 0);
160 if(length != this->size())
161 return false;
162 auto storagePtr = reinterpret_cast<const uint8_t*>(&storage);
163 std::copy(storagePtr, storagePtr + length, data);
164 return true;
165 }
166
170 constexpr datatype_t get() const { return storage; }
174 void put(datatype_t value) { storage = value; }
175
176 void registerBitfield(abstract_bitfield<datatype_t>& bitfield) { bitfields.push_back(bitfield); }
177
181 constexpr operator datatype_t() const { return storage; }
186 storage = other;
187 return *this;
188 }
189
201 void setWriteCallback(std::function<void(bitfield_register<datatype_t>&, datatype_t& valueToWrite)> callback) {
202 writeCallback = std::move(callback);
203 }
204
211 void setReadCallback(std::function<void(const bitfield_register<datatype_t>&, datatype_t& result)> callback) {
212 readCallback = std::move(callback);
213 }
214
215 const size_t offset;
216
217protected:
218 const datatype_t resetValue;
219 const datatype_t writeMask;
220 const datatype_t readMask;
221 datatype_t storage;
222
223 std::function<void(bitfield_register<datatype_t>&, datatype_t&)> writeCallback;
224 std::function<void(const bitfield_register<datatype_t>&, datatype_t&)> readCallback;
225 std::vector<std::reference_wrapper<abstract_bitfield<datatype_t>>> bitfields;
226};
227
228template <typename datatype_t> class bitfield : public abstract_bitfield<datatype_t> {
229public:
230 enum Access { RW, ReadOnly };
231 using abstract_bitfield<datatype_t>::mask;
232 using abstract_bitfield<datatype_t>::bitOffset;
233
243 // constexpr //TODO: requires c++14
244 bitfield(bitfield_register<datatype_t>& reg, std::string name, size_t bitOffset, size_t bitSize, std::string urid, Access access = RW)
245 : reg{reg}
246 , abstract_bitfield<datatype_t>{std::move(name), bitOffset, bitSize, std::move(urid)}
247 , access{access} {
248 reg.registerBitfield(*this);
249 }
250 bitfield(const bitfield&) = delete;
251 bitfield& operator=(const bitfield&) = delete;
252
253 void write(datatype_t& valueToWrite) override {
254 if(writeCallback)
255 writeCallback(*this, valueToWrite);
256 if(access == ReadOnly)
257 valueToWrite = get();
258 }
259 datatype_t read() override {
260 if(readCallback)
261 return readCallback(*this);
262 else
263 return get();
264 }
265
269 constexpr datatype_t get() const { return (reg.get() & mask()) >> bitOffset; }
273 void put(datatype_t value) { reg.put((reg.get() & ~mask()) | ((value << bitOffset) & mask())); }
274
278 constexpr operator datatype_t() const { return get(); }
282 bitfield<datatype_t>& operator=(datatype_t other) {
283 put(other);
284 return *this;
285 }
286
298 void setWriteCallback(std::function<void(bitfield<datatype_t>&, datatype_t& valueToWrite)> callback) {
299 writeCallback = std::move(callback);
300 }
301
308 void setReadCallback(std::function<datatype_t(const bitfield<datatype_t>&)> callback) { readCallback = std::move(callback); }
309
311 Access access;
312
313protected:
314 std::function<void(bitfield<datatype_t>&, datatype_t&)> writeCallback;
315 std::function<datatype_t(const bitfield<datatype_t>&)> readCallback;
316};
317
326template <typename derived_t, bool use_URID = false> class tlm_target_bfs_register_base : public sc_core::sc_object, public scc::resetable {
327public:
328 tlm_target_bfs_register_base(sc_core::sc_module_name name)
329 : sc_core::sc_object{name} {}
330
331 template <unsigned buswidth> void registerResources(scc::tlm_target<buswidth>& target) {
332 for(auto&& reg : asDerived().registers) {
333 target.addResource(reg, reg.offset);
334 this->register_resource(&reg);
335 }
336 }
337
343 bitfield_register<uint32_t>& getRegister(const std::string& name) {
344 auto found = std::find_if(asDerived().registers.begin(), asDerived().registers.end(),
345 [name](const bitfield_register<uint32_t>& reg) { return name.compare(reg.basename()) == 0; });
346 if(found == asDerived().registers.end()) {
347 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Register " + name + " not found").c_str());
348 }
349 return *found;
350 }
351
359 bitfield<uint32_t>& getBitfieldByName(const std::string& regname, const std::string& name) {
360 auto found =
361 std::find_if(asDerived().bitfields.begin(), asDerived().bitfields.end(), [regname, name](const bitfield<uint32_t>& bf) {
362 return regname.compare(bf.reg.basename()) == 0 && name == bf.name;
363 });
364 if(found == asDerived().bitfields.end()) {
365 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Bitfield " + name + " in register " + regname + " not found").c_str());
366 }
367 return *found;
368 }
369
376 bitfield<uint32_t>& getBitfieldById(const std::string& urid) {
377 auto found = std::find_if(asDerived().bitfields.begin(), asDerived().bitfields.end(),
378 [urid](const bitfield<uint32_t>& bf) { return urid == bf.urid; });
379 if(found == asDerived().bitfields.end()) {
380 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, ("Bitfield with urid " + urid + " not found").c_str());
381 }
382 return *found;
383 }
384
395 bitfield<uint32_t>& getBitfield(const std::string& regname, const std::string& name, const std::string& urid) {
396 if(use_URID) {
397 return getBitfieldById(urid);
398 } else {
399 bitfield<uint32_t>& result = getBitfieldByName(regname, name);
400 if(result.urid != urid) {
401 SC_REPORT_WARNING(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE,
402 ("URID of register is " + result.urid + " but " + urid + " was passed").c_str());
403 }
404 return result;
405 }
406 }
407
408private:
409 derived_t& asDerived() { return static_cast<derived_t&>(*this); }
410};
411
412} // namespace scc
413
425#define BITFIELD_ARRAY_ELEMENT(z, i, elem) \
426 BOOST_PP_COMMA_IF(i) { \
427 getRegister(BOOST_PP_TUPLE_ELEM(0, elem)), \
428 BOOST_PP_TUPLE_ELEM(1, elem) \
429 BOOST_PP_STRINGIZE(i), BOOST_PP_TUPLE_ELEM(2, elem) + i *BOOST_PP_TUPLE_ELEM(3, elem), BOOST_PP_TUPLE_ELEM(3, elem), \
430 BOOST_PP_TUPLE_ELEM(4, elem) BOOST_PP_STRINGIZE(i) BOOST_PP_TUPLE_ELEM(5, elem) \
431 }
432
449#define BITFIELD_ARRAY(regname, basename, offset, size, uridbase, count) \
450 BOOST_PP_REPEAT(count, BITFIELD_ARRAY_ELEMENT, (regname, basename, offset, size, uridbase, ))
451
459#define BITFIELD_ARRAY_POSTFIX(regname, basename, offset, size, uridbase, uridpostfix, count) \
460 BOOST_PP_REPEAT(count, BITFIELD_ARRAY_ELEMENT, (regname, basename, offset, size, uridbase, uridpostfix))
461
473#define REGISTER_ARRAY_ELEMENT(z, i, elem) \
474 BOOST_PP_COMMA_IF(i) { \
475 BOOST_PP_TUPLE_ELEM(0, elem) \
476 BOOST_PP_STRINGIZE(i), BOOST_PP_TUPLE_ELEM(1, elem) + i* BOOST_PP_TUPLE_ELEM(2, elem) \
477 }
478
493#define REGISTER_ARRAY(basename, offset, size, count) BOOST_PP_REPEAT(count, REGISTER_ARRAY_ELEMENT, (basename, offset, size))
494
495#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
constexpr size_t size() const noexcept override
void reset() override
reset the resource
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.