8#include <boost/algorithm/string.hpp>
15namespace ChimeraTK::detail {
19 TraditionalMapFileParser::TraditionalMapFileParser(std::string fileName) : _fileName(
std::move(fileName)) {}
23 std::pair<NumericAddressedRegisterCatalogue, MetadataCatalogue> TraditionalMapFileParser::parse(
24 std::ifstream& stream) {
26 while(std::getline(stream, line)) {
30 line.erase(line.begin(), std::find_if(line.begin(), line.end(), [](
int c) { return !isspace(c); }));
33 auto pos = line.find(
'#');
34 if(pos != std::string::npos) {
35 line.erase(pos, std::string::npos);
50 _parsedLines.push_back(parseLine(line));
55 for(
const auto& pl : _parsedLines) {
56 _parsedLinesMap.emplace(pl.pathName, pl);
60 for(
const auto& pl : _parsedLines) {
61 if(isScalarOr1D(pl.pathName)) {
62 auto registerInfo = NumericAddressedRegisterInfo(pl.pathName, pl.nElements, pl.address, pl.nBytes, pl.bar,
63 pl.width, pl.nFractionalBits, pl.signedFlag, pl.registerAccess, pl.type, pl.interruptID);
64 _pmap.addRegister(registerInfo);
66 else if(is2D(pl.pathName)) {
69 else if(is2DNewStyle(pl.pathName)) {
74 return {std::move(_pmap), std::move(_metadataCatalogue)};
79 std::pair<RegisterPath, std::string> TraditionalMapFileParser::splitStringAtLastDot(RegisterPath moduleDotName) {
80 moduleDotName.setAltSeparator(
".");
81 auto regname = moduleDotName.getComponents().back();
83 return {moduleDotName, regname};
88 std::pair<NumericAddressedRegisterInfo::Type, int> TraditionalMapFileParser::getTypeAndNFractionalBits(
89 const std::string& bitInterpretation,
unsigned int width) {
90 if(width == 0)
return {NumericAddressedRegisterInfo::Type::VOID, 0};
91 if(bitInterpretation ==
"IEEE754")
return {NumericAddressedRegisterInfo::Type::IEEE754, 0};
92 if(bitInterpretation ==
"ASCII")
return {NumericAddressedRegisterInfo::Type::ASCII, 0};
96 int nBits = std::stoi(bitInterpretation,
nullptr,
98 return {NumericAddressedRegisterInfo::Type::FIXED_POINT, nBits};
100 catch(std::exception& e) {
102 bitInterpretation +
"', caught exception: " + e.what());
108 std::vector<size_t> TraditionalMapFileParser::getInterruptId(std::string accessTypeStr) {
109 std::string strToFind(
"INTERRUPT");
110 auto pos = accessTypeStr.find(strToFind);
111 if(pos == std::string::npos)
return {};
112 std::vector<size_t> retVal;
114 accessTypeStr.erase(pos, strToFind.length());
118 delimiterPos = accessTypeStr.find(
':');
119 std::string interruptStr = accessTypeStr.substr(0, delimiterPos);
120 size_t interruptNumber = 0;
122 interruptNumber = std::stoul(interruptStr,
nullptr, 0);
124 catch(std::exception& e) {
126 std::string(
"Map file error in accessString: wrong argument in interrupt controller number. Argument: '") +
127 interruptStr +
"', caught exception: " + e.what());
129 retVal.push_back(interruptNumber);
132 if(delimiterPos != std::string::npos) {
133 accessTypeStr = accessTypeStr.substr(delimiterPos + 1);
135 }
while(delimiterPos != std::string::npos);
142 void TraditionalMapFileParser::checkFileConsitencyAndThrowIfError(
143 NumericAddressedRegisterInfo::Access registerAccessMode, NumericAddressedRegisterInfo::Type registerType,
144 uint32_t nElements, uint64_t address, uint32_t nBytes, uint64_t bar, uint32_t width, int32_t nFractionalBits,
148 if(registerType == NumericAddressedRegisterInfo::Type::VOID &&
149 registerAccessMode == NumericAddressedRegisterInfo::Access::READ_ONLY) {
150 throw ChimeraTK::logic_error(std::string(
"Map file error. Register Type is VOID and access mode is READ only. "));
154 if(registerType == NumericAddressedRegisterInfo::Type::VOID &&
155 registerAccessMode == NumericAddressedRegisterInfo::Access::INTERRUPT) {
156 if(width || nElements || address || nBytes || bar || nFractionalBits || signedFlag) {
158 std::string(
"Map file error. Register Type is VOID (width field set to 0). All other fields must be '0'."));
165 void TraditionalMapFileParser::parseMetaData(std::string line) {
166 std::string metadata_name, metadata_value;
169 line.erase(line.begin(), line.begin() + 1);
172 line.erase(line.begin(), std::find_if(line.begin(), line.end(), [](
int c) { return !isspace(c); }));
174 std::istringstream is;
181 line.erase(line.begin(), line.begin() +
static_cast<std::string::difference_type
>(metadata_name.length()));
183 line.erase(std::remove_if(line.begin(), line.end(), [](
unsigned char x) { return std::isspace(x); }),
185 metadata_value = line;
186 _metadataCatalogue.addMetadata(metadata_name, metadata_value);
192 TraditionalMapFileParser::ParsedLine TraditionalMapFileParser::parseLine(
const std::string& line) {
195 std::istringstream is;
202 pl.pathName.setAltSeparator(
".");
204 is >> std::setbase(0) >> pl.nElements >> std::setbase(0) >> pl.address >> std::setbase(0) >> pl.nBytes;
211 is >> std::setbase(0) >> pl.bar;
215 is >> std::setbase(0) >> pl.width;
216 if((pl.nElements > 0) && (pl.width > pl.nBytes / pl.nElements * 8)) {
224 std::string bitInterpretation;
225 is >> bitInterpretation;
228 std::tie(pl.type, pl.nFractionalBits) = getTypeAndNFractionalBits(bitInterpretation, pl.width);
229 if(pl.nFractionalBits > 1023 || pl.nFractionalBits < -1024) {
238 is >> std::setbase(0) >> pl.signedFlag;
243 std::string accessString;
247 std::transform(accessString.begin(), accessString.end(), accessString.begin(),
248 [](
unsigned char c) { return std::toupper(c); });
251 auto interruptId = getInterruptId(accessString);
253 if(!interruptId.empty()) {
254 pl.registerAccess = NumericAddressedRegisterInfo::Access::INTERRUPT;
255 pl.interruptID = interruptId;
257 else if(accessString ==
"RO") {
258 pl.registerAccess = NumericAddressedRegisterInfo::Access::READ_ONLY;
260 else if(accessString ==
"RW") {
261 pl.registerAccess = NumericAddressedRegisterInfo::Access::READ_WRITE;
263 else if(accessString ==
"WO") {
264 pl.registerAccess = NumericAddressedRegisterInfo::Access::WRITE_ONLY;
273 checkFileConsitencyAndThrowIfError(pl.registerAccess, pl.type, pl.nElements, pl.address, pl.nBytes, pl.bar,
274 pl.width, pl.nFractionalBits, pl.signedFlag);
281 bool TraditionalMapFileParser::isScalarOr1D(
const RegisterPath& pathName) {
282 auto [module, name] = splitStringAtLastDot(pathName);
283 return !boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX) &&
284 !boost::algorithm::starts_with(name, SEQUENCE_PREFIX) &&
285 !boost::algorithm::starts_with(name, MEM_MULTIPLEXED_PREFIX) && !is2DNewStyle(module);
290 bool TraditionalMapFileParser::is2D(
const RegisterPath& pathName) {
291 auto [module, name] = splitStringAtLastDot(pathName);
292 return boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX);
297 bool TraditionalMapFileParser::is2DNewStyle(RegisterPath pathName) {
299 pathName.setAltSeparator(
".");
300 auto components = pathName.getComponents();
301 if(components.size() != 2)
return false;
302 return boost::algorithm::starts_with(components[1], MEM_MULTIPLEXED_PREFIX);
307 RegisterPath TraditionalMapFileParser::makeSequenceName(
const RegisterPath& pathName,
size_t index) {
308 auto [module, name] = splitStringAtLastDot(pathName);
309 assert(boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX));
310 name = name.substr(strlen(MULTIPLEXED_SEQUENCE_PREFIX));
312 r.setAltSeparator(
".");
318 RegisterPath TraditionalMapFileParser::make2DName(
const RegisterPath& pathName,
const std::string& prefix) {
319 auto [module, name] = splitStringAtLastDot(pathName);
320 assert(boost::algorithm::starts_with(name, prefix));
321 name = name.substr(prefix.size());
322 auto r = RegisterPath(module) / name;
323 r.setAltSeparator(
".");
329 void TraditionalMapFileParser::handle2DNewStyle(
const ParsedLine& pl) {
333 std::list<ParsedLine> channelLines;
334 for(
auto& [key, value] : _parsedLinesMap) {
335 if(key.startsWith(pl.pathName) and pl.pathName.length() < key.length()) {
337 if(value.address < pl.address) {
339 "Start address of channel smaller than 2D register start address ('" + pl.pathName +
"').");
341 channelLines.push_back(value);
345 channelLines.sort([](
auto& a,
auto& b) {
return a.address < b.address; });
346 make2DRegisterInfos(pl, channelLines, MEM_MULTIPLEXED_PREFIX);
349 void TraditionalMapFileParser::make2DRegisterInfos(
350 const ParsedLine& pl, std::list<ParsedLine>& channelLines,
const std::string& prefix) {
351 if(channelLines.empty()) {
354 std::vector<NumericAddressedRegisterInfo::ChannelInfo> channels;
355 size_t bytesPerBlock = 0;
357 for(
auto& channel : channelLines) {
358 channels.emplace_back(NumericAddressedRegisterInfo::ChannelInfo{uint32_t(channel.address - pl.address) * 8,
359 channel.type, channel.width, channel.nFractionalBits, channel.signedFlag});
360 bytesPerBlock += channel.nBytes;
362 if(channel.nBytes != 1 && channel.nBytes != 2 && channel.nBytes != 4 && channel.nBytes != 8) {
367 assert(bytesPerBlock > 0);
370 for(
size_t i = 0; i < channels.size() - 1; ++i) {
371 auto actualWidth = channels[i + 1].bitOffset - channels[i].bitOffset;
372 if(channels[i].width > actualWidth) {
373 channels[i].width = actualWidth;
378 auto actualWidth = bytesPerBlock * 8 - channels.back().bitOffset;
379 if(channels.back().width > actualWidth) {
380 channels.back().width = actualWidth;
385 auto nBlocks =
static_cast<uint32_t
>(std::floor(pl.nBytes / bytesPerBlock));
386 auto name2D = make2DName(pl.pathName, prefix);
387 auto registerInfo = NumericAddressedRegisterInfo(
388 name2D, pl.bar, pl.address, nBlocks, bytesPerBlock * 8, channels, pl.registerAccess, pl.interruptID);
389 _pmap.addRegister(registerInfo);
392 if(!pl.nBytes || !pl.nElements) {
395 assert(pl.nBytes % 4 == 0);
398 if(pl.nBytes / pl.nElements == 8) {
402 auto registerInfoMuxedRaw =
403 NumericAddressedRegisterInfo(name2D +
".MULTIPLEXED_RAW", pl.nBytes / regSize, pl.address, pl.nBytes, pl.bar,
404 width, 0,
true, pl.registerAccess, NumericAddressedRegisterInfo::Type::FIXED_POINT, pl.interruptID);
405 _pmap.addRegister(registerInfoMuxedRaw);
410 void TraditionalMapFileParser::handle2D(
const ParsedLine& pl) {
412 std::list<ParsedLine> channelLines;
414 auto it = _parsedLinesMap.find(makeSequenceName(pl.pathName, channelLines.size()));
415 if(it == _parsedLinesMap.end())
break;
416 if(it->second.address < pl.address) {
418 "Start address of channel smaller than 2D register start address ('" + pl.pathName +
"').");
420 channelLines.push_back(it->second);
423 make2DRegisterInfos(pl, channelLines, MULTIPLEXED_SEQUENCE_PREFIX);
Exception thrown when a logic error has occured.
constexpr auto SEQUENCE_PREFIX
std::string to_string(const std::string &v)