ChimeraTK-DeviceAccess  03.18.00
NumericAddressedRegisterCatalogue.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 #include "Exception.h"
5 #include "MapFileParser.h"
6 #include "NumericAddress.h"
7 #include "predicates.h"
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <stdexcept>
12 #include <utility>
13 
14 namespace ChimeraTK {
15 
16  /********************************************************************************************************************/
17 
19  uint64_t address_, uint32_t nBytes_, uint64_t bar_, uint32_t width_, int32_t nFractionalBits_, bool signedFlag_,
20  Access dataAccess_, Type dataType_, std::vector<size_t> interruptId_)
21  : pathName(pathName_), nElements(nElements_), elementPitchBits(nElements_ > 0 ? nBytes_ / nElements_ * 8 : 0),
22  bar(bar_), address(address_), registerAccess(dataAccess_), interruptId(std::move(interruptId_)),
23  channels({{0, dataType_, width_, nFractionalBits_, signedFlag_}}) {
24  assert(channels.size() == 1);
25 
26  // make sure . and / is treated as similar as possible
27  pathName.setAltSeparator(".");
28 
29  // consistency checks
30  if(nBytes_ > 0 && nElements_ > 0) {
31  if(nBytes_ % nElements_ != 0) {
32  // nBytes_ must be divisible by nElements_
33  throw logic_error("Number of bytes is not a multiple of number of elements for register " + pathName +
34  ". Check your map file!");
35  }
36  }
37 
38  computeDataDescriptor();
39  }
40 
41  /********************************************************************************************************************/
42 
44  uint64_t address_, uint32_t nElements_, uint32_t elementPitchBits_, std::vector<ChannelInfo> channelInfo_,
45  Access dataAccess_, std::vector<size_t> interruptId_)
46  : pathName(pathName_), nElements(nElements_), elementPitchBits(elementPitchBits_), bar(bar_), address(address_),
47  registerAccess(dataAccess_), interruptId(std::move(interruptId_)), channels(std::move(channelInfo_)) {
48  assert(!channels.empty());
49 
50  // make sure . and / is treated as similar as possible
52 
53  computeDataDescriptor();
54  }
55 
56  /********************************************************************************************************************/
57 
58  void NumericAddressedRegisterInfo::computeDataDescriptor() {
59  // Determine DataDescriptor. If there are multiple channels, use the "biggest" data type.
60  Type dataType = Type::VOID;
61  uint32_t width = 0;
62  int32_t nFractionalBits = 0;
63  bool signedFlag = false;
64  for(auto& c : channels) {
65  if(int(c.dataType) > int(dataType)) dataType = c.dataType;
66  if(c.width + c.nFractionalBits + c.signedFlag > width + nFractionalBits + signedFlag) {
67  width = c.width;
68  nFractionalBits = c.nFractionalBits;
69  signedFlag = c.signedFlag;
70  }
71  }
72 
73  // set raw data type
74  DataType rawDataInfo{DataType::none};
75  if(channels.size() == 1) {
76  if(elementPitchBits == 0) {
77  rawDataInfo = DataType::Void;
78  }
79  else if(elementPitchBits == 8) {
80  rawDataInfo = DataType::int8;
81  }
82  else if(elementPitchBits == 16) {
83  rawDataInfo = DataType::int16;
84  }
85  else if(elementPitchBits == 32) {
86  rawDataInfo = DataType::int32;
87  }
88  else if(elementPitchBits == 64) {
89  rawDataInfo = DataType::int64;
90  }
91  else {
92  if(dataType != Type::ASCII) {
94  "Unsupported raw size: " + std::to_string(elementPitchBits) + " bits in register " + pathName);
95  }
96  }
97  }
98 
99  // set "cooked" data type
100  if(dataType == Type::IEEE754) {
101  if(width == 32) {
102  // Largest possible number +- 3e38, smallest possible number 1e-45
103  // However, the actual precision is only 23+1 bit, which is < 1e9 relevant
104  // digits. Hence, we don't have to add the 3e38 and the 1e45, but just add
105  // the leading 0. comma and sign to the largest 45 digits
106  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::numeric, // fundamentalType
107  false, // isIntegral
108  true, // isSigned
109  3 + 45, // nDigits
110  45, // nFractionalDigits
111  rawDataInfo); // we have integer in the transport layer, or none if multiplexed
112  }
113  else if(width == 64) {
114  // smallest possible 5e-324, largest 2e308
115  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::numeric, // fundamentalType
116  false, // isIntegral
117  true, // isSigned
118  3 + 325, // nDigits
119  325, // nFractionalDigits
120  rawDataInfo);
121  }
122  else {
123  throw logic_error("Wrong data width for data type IEEE754 for register " + pathName + ". Check your map file!");
124  }
125  }
126  else if(dataType == Type::FIXED_POINT) {
127  if(width > 1) { // numeric type
128 
129  if(nFractionalBits > 0) {
130  auto nDigits = static_cast<size_t>(
131  std::ceil(std::log10(std::pow(2, width))) + (signedFlag ? 1 : 0) + (nFractionalBits != 0 ? 1 : 0));
132  size_t nFractionalDigits = std::ceil(std::log10(std::pow(2, nFractionalBits)));
133 
134  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::numeric, // fundamentalType
135  false, // isIntegral
136  signedFlag, // isSigned
137  nDigits, nFractionalDigits, rawDataInfo);
138  }
139  else {
140  auto nDigits =
141  static_cast<size_t>(std::ceil(std::log10(std::pow(2, width + nFractionalBits))) + (signedFlag ? 1 : 0));
142 
143  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::numeric, // fundamentalType
144  true, // isIntegral
145  signedFlag, // isSigned
146  nDigits, 0, rawDataInfo);
147  }
148  }
149  else if(width == 1) { // boolean
150  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::boolean, true, false, 1, 0, rawDataInfo);
151  }
152  else { // width == 0 -> nodata
153  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::nodata, false, false, 0, 0, rawDataInfo);
154  }
155  }
156  else if(dataType == Type::ASCII) {
157  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::string, false, false, 0, 0, rawDataInfo);
158  }
159  else if(dataType == Type::VOID) {
160  dataDescriptor = DataDescriptor(DataDescriptor::FundamentalType::nodata, false, false, 0, 0, rawDataInfo);
161  }
162  }
163 
164  /********************************************************************************************************************/
165 
167  return (address == rhs.address) && (bar == rhs.bar) && (nElements == rhs.nElements) && (channels == rhs.channels) &&
168  (pathName == rhs.pathName) && (elementPitchBits == rhs.elementPitchBits) &&
170  (interruptId == rhs.interruptId);
171  }
172 
173  /********************************************************************************************************************/
174 
176  return !operator==(rhs);
177  }
178 
179  /********************************************************************************************************************/
180 
182  return interruptId;
183  }
184 
185  /********************************************************************************************************************/
186 
188  return bitOffset == rhs.bitOffset && dataType == rhs.dataType && width == rhs.width &&
190  }
191 
192  /********************************************************************************************************************/
193 
195  if(width > 16) return DataType::int32;
196  if(width > 8) return DataType::int16;
197  return DataType::int8;
198  }
199 
200  /********************************************************************************************************************/
201 
203  return !operator==(rhs);
204  }
205 
206  /********************************************************************************************************************/
207  /********************************************************************************************************************/
208 
210  const RegisterPath& registerPathName) const {
211  auto path = registerPathName;
212  path.setAltSeparator(".");
213 
214  if(path.startsWith(numeric_address::BAR())) {
215  // special treatment for numeric addresses
216  auto components = path.getComponents();
217  if(components.size() != 3) {
218  throw ChimeraTK::logic_error("Illegal numeric address: '" + (path) + "'");
219  }
220  auto bar = std::stoi(components[1]);
221  size_t pos = components[2].find_first_of('*');
222  auto address = std::stoi(components[2].substr(0, pos));
223  size_t nBytes;
224  if(pos != std::string::npos) {
225  nBytes = std::stoi(components[2].substr(pos + 1));
226  }
227  else {
228  nBytes = sizeof(int32_t);
229  }
230  auto nElements = nBytes / sizeof(int32_t);
231  if(nBytes == 0 || nBytes % sizeof(int32_t) != 0) {
232  throw ChimeraTK::logic_error("Illegal numeric address: '" + (path) + "'");
233  }
234  return NumericAddressedRegisterInfo(path, nElements, address, nBytes, bar);
235  }
236  if(path.startsWith("!")) {
237  auto canonicalInterrupt = _canonicalInterrupts.find(path);
238  if(canonicalInterrupt == _canonicalInterrupts.end()) {
239  throw ChimeraTK::logic_error("Illegal canonical interrupt path: '" + (path) + "'");
240  }
241  return NumericAddressedRegisterInfo(path, 0, 0, 0, 0, 0, 0, false,
243  canonicalInterrupt->second);
244  }
246  }
247 
248  /********************************************************************************************************************/
249 
250  [[nodiscard]] bool NumericAddressedRegisterCatalogue::hasRegister(const RegisterPath& registerPathName) const {
251  if(registerPathName.startsWith(numeric_address::BAR())) {
253  return true;
254  }
255  if(_canonicalInterrupts.find(registerPathName) != _canonicalInterrupts.end()) {
256  return true;
257  }
258  return BackendRegisterCatalogue::hasRegister(registerPathName);
259  }
260 
261  /********************************************************************************************************************/
262 
263  const std::set<std::vector<size_t>>& NumericAddressedRegisterCatalogue::getListOfInterrupts() const {
264  return _listOfInterrupts;
265  }
266 
267  /********************************************************************************************************************/
268 
271  _listOfInterrupts.insert(registerInfo.interruptId);
272  RegisterPath canonicalName = "!" + std::to_string(registerInfo.interruptId.front());
273  std::vector<size_t> canonicalID = {registerInfo.interruptId.front()};
274  _canonicalInterrupts[canonicalName] = canonicalID;
275  for(auto subId = ++registerInfo.interruptId.begin(); subId != registerInfo.interruptId.end(); ++subId) {
276  canonicalName += ":" + std::to_string(*subId);
277  canonicalID.push_back(*subId);
278  _canonicalInterrupts[canonicalName] = canonicalID;
279  }
280  }
282  }
283 
284  /********************************************************************************************************************/
285 
286  std::unique_ptr<BackendRegisterCatalogueBase> NumericAddressedRegisterCatalogue::clone() const {
287  std::unique_ptr<BackendRegisterCatalogueBase> c = std::make_unique<NumericAddressedRegisterCatalogue>();
288  auto* casted_c = dynamic_cast<NumericAddressedRegisterCatalogue*>(c.get());
289  fillFromThis(casted_c);
290  casted_c->_listOfInterrupts = _listOfInterrupts;
291  casted_c->_canonicalInterrupts = _canonicalInterrupts;
292  return c;
293  }
294 
295  /********************************************************************************************************************/
296 
297 } // namespace ChimeraTK
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::operator!=
bool operator!=(const ChannelInfo &rhs) const
Definition: NumericAddressedRegisterCatalogue.cc:202
ChimeraTK::NumericAddressedRegisterInfo::interruptId
std::vector< size_t > interruptId
Definition: NumericAddressedRegisterCatalogue.h:117
ChimeraTK::NumericAddressedRegisterInfo::address
uint64_t address
Lower part of the address relative to BAR, in bytes.
Definition: NumericAddressedRegisterCatalogue.h:114
ChimeraTK::NumericAddressedRegisterCatalogue::addRegister
void addRegister(const NumericAddressedRegisterInfo &registerInfo)
Definition: NumericAddressedRegisterCatalogue.cc:269
ChimeraTK::NumericAddressedRegisterInfo::Type::ASCII
@ ASCII
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::nFractionalBits
int32_t nFractionalBits
Number of fractional bits.
Definition: NumericAddressedRegisterCatalogue.h:46
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::width
uint32_t width
Number of significant bits in the register.
Definition: NumericAddressedRegisterCatalogue.h:45
ChimeraTK::NumericAddressedRegisterCatalogue::getBackendRegister
NumericAddressedRegisterInfo getBackendRegister(const RegisterPath &registerPathName) const override
Note: Override this function if backend has "hidden" registers which are not added to the map and hen...
Definition: NumericAddressedRegisterCatalogue.cc:209
MapFileParser.h
ChimeraTK::NumericAddressedRegisterInfo::nElements
uint32_t nElements
Number of elements in register.
Definition: NumericAddressedRegisterCatalogue.h:110
ChimeraTK::NumericAddressedRegisterInfo::operator==
bool operator==(const ChimeraTK::NumericAddressedRegisterInfo &rhs) const
Definition: NumericAddressedRegisterCatalogue.cc:166
ChimeraTK::NumericAddressedRegisterInfo
Definition: NumericAddressedRegisterCatalogue.h:15
ChimeraTK::DataType::int32
@ int32
Signed 32 bit integer.
Definition: SupportedUserTypes.h:611
ChimeraTK::DataDescriptor::FundamentalType::nodata
@ nodata
ChimeraTK::NumericAddressedRegisterInfo::Type::VOID
@ VOID
ChimeraTK::NumericAddressedRegisterInfo::Type::IEEE754
@ IEEE754
ChimeraTK::NumericAddressedRegisterInfo::Access::INTERRUPT
@ INTERRUPT
ChimeraTK::RegisterPath::setAltSeparator
void setAltSeparator(const std::string &altSeparator)
set alternative separator.
Definition: RegisterPath.h:37
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::dataType
Type dataType
Data type (fixpoint, floating point)
Definition: NumericAddressedRegisterCatalogue.h:44
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::signedFlag
bool signedFlag
Signed/Unsigned flag.
Definition: NumericAddressedRegisterCatalogue.h:47
ChimeraTK::NumericAddressedRegisterCatalogue::getListOfInterrupts
const std::set< std::vector< size_t > > & getListOfInterrupts() const
Definition: NumericAddressedRegisterCatalogue.cc:263
ChimeraTK::DataDescriptor::FundamentalType::boolean
@ boolean
ChimeraTK::DataType::Void
@ Void
Void.
Definition: SupportedUserTypes.h:619
ChimeraTK::NumericAddressedRegisterInfo::pathName
RegisterPath pathName
Definition: NumericAddressedRegisterCatalogue.h:108
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::bitOffset
uint32_t bitOffset
Offset in bits w.r.t.
Definition: NumericAddressedRegisterCatalogue.h:43
ChimeraTK::NumericAddressedRegisterInfo::bar
uint64_t bar
Upper part of the address (name originally from PCIe, meaning now generalised)
Definition: NumericAddressedRegisterCatalogue.h:113
ChimeraTK::BackendRegisterInfoBase::getNumberOfDimensions
unsigned int getNumberOfDimensions() const
Return number of dimensions of this register.
Definition: BackendRegisterInfoBase.h:58
ChimeraTK::NumericAddressedRegisterCatalogue::clone
std::unique_ptr< BackendRegisterCatalogueBase > clone() const override
Create deep copy of the catalogue.
Definition: NumericAddressedRegisterCatalogue.cc:286
ChimeraTK::DataType::none
@ none
The data type/concept does not exist, e.g. there is no raw transfer (do not confuse with Void)
Definition: SupportedUserTypes.h:606
ChimeraTK::RegisterPath::startsWith
bool startsWith(const RegisterPath &compare) const
check if the register path starts with the given path
Definition: RegisterPath.h:141
ChimeraTK::numeric_address::BAR
RegisterPath BAR()
The numeric_address::BAR() function can be used to directly access registers by numeric addresses,...
Definition: NumericAddress.cc:7
ChimeraTK::NumericAddressedRegisterInfo::Type::FIXED_POINT
@ FIXED_POINT
ChimeraTK::BackendRegisterCatalogue::addRegister
void addRegister(const BackendRegisterInfo &registerInfo)
Add register information to the catalogue.
Definition: BackendRegisterCatalogue.h:342
ChimeraTK::NumericAddressedRegisterInfo::dataDescriptor
DataDescriptor dataDescriptor
Definition: NumericAddressedRegisterCatalogue.h:122
NumericAddress.h
ChimeraTK::DataDescriptor::FundamentalType::numeric
@ numeric
ChimeraTK::DataType
A class to describe which of the supported data types is used.
Definition: SupportedUserTypes.h:599
ChimeraTK::DataType::int64
@ int64
Signed 64 bit integer.
Definition: SupportedUserTypes.h:613
ChimeraTK::NumericAddressedRegisterInfo::channels
std::vector< ChannelInfo > channels
Define per-channel information (bit interpretation etc.), 1D/scalars have exactly one entry.
Definition: NumericAddressedRegisterCatalogue.h:120
ChimeraTK::NumericAddressedRegisterInfo::Type
Type
Enum descibing the data interpretation:
Definition: NumericAddressedRegisterCatalogue.h:36
ChimeraTK::NumericAddressedRegisterInfo::elementPitchBits
uint32_t elementPitchBits
Distance in bits (!) between two elements (of the same channel)
Definition: NumericAddressedRegisterCatalogue.h:111
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo
Per-channel information.
Definition: NumericAddressedRegisterCatalogue.h:42
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::operator==
bool operator==(const ChannelInfo &rhs) const
Definition: NumericAddressedRegisterCatalogue.cc:187
ChimeraTK::NumericAddressedRegisterInfo::Access
Access
Enum describing the access mode of the register:
Definition: NumericAddressedRegisterCatalogue.h:24
ChimeraTK::NumericAddressedRegisterInfo::getQualifiedAsyncId
std::vector< size_t > getQualifiedAsyncId() const override
Return the fully qualified async::SubDomain ID.
Definition: NumericAddressedRegisterCatalogue.cc:181
ChimeraTK::DataType::int8
@ int8
Signed 8 bit integer.
Definition: SupportedUserTypes.h:607
ChimeraTK::RegisterPath
Class to store a register path name.
Definition: RegisterPath.h:16
ChimeraTK::NumericAddressedRegisterInfo::NumericAddressedRegisterInfo
NumericAddressedRegisterInfo(RegisterPath const &pathName_={}, uint32_t nElements_=0, uint64_t address_=0, uint32_t nBytes_=0, uint64_t bar_=0, uint32_t width_=32, int32_t nFractionalBits_=0, bool signedFlag_=true, Access dataAccess_=Access::READ_WRITE, Type dataType_=Type::FIXED_POINT, std::vector< size_t > interruptId_={})
Constructor to set all data members for scalar/1D registers.
Definition: NumericAddressedRegisterCatalogue.cc:18
ChimeraTK::NumericAddressedRegisterCatalogue
Definition: NumericAddressedRegisterCatalogue.h:136
ChimeraTK::NumericAddressedRegisterInfo::registerAccess
Access registerAccess
Data access direction: Read, write, read and write or interrupt.
Definition: NumericAddressedRegisterCatalogue.h:116
ChimeraTK::BackendRegisterCatalogue::hasRegister
bool hasRegister(const RegisterPath &registerPathName) const override
Check if register with the given path name exists.
Definition: BackendRegisterCatalogue.h:274
ChimeraTK::BackendRegisterCatalogue::getBackendRegister
virtual BackendRegisterInfo getBackendRegister(const RegisterPath &registerPathName) const
Note: Override this function if backend has "hidden" registers which are not added to the map and hen...
Definition: BackendRegisterCatalogue.h:261
ChimeraTK::NumericAddressedRegisterCatalogue::hasRegister
bool hasRegister(const RegisterPath &registerPathName) const override
Check if register with the given path name exists.
Definition: NumericAddressedRegisterCatalogue.cc:250
Exception.h
ChimeraTK::NumericAddressedRegisterInfo::operator!=
bool operator!=(const ChimeraTK::NumericAddressedRegisterInfo &rhs) const
Definition: NumericAddressedRegisterCatalogue.cc:175
ChimeraTK::DataType::int16
@ int16
Signed 16 bit integer.
Definition: SupportedUserTypes.h:609
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::to_string
std::string to_string(Boolean &value)
Definition: SupportedUserTypes.h:59
predicates.h
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51
ChimeraTK::NumericAddressedRegisterInfo::ChannelInfo::getRawType
DataType getRawType() const
Return raw type matching the given width.
Definition: NumericAddressedRegisterCatalogue.cc:194
ChimeraTK::DataDescriptor::FundamentalType::string
@ string