scc  2022.4.0
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  *******************************************************************************/
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 
50 namespace scc {
51 
57 template <typename datatype_t> class abstract_bitfield {
58 public:
59  constexpr 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 
86 template <typename datatype_t> class bitfield_register : public sc_core::sc_object, public scc::resource_access_if {
87 public:
99  constexpr 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  }
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 
217 protected:
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 
228 template <typename datatype_t> class bitfield : public abstract_bitfield<datatype_t> {
229 public:
230  enum Access { RW, ReadOnly };
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  }
308  void setReadCallback(std::function<datatype_t(const bitfield<datatype_t>&)> callback) { readCallback = std::move(callback); }
309 
311  Access access;
312 
313 protected:
314  std::function<void(bitfield<datatype_t>&, datatype_t&)> writeCallback;
315  std::function<datatype_t(const bitfield<datatype_t>&)> readCallback;
316 };
317 
326 template <typename derived_t, bool use_URID = false> class tlm_target_bfs_register_base : public sc_core::sc_object, public scc::resetable {
327 public:
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 
408 private:
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
bitfield_register< datatype_t > & operator=(datatype_t other)
bool read_dbg(uint8_t *data, std::size_t length, uint64_t offset=0) const override
debug read the data from the resource
constexpr bitfield_register(sc_core::sc_module_name name, size_t offset, datatype_t resetValue=0, datatype_t writeMask=-1, datatype_t readMask=-1)
constexpr datatype_t get() const
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)
bitfield< datatype_t > & operator=(datatype_t other)
constexpr datatype_t get() const
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 > & 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.
bitfield< uint32_t > & getBitfieldById(const std::string &urid)
Search for a bitfield by urid.
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 SystemC utilities.