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(
".");
205 is >> std::setbase(0) >> pl.nElements >> std::setbase(0) >> pl.address >> std::setbase(0) >> pl.nBytes;
213 is >> std::setbase(0) >> pl.bar;
217 is >> std::setbase(0) >> pl.width;
226 std::string bitInterpretation;
227 is >> bitInterpretation;
230 std::tie(pl.type, pl.nFractionalBits) = getTypeAndNFractionalBits(bitInterpretation, pl.width);
231 if(pl.nFractionalBits > 1023 || pl.nFractionalBits < -1024) {
240 is >> std::setbase(0) >> pl.signedFlag;
245 std::string accessString;
249 std::transform(accessString.begin(), accessString.end(), accessString.begin(),
250 [](
unsigned char c) { return std::toupper(c); });
253 auto interruptId = getInterruptId(accessString);
255 if(!interruptId.empty()) {
256 pl.registerAccess = NumericAddressedRegisterInfo::Access::INTERRUPT;
257 pl.interruptID = interruptId;
259 else if(accessString ==
"RO") {
260 pl.registerAccess = NumericAddressedRegisterInfo::Access::READ_ONLY;
262 else if(accessString ==
"RW") {
263 pl.registerAccess = NumericAddressedRegisterInfo::Access::READ_WRITE;
265 else if(accessString ==
"WO") {
266 pl.registerAccess = NumericAddressedRegisterInfo::Access::WRITE_ONLY;
275 checkFileConsitencyAndThrowIfError(pl.registerAccess, pl.type, pl.nElements, pl.address, pl.nBytes, pl.bar,
276 pl.width, pl.nFractionalBits, pl.signedFlag);
283 bool TraditionalMapFileParser::isScalarOr1D(
const RegisterPath& pathName) {
284 auto [module, name] = splitStringAtLastDot(pathName);
285 return !boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX) &&
286 !boost::algorithm::starts_with(name, SEQUENCE_PREFIX) &&
287 !boost::algorithm::starts_with(name, MEM_MULTIPLEXED_PREFIX) && !is2DNewStyle(module);
292 bool TraditionalMapFileParser::is2D(
const RegisterPath& pathName) {
293 auto [module, name] = splitStringAtLastDot(pathName);
294 return boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX);
299 bool TraditionalMapFileParser::is2DNewStyle(RegisterPath pathName) {
301 pathName.setAltSeparator(
".");
302 auto components = pathName.getComponents();
303 if(components.size() != 2)
return false;
304 return boost::algorithm::starts_with(components[1], MEM_MULTIPLEXED_PREFIX);
309 RegisterPath TraditionalMapFileParser::makeSequenceName(
const RegisterPath& pathName,
size_t index) {
310 auto [module, name] = splitStringAtLastDot(pathName);
311 assert(boost::algorithm::starts_with(name, MULTIPLEXED_SEQUENCE_PREFIX));
312 name = name.substr(strlen(MULTIPLEXED_SEQUENCE_PREFIX));
314 r.setAltSeparator(
".");
320 RegisterPath TraditionalMapFileParser::make2DName(
const RegisterPath& pathName,
const std::string& prefix) {
321 auto [module, name] = splitStringAtLastDot(pathName);
322 assert(boost::algorithm::starts_with(name, prefix));
323 name = name.substr(prefix.size());
324 auto r = RegisterPath(module) / name;
325 r.setAltSeparator(
".");
331 void TraditionalMapFileParser::handle2DNewStyle(
const ParsedLine& pl) {
335 std::list<ParsedLine> channelLines;
336 for(
auto& [key, value] : _parsedLinesMap) {
337 if(key.startsWith(pl.pathName) and pl.pathName.length() < key.length()) {
339 if(value.address < pl.address) {
341 "Start address of channel smaller than 2D register start address ('" + pl.pathName +
"').");
343 channelLines.push_back(value);
347 channelLines.sort([](
auto& a,
auto& b) {
return a.address < b.address; });
348 make2DRegisterInfos(pl, channelLines, MEM_MULTIPLEXED_PREFIX);
351 void TraditionalMapFileParser::make2DRegisterInfos(
352 const ParsedLine& pl, std::list<ParsedLine>& channelLines,
const std::string& prefix) {
353 if(channelLines.empty()) {
357 std::vector<NumericAddressedRegisterInfo::ChannelInfo> channels;
358 size_t bytesPerBlock = 0;
360 for(
auto& channel : channelLines) {
361 channels.emplace_back(NumericAddressedRegisterInfo::ChannelInfo{uint32_t(channel.address - pl.address) * 8,
362 channel.type, channel.width, channel.nFractionalBits, channel.signedFlag});
363 bytesPerBlock += channel.nBytes;
364 if(channel.nBytes != 1 && channel.nBytes != 2 && channel.nBytes != 4) {
369 assert(bytesPerBlock > 0);
372 for(
size_t i = 0; i < channels.size() - 1; ++i) {
373 auto actualWidth = channels[i + 1].bitOffset - channels[i].bitOffset;
374 if(channels[i].width > actualWidth) {
375 channels[i].width = actualWidth;
380 auto actualWidth = bytesPerBlock * 8 - channels.back().bitOffset;
381 if(channels.back().width > actualWidth) {
382 channels.back().width = actualWidth;
387 auto nBlocks =
static_cast<uint32_t
>(std::floor(pl.nBytes / bytesPerBlock));
388 auto name2D = make2DName(pl.pathName, prefix);
389 auto registerInfo = NumericAddressedRegisterInfo(
390 name2D, pl.bar, pl.address, nBlocks, bytesPerBlock * 8, channels, pl.registerAccess, pl.interruptID);
391 _pmap.addRegister(registerInfo);
394 assert(pl.nBytes % 4 == 0);
395 auto registerInfoMuxedRaw =
396 NumericAddressedRegisterInfo(name2D +
".MULTIPLEXED_RAW", pl.nBytes / 4, pl.address, pl.nBytes, pl.bar, 32, 0,
397 true, pl.registerAccess, NumericAddressedRegisterInfo::Type::FIXED_POINT, pl.interruptID);
398 _pmap.addRegister(registerInfoMuxedRaw);
403 void TraditionalMapFileParser::handle2D(
const ParsedLine& pl) {
405 std::list<ParsedLine> channelLines;
407 auto it = _parsedLinesMap.find(makeSequenceName(pl.pathName, channelLines.size()));
408 if(it == _parsedLinesMap.end())
break;
409 if(it->second.address < pl.address) {
411 "Start address of channel smaller than 2D register start address ('" + pl.pathName +
"').");
413 channelLines.push_back(it->second);
416 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)