7#include <nlohmann/json.hpp>
9#include <boost/bimap.hpp>
30 boost::bimap<std::string, GmidOptionCode>
makeBimap(
31 std::initializer_list<
typename boost::bimap<std::string, GmidOptionCode>::value_type> list) {
32 return {list.begin(), list.end()};
37 static const auto OptionCodeMap =
makeBimap({
63 inline uint32_t
iToMask(
const uint32_t ithInterrupt) {
64 return 0x1U << ithInterrupt;
77 auto it = OptionCodeMap.left.find(opt);
78 if(it != OptionCodeMap.left.end()) {
91 auto it = OptionCodeMap.right.find(optCode);
92 if(it != OptionCodeMap.right.end()) {
96 return "INVALID_OPTION_CODE";
107 static std::map<GmidOptionCode, std::string> mapOptCode2Message= {
108 {
ISR,
"Interrupt Status Register"},
109 {
IER,
"Interrupt Enable Register"},
110 {
MER,
"Master Enable Register"},
111 {
MIE,
"Master Interrupt Enable"},
112 {
GIE,
"Global Interrupt Enable"},
113 {
ICR,
"Interrupt Clear Register"},
114 {
IAR,
"Interrupt Acknowledge Register"},
115 {
IPR,
"Interrupt Pending Register"},
116 {
SIE,
"Set Interrupt Enable"},
117 {
CIE,
"Clear Interrupt Enable"},
119 "Interrupt Mask Register, not to be confused with Interrupt Mode Register"},
121 "Interrupt Mode Register, what AXI INTC v4.1 calls this 'IMR', not to be confused with Interrupt Mask "
122 "Register, which we call 'IMR'"},
123 {
IVR,
"Interrupt Vector Register"},
124 {
ILR,
"Interrupt Level Register"},
125 {
IVAR,
"Interrupt Vector Address Register"},
126 {
IVEAR,
"Interrupt Vector Extended Address Register"},
139 std::string
strSetToStr(
const std::set<std::string>& strSet,
char delimiter =
',') {
141 if(not strSet.empty()) {
142 for(
const auto& str : strSet) {
143 result += str + delimiter;
157 std::string
intVecToStr(
const std::vector<size_t>& intVec,
char delimiter =
',') {
159 if(not intVec.empty()) {
160 for(
const auto& i : intVec) {
188 const std::vector<size_t>& controllerID,
const std::string& descriptionJsonStr) {
201 static const std::vector<std::string> defaultOptionRegisterNames = {
"ISR",
"IER"};
202 std::string registerPath;
203 std::bitset<OPTION_CODE_COUNT> optionRegisterSettings(0);
205 nlohmann::json descriptionJson;
207 descriptionJson = nlohmann::json::parse(descriptionJsonStr);
209 catch(
const nlohmann::json::parse_error& ex) {
210 std::ostringstream oss;
212 <<
" was unable to parse map file json snippet " << descriptionJsonStr;
217 for(
auto& el : descriptionJson.items()) {
220 std::ostringstream oss;
221 oss <<
"Unknown JSON key '" << el.key() <<
"' provided to map file for GenericMuxedInterruptDistributor "
230 catch(
const nlohmann::json::exception& e) {
231 std::ostringstream oss;
233 <<
"' error for GenericMuxedInterruptDistributor " <<
controllerIDToStr(controllerID) <<
": " << e.what();
241 std::ostringstream oss;
242 oss <<
"GenericMuxedInterruptDistributor " <<
controllerIDToStr(controllerID) <<
" expects a "
249 catch(
const nlohmann::json::exception& e) {
250 std::ostringstream oss;
256 std::vector<std::string> optionRegisterNames;
261 catch(
const nlohmann::json::exception& e) {
262 std::ostringstream oss;
273 std::set<std::string> invalidOptionRegisterNamesEncountered;
274 for(
const auto& orn : optionRegisterNames) {
276 optionRegisterSettings.set(ornCode);
279 invalidOptionRegisterNamesEncountered.insert(orn);
282 if(!invalidOptionRegisterNamesEncountered.empty()) {
283 std::ostringstream oss;
284 oss <<
"Invalid register options " <<
strSetToStr(invalidOptionRegisterNamesEncountered)
290 return std::make_pair(optionRegisterSettings, registerPath);
300 std::bitset<OPTION_CODE_COUNT>
const& optionRegisterSettings, std::vector<size_t>
const& controllerID) {
315 if(optionRegisterSettings.test(
SIE) != optionRegisterSettings.test(
CIE)) {
316 std::ostringstream oss;
318 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
320 <<
" is set, but not both.";
325 if(optionRegisterSettings.test(
IMaskR)) {
326 if(optionRegisterSettings.test(
SIE)) {
327 std::ostringstream oss;
329 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
331 <<
" cannot not both be set.";
334 if(optionRegisterSettings.test(
CIE)) {
335 std::ostringstream oss;
337 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
339 <<
" cannot not both be set.";
345 if(optionRegisterSettings.test(
ICR) and optionRegisterSettings.test(
IAR)) {
346 std::ostringstream oss;
348 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
350 <<
" cannot not both be set.";
355 if(optionRegisterSettings.test(
IMaskR) and optionRegisterSettings.test(
IER)) {
356 std::ostringstream oss;
358 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
360 <<
" cannot not both be set.";
365 if(not(optionRegisterSettings.test(
IMaskR) or optionRegisterSettings.test(
IER))) {
366 std::ostringstream oss;
369 <<
" are set, one of the two is required.";
375 int nMieGieMer =
static_cast<int>(optionRegisterSettings.test(
MIE)) +
376 static_cast<int>(optionRegisterSettings.test(
GIE)) +
static_cast<int>(optionRegisterSettings.test(
MER));
378 std::ostringstream oss;
380 <<
" combination specified in map file json descriptor for GenericMuxedInterruptDistributor "
389 if(optionRegisterSettings.test(
IModeR)) {
390 std::ostringstream oss;
392 <<
" specified in map file json descriptor for GenericMuxedInterruptDistributor "
394 <<
" is a defined options in the AXI IntC v4.1 register space, it is not currently an allowed options in"
395 " the GenericMuxedInterruptDistributor";
399 if(optionRegisterSettings.test(
IVEAR) or optionRegisterSettings.test(
IVAR) or optionRegisterSettings.test(
IVR) or
400 optionRegisterSettings.test(
ILR) or optionRegisterSettings.test(
IModeR)) {
401 std::ostringstream oss;
403 <<
" specified in map file json descriptor for GenericMuxedInterruptDistributor "
406 <<
"are defined options in the AXI IntC v4.1 register space, they are not currently allowed options in the "
407 "GenericMuxedInterruptDistributor";
411 if(optionRegisterSettings.test(
IMaskR)) {
412 std::ostringstream oss;
414 <<
" specified in map file json descriptor for GenericMuxedInterruptDistributor "
416 <<
" is not currently an allowed options in the GenericMuxedInterruptDistributor, but should be supported "
417 "in a later version. ";
422 if(not optionRegisterSettings.test(
ISR)) {
423 std::ostringstream oss;
424 oss <<
explainOptCode(
ISR) <<
" is required but is not enabled for GenericMuxedInterruptDistributor "
436 std::bitset<GmidOptionCode::OPTION_CODE_COUNT> optionRegisterSettings)
439 optionRegisterSettings.set(
ISR);
440 if(not optionRegisterSettings.test(
IMaskR)) {
441 optionRegisterSettings.set(
IER);
458 if(optionRegisterSettings.test(
ICR)) {
461 else if(optionRegisterSettings.test(
IAR)) {
468 _hasMer = optionRegisterSettings.test(
MER) or optionRegisterSettings.test(
MIE) or optionRegisterSettings.test(
GIE);
471 optionRegisterSettings.test(
MIE) ?
MIE : (optionRegisterSettings.test(
GIE) ?
GIE :
MER);
489 auto catalogue =
_backend->getRegisterCatalogue();
491 auto checkRedable = [catalogue](
auto& accessor) {
492 auto description = catalogue.getRegister(accessor->getName());
493 if(!description.isReadable()) {
495 "GenericMuxedInterruptDistributor: Handshake register not readable: " + accessor->getName());
498 auto checkWriteable = [catalogue](
auto& accessor) {
499 auto description = catalogue.getRegister(accessor->getName());
500 if(!description.isWriteable()) {
502 "GenericMuxedInterruptDistributor: Handshake register not writeable: " + accessor->getName());
507 checkWriteable(
_ier);
508 checkWriteable(
_icr);
511 checkWriteable(
_mer);
514 checkWriteable(
_sie);
517 checkWriteable(
_cie);
530 std::cerr <<
"Logic error in ~GenericMuxedInterruptDistributor: " << e.
what() <<
" TERMINATING!" << std::endl;
540 _icr->accessData(0) = mask;
568 _ier->accessData(0) = ~_activeInterrupts;
573 _cie->accessData(0) = mask;
609 _ier->accessData(0) = ~_activeInterrupts;
639 for(
auto const& [i, subDomainWeakPtr] :
_subDomains) {
642 if(
auto subDomain = subDomainWeakPtr.lock(); subDomain) {
647 subDomain->distribute(
nullptr, version);
671 std::bitset<OPTION_CODE_COUNT> optionRegisterSettings = parseResult.first;
672 std::string registerPath = parseResult.second;
674 return std::make_unique<GenericMuxedInterruptDistributor>(parent, registerPath, optionRegisterSettings);
681 _mer->accessData(0) = 0x00000003;
689 uint32_t activeInterrupts = 0;
690 for(
auto const& [i, subDomainWeakPtr] :
_subDomains) {
692 if(subDomainWeakPtr.lock()) {
693 activeInterrupts |=
iToMask(i);
707 auto subDomain = subDomainIter.second.lock();
709 subDomain->activate(
nullptr, version);
717 auto index = subDomain.
getId().back();
722 subDomain.
activate(
nullptr, version);
Class for generating and holding version numbers without exposing a numeric representation.
void clearInterruptsFromMask(uint32_t mask)
In mask, 1 bits clear the corresponding registers, 0 bits do nothing.
void enableInterruptsFromMask(uint32_t mask)
For each bit in mask that is a 1, the corresponding interrupt gets enabled, and the internal copy of ...
~GenericMuxedInterruptDistributor() override
void disableInterruptsFromMask(uint32_t mask)
Disables each interrupt corresponding to the 1 bits in mask, and updates _activeInterrupts.
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _ier
uint32_t _activeInterrupts
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _cie
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _isr
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _sie
void clearOneInterrupt(uint32_t ithInterrupt)
void clearAllEnabledInterrupts()
void handle(VersionNumber version) override
Handle gets called when a trigger comes in.
void activate(VersionNumber version) override
void activateSubDomain(SubDomain< std::nullptr_t > &subDomain, VersionNumber const &version) override
Function to activate a (new) single SubDomain if the MuxedInterruptDistributor is already active.
void clearAllInterrupts()
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _icr
boost::shared_ptr< NDRegisterAccessor< uint32_t > > _mer
static std::unique_ptr< GenericMuxedInterruptDistributor > create(std::string const &description, const boost::shared_ptr< SubDomain< std::nullptr_t > > &parent)
Create parses the json configuration snippet 'description', and calls the constructor.
void enableOneInterrupt(uint32_t ithInterrupt)
void disableOneInterrupt(uint32_t ithInterrupt)
GenericMuxedInterruptDistributor(const boost::shared_ptr< SubDomain< std::nullptr_t > > &parent, const std::string ®isterPath, std::bitset<(ulong) GmidOptionCode::OPTION_CODE_COUNT > optionRegisterSettings)
Interface base class for interrupt controller handlers.
std::map< size_t, boost::weak_ptr< SubDomain< std::nullptr_t > > > _subDomains
boost::shared_ptr< DeviceBackend > _backend
Send backend-specific asynchronous data to different distributors:
std::vector< size_t > getId()
void activate(BackendSpecificDataType, VersionNumber v)
Exception thrown when a logic error has occured.
const char * what() const noexcept override
Return the message describing what exactly went wrong.
Exception thrown when a runtime error has occured.
std::string explainOptCode(GmidOptionCode optCode)
This returns strings explaining the option code acronyms for use in error messages.
std::pair< std::bitset< OPTION_CODE_COUNT >, std::string > parseAndValidateJsonDescriptionStrV0(const std::vector< size_t > &controllerID, const std::string &descriptionJsonStr)
This extracts and validates data from the json snippet 'descriptorJsonStr' that matches the version 1...
std::string getOptionRegisterStr(GmidOptionCode optCode)
Given the Register option code enum, returns the corresponding string.
std::string strSetToStr(const std::set< std::string > &strSet, char delimiter=',')
The default delimiter is ',' TODO move this to some string helper library.
std::string controllerIDToStr(const std::vector< size_t > &controllerID)
Return a string describing the controllerID of the form "[1,2,3]".
std::string intVecToStr(const std::vector< size_t > &intVec, char delimiter=',')
Return a string describing the intVec of the form "1,2,3" The default delimiter is ',...
GmidOptionCode getOptionRegisterEnum(const std::string &opt)
If the string is not a recognized option code, returns GmidOptionCode::INVALID_OPTION_CODE It is not ...
uint32_t iToMask(const uint32_t ithInterrupt)
Return a 32 bit mask with the ithInterrupt bit from the left set to 1 and all others 0.
boost::bimap< std::string, GmidOptionCode > makeBimap(std::initializer_list< typename boost::bimap< std::string, GmidOptionCode >::value_type > list)
This is an initializer for a boost::bimap so that it can be produced using nice syntax.
void steriliseOptionRegisterSettings(std::bitset< OPTION_CODE_COUNT > const &optionRegisterSettings, std::vector< size_t > const &controllerID)
Ensures permissible combinations of option registers by throwing ChimeraTK::logic_error if there are ...
std::string to_string(const std::string &v)
static constexpr const char *const VERSION_JSON_KEY
static constexpr const char *const OPTIONS_JSON_KEY
static constexpr const char *const PATH_JSON_KEY
static constexpr const int jsonDescriptorVersion