24#ifndef __SCC_TLM_TARGET_BFS_REGISTER_BASE_H__
25#define __SCC_TLM_TARGET_BFS_REGISTER_BASE_H__
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>
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"
48#define ID_SCC_TLM_TARGET_BFS_REGISTER_BASE "scc: tlm target bitfield support register base"
57template <
typename datatype_t>
class abstract_bitfield {
59 abstract_bitfield(std::string name,
size_t bitOffset,
size_t bitSize, std::string urid)
60 : bitOffset{bitOffset}
62 , name{std::move(name)}
63 , urid{std::move(urid)} {}
65 virtual void write(datatype_t& valueToWrite) = 0;
66 virtual datatype_t read() = 0;
67 virtual ~abstract_bitfield() =
default;
69 constexpr bool affected(
size_t byteOffset,
size_t byteLength)
const noexcept {
70 return (byteOffset * 8 < bitOffset + bitSize) && (bitOffset < (byteOffset + byteLength) * 8);
73 constexpr datatype_t mask()
const noexcept {
return ((1ULL << bitSize) - 1) << bitOffset; }
75 const size_t bitOffset;
77 const std::string name;
78 const std::string urid;
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}
103 , resetValue{resetValue}
104 , writeMask{writeMask}
105 , readMask{readMask} {}
110 char const*
full_name()
const override {
return name(); };
114 size_t size() const noexcept
override {
return sizeof(datatype_t); }
116 void reset()
override { storage = resetValue; }
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);
131 writeCallback(*
this, valueToWrite);
132 storage = (valueToWrite & writeMask) | (storage & ~writeMask);
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};
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);
148 readCallback(*
this, result);
149 auto begin =
reinterpret_cast<const uint8_t*
>(&result) + offset;
150 std::copy(begin, begin + length, data);
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())
158 std::copy(data, data + length,
reinterpret_cast<uint8_t*
>(&storage));
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())
166 auto storagePtr =
reinterpret_cast<const uint8_t*
>(&storage);
167 std::copy(storagePtr, storagePtr + length, data);
174 constexpr datatype_t
get()
const {
return storage; }
178 void put(datatype_t value) { storage = value; }
185 constexpr operator datatype_t()
const {
return storage; }
206 writeCallback = std::move(callback);
216 readCallback = std::move(callback);
222 const datatype_t resetValue;
223 const datatype_t writeMask;
224 const datatype_t readMask;
229 std::vector<std::reference_wrapper<abstract_bitfield<datatype_t>>> bitfields;
232template <
typename datatype_t>
class bitfield :
public abstract_bitfield<datatype_t> {
234 enum Access { RW, ReadOnly };
235 using abstract_bitfield<datatype_t>::mask;
236 using abstract_bitfield<datatype_t>::bitOffset;
250 , abstract_bitfield<datatype_t>{std::move(name), bitOffset, bitSize, std::move(urid)}
252 reg.registerBitfield(*
this);
257 void write(datatype_t& valueToWrite)
override {
259 writeCallback(*
this, valueToWrite);
260 if(access == ReadOnly)
261 valueToWrite =
get();
263 datatype_t read()
override {
265 return readCallback(*
this);
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())); }
282 constexpr operator datatype_t()
const {
return get(); }
303 writeCallback = std::move(callback);
330template <
typename derived_t,
bool use_URID = false>
class tlm_target_bfs_register_base :
public sc_core::sc_object,
public scc::resetable {
332 tlm_target_bfs_register_base(sc_core::sc_module_name name)
333 : sc_core::sc_object{name} {}
336 for(
auto&& reg : asDerived().registers) {
348 auto found = std::find_if(asDerived().registers.begin(), asDerived().registers.end(),
350 if(found == asDerived().registers.end()) {
351 SC_REPORT_FATAL(ID_SCC_TLM_TARGET_BFS_REGISTER_BASE, (
"Register " + name +
" not found").c_str());
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;
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());
381 auto found = std::find_if(asDerived().bitfields.begin(), asDerived().bitfields.end(),
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());
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());
413 derived_t& asDerived() {
return static_cast<derived_t&
>(*this); }
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) \
453#define BITFIELD_ARRAY(regname, basename, offset, size, uridbase, count) \
454 BOOST_PP_REPEAT(count, BITFIELD_ARRAY_ELEMENT, (regname, basename, offset, size, uridbase, ))
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))
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) \
497#define REGISTER_ARRAY(basename, offset, size, count) BOOST_PP_REPEAT(count, REGISTER_ARRAY_ELEMENT, (basename, offset, size))
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
void put(datatype_t value)
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 > ®, 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
void register_resource(resource_access_if *res)
register a resource with this reset domain
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 ®name, const std::string &name)
Search for a bitfield by name and register name.
bitfield< uint32_t > & getBitfield(const std::string ®name, 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)
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