diff options
author | Jens Heuschkel <heuschkel@tk.tu-darmstadt.de> | 2016-11-23 10:24:55 (GMT) |
---|---|---|
committer | Jens Heuschkel <heuschkel@tk.tu-darmstadt.de> | 2016-11-23 10:24:55 (GMT) |
commit | 5dbac430453dac1ec1fb76250797df7222f37f40 (patch) | |
tree | 26e3c255ac71afa09267242ea882878a3599b7fa | |
parent | e7aa2089b209388afd361b1d094ceeb57b5a6910 (diff) | |
download | uscxml-5dbac430453dac1ec1fb76250797df7222f37f40.zip uscxml-5dbac430453dac1ec1fb76250797df7222f37f40.tar.gz uscxml-5dbac430453dac1ec1fb76250797df7222f37f40.tar.bz2 |
butify code again
-rw-r--r-- | src/uscxml/plugins/datamodel/promela/PromelaParser.cpp | 2 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.cpp | 4610 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.h | 82 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.cpp | 2708 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.h | 322 | ||||
-rw-r--r-- | src/uscxml/transform/Transformer.h | 10 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp | 258 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaCodeAnalyzer.h | 30 | ||||
-rw-r--r-- | src/uscxml/util/String.cpp | 25 |
9 files changed, 4027 insertions, 4020 deletions
diff --git a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp index 32fbc13..57f694a 100644 --- a/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp +++ b/src/uscxml/plugins/datamodel/promela/PromelaParser.cpp @@ -85,7 +85,7 @@ void PromelaParser::init(const std::string& expr) { parseInCompound = 0; input_length = expr.length() + 2; // plus some zero terminators input = (char*) calloc(1, input_length); - memcpy(input, expr.c_str(), expr.length()); + memcpy(input, expr.c_str(), expr.length()); promela_lex_init(&scanner); // promela_assign_set_extra(ast, &scanner); diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp index 06c8a92..5dcf9f0 100644 --- a/src/uscxml/transform/ChartToPromela.cpp +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -78,140 +78,140 @@ ChartToPromela::~ChartToPromela() { } void ChartToPromela::prepare() { - if (_machinesAll == NULL) { - _machinesAll = new std::map<DOMElement*, ChartToPromela*>(); - (*_machinesAll)[_scxml] = this; - } - - if (_machinesAllPerId == NULL) - _machinesAllPerId = new std::map<std::string, XERCESC_NS::DOMElement* >(); - - if (_parentTopMost == NULL) { - _parentTopMost = this; - } - - // are there nested SCXML invokers? - std::list<DOMElement*> invokes = DOMUtils::inDocumentOrder({ XML_PREFIX(_scxml).str() + "invoke" }, _scxml); - for (auto invoke : invokes) { - - if (!HAS_ATTR(invoke, "id")) { - invoke->setAttribute(X("id"), X("INV_" + UUID::getUUID().substr(0,5))); - } else if (HAS_ATTR(invoke, "id") && UUID::isUUID(ATTR(invoke, "id"))) { - // shorten UUIDs - invoke->setAttribute(X("id"), X("INV_" + ATTR(invoke, "id").substr(0,5))); - } - - if (HAS_ATTR(invoke, "type") && - ATTR(invoke, "type") != "scxml" && - ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/" && - ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") - continue; - - assert(HAS_ATTR(invoke, "id")); - invoke->setAttribute(X("name"), invoke->getAttribute(X("id"))); - - Interpreter nested; - if (HAS_ATTR(invoke, "src")) { - nested = Interpreter::fromURL(URL::resolve(ATTR(invoke, "src"), _baseURL)); - } else { - std::list<DOMElement*> contents = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "content", invoke); - std::list<DOMElement*> scxmls = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "scxml", contents.front()); - - assert (scxmls.size() > 0); - nested = Interpreter::fromElement(scxmls.front(), _baseURL); - } - - _machinesNested[invoke] = new ChartToPromela(nested); - _machinesNested[invoke]->_analyzer = _analyzer; - _machinesNested[invoke]->_analyzer->analyze(_machinesNested[invoke]); - _machinesNested[invoke]->prepare(); - _machinesNested[invoke]->_parent = this; - _machinesNested[invoke]->_parentTopMost = _parentTopMost; - _machinesNested[invoke]->_machinesAll = _machinesAll; - (*_machinesAll)[invoke] = _machinesNested[invoke]; - - _machinesNested[invoke]->_invokerid = ATTR(invoke, "id"); - _analyzer->createMacroName(_machinesNested[invoke]->_invokerid); - _analyzer->addEvent("done.invoke." + _machinesNested[invoke]->_invokerid); - - _machinesNested[invoke]->_prefix = _analyzer->macroForLiteral(ATTR(invoke, "id")) + "_"; - - - _machinesPerId[ATTR_CAST(invoke, "id")] = invoke; - (*_machinesAllPerId)[ATTR(invoke, "id")] = invoke; - - } - - if (_machinesAll->size() > 1) { + if (_machinesAll == NULL) { + _machinesAll = new std::map<DOMElement*, ChartToPromela*>(); + (*_machinesAll)[_scxml] = this; + } + + if (_machinesAllPerId == NULL) + _machinesAllPerId = new std::map<std::string, XERCESC_NS::DOMElement* >(); + + if (_parentTopMost == NULL) { + _parentTopMost = this; + } + + // are there nested SCXML invokers? + std::list<DOMElement*> invokes = DOMUtils::inDocumentOrder({ XML_PREFIX(_scxml).str() + "invoke" }, _scxml); + for (auto invoke : invokes) { + + if (!HAS_ATTR(invoke, "id")) { + invoke->setAttribute(X("id"), X("INV_" + UUID::getUUID().substr(0,5))); + } else if (HAS_ATTR(invoke, "id") && UUID::isUUID(ATTR(invoke, "id"))) { + // shorten UUIDs + invoke->setAttribute(X("id"), X("INV_" + ATTR(invoke, "id").substr(0,5))); + } + + if (HAS_ATTR(invoke, "type") && + ATTR(invoke, "type") != "scxml" && + ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/" && + ATTR(invoke, "type") != "http://www.w3.org/TR/scxml/#SCXMLEventProcessor") + continue; + + assert(HAS_ATTR(invoke, "id")); + invoke->setAttribute(X("name"), invoke->getAttribute(X("id"))); + + Interpreter nested; + if (HAS_ATTR(invoke, "src")) { + nested = Interpreter::fromURL(URL::resolve(ATTR(invoke, "src"), _baseURL)); + } else { + std::list<DOMElement*> contents = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "content", invoke); + std::list<DOMElement*> scxmls = DOMUtils::filterChildElements(XML_PREFIX(invoke).str() + "scxml", contents.front()); + + assert (scxmls.size() > 0); + nested = Interpreter::fromElement(scxmls.front(), _baseURL); + } + + _machinesNested[invoke] = new ChartToPromela(nested); + _machinesNested[invoke]->_analyzer = _analyzer; + _machinesNested[invoke]->_analyzer->analyze(_machinesNested[invoke]); + _machinesNested[invoke]->prepare(); + _machinesNested[invoke]->_parent = this; + _machinesNested[invoke]->_parentTopMost = _parentTopMost; + _machinesNested[invoke]->_machinesAll = _machinesAll; + (*_machinesAll)[invoke] = _machinesNested[invoke]; + + _machinesNested[invoke]->_invokerid = ATTR(invoke, "id"); + _analyzer->createMacroName(_machinesNested[invoke]->_invokerid); + _analyzer->addEvent("done.invoke." + _machinesNested[invoke]->_invokerid); + + _machinesNested[invoke]->_prefix = _analyzer->macroForLiteral(ATTR(invoke, "id")) + "_"; + + + _machinesPerId[ATTR_CAST(invoke, "id")] = invoke; + (*_machinesAllPerId)[ATTR(invoke, "id")] = invoke; + + } + + if (_machinesAll->size() > 1) { // _analyzer->addCode("_event.origin", this); - _analyzer->addCode("_event.invokeid", this); - } - - // transform data / assign json into PROMELA statements - std::list<DOMElement*> values; - values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "assign"}, _scxml)); - values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "data"}, _scxml)); - - for (auto element : values) { - std::string key; - if (HAS_ATTR(element, "id")) { - key = ATTR(element, "id"); - } else if (HAS_ATTR(element, "location")) { - key = ATTR(element, "location"); - } - - if (key.length() == 0) - continue; - - std::string value; - if (HAS_ATTR(element, "expr")) { - value = ATTR(element, "expr"); - } else if (HAS_ATTR(element, "src")) { - URL absUrl = URL::resolve(ATTR_CAST(element, "src"), _baseURL); - value = absUrl.getInContent(); - } else { - std::list<DOMNode*> assignTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, element, true); - if (assignTexts.size() > 0) { - for (auto assignText : assignTexts) { - value += X(assignText->getNodeValue()).str(); - } - } - } - - boost::trim(value); - if (value.size() == 0) - continue; - - // remove all children, we will replace by suitable promela statements - while(element->hasChildNodes()) - element->removeChild(element->getFirstChild()); - - std::string newValue; - Data json = Data::fromJSON(value); - if (!json.empty()) { - newValue = dataToAssignments(key, json); - } else { - newValue = key + " = " + value + ";"; - } - - if (LOCALNAME(element) == "data") - _varInitializers.push_back(newValue); - - DOMText* newText = _document->createTextNode(X(newValue)); - element->insertBefore(newText, NULL); - - _analyzer->addCode(newValue, this); - - } + _analyzer->addCode("_event.invokeid", this); + } + + // transform data / assign json into PROMELA statements + std::list<DOMElement*> values; + values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "assign"}, _scxml)); + values.splice(values.end(), DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "data"}, _scxml)); + + for (auto element : values) { + std::string key; + if (HAS_ATTR(element, "id")) { + key = ATTR(element, "id"); + } else if (HAS_ATTR(element, "location")) { + key = ATTR(element, "location"); + } + + if (key.length() == 0) + continue; + + std::string value; + if (HAS_ATTR(element, "expr")) { + value = ATTR(element, "expr"); + } else if (HAS_ATTR(element, "src")) { + URL absUrl = URL::resolve(ATTR_CAST(element, "src"), _baseURL); + value = absUrl.getInContent(); + } else { + std::list<DOMNode*> assignTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, element, true); + if (assignTexts.size() > 0) { + for (auto assignText : assignTexts) { + value += X(assignText->getNodeValue()).str(); + } + } + } + + boost::trim(value); + if (value.size() == 0) + continue; + + // remove all children, we will replace by suitable promela statements + while(element->hasChildNodes()) + element->removeChild(element->getFirstChild()); + + std::string newValue; + Data json = Data::fromJSON(value); + if (!json.empty()) { + newValue = dataToAssignments(key, json); + } else { + newValue = key + " = " + value + ";"; + } + + if (LOCALNAME(element) == "data") + _varInitializers.push_back(newValue); + + DOMText* newText = _document->createTextNode(X(newValue)); + element->insertBefore(newText, NULL); + + _analyzer->addCode(newValue, this); + + } } - + void ChartToPromela::writeTo(std::ostream& stream) { - _prefix = "ROOT_"; - _invokerid = "ROOT"; - _analyzer = new PromelaCodeAnalyzer(); - _analyzer->analyze(this); - _analyzer->createMacroName(_invokerid); - prepare(); + _prefix = "ROOT_"; + _invokerid = "ROOT"; + _analyzer = new PromelaCodeAnalyzer(); + _analyzer->analyze(this); + _analyzer->createMacroName(_invokerid); + prepare(); stream << "/** generated from " << std::endl; stream << " " << std::string(_baseURL) << std::endl; @@ -224,88 +224,88 @@ void ChartToPromela::writeTo(std::ostream& stream) { writeMacros(stream); - stream << std::endl; - writeStrings(stream); - stream << std::endl; - - for (auto machine : *_machinesAll) { - machine.second->writeBitHasAndMacro(stream); - stream << std::endl; - machine.second->writeBitHasAnyMacro(stream); - stream << std::endl; - machine.second->writeBitOrMacro(stream); - stream << std::endl; - machine.second->writeBitClearMacro(stream); - stream << std::endl; - machine.second->writeBitCopyMacro(stream); - stream << std::endl; - machine.second->writeBitAndMacro(stream); - stream << std::endl; - machine.second->writeBitAndNotMacro(stream); - stream << std::endl; - writeTypeDefs(stream); - stream << std::endl; - - } - - writeCommonTypeDefs(stream); - stream << std::endl; - - for (auto machine : *_machinesAll) { - machine.second->writeVariables(stream); - stream << std::endl; - } - writeCommonVariables(stream); - stream << std::endl; - - if (_analyzer->usesComplexEventStruct()) { - if (_analyzer->usesEventField("delay")) { - writeInsertWithDelay(stream); - stream << std::endl; - } - writeAdvanceTime(stream); - stream << std::endl; - writeScheduleMachines(stream); - stream << std::endl; - writeRescheduleProcess(stream); - stream << std::endl; - writeDetermineShortestDelay(stream); - stream << std::endl; - } - - if (_machinesAll->size() > 1) { - writeRemovePendingEventsFromInvoker(stream); - stream << std::endl; - } - - writeCancelEvents(stream); - stream << std::endl; - - for (auto machine : *_machinesAll) { - machine.second->writeFSM(stream); - stream << std::endl; - } + stream << std::endl; + writeStrings(stream); + stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeBitHasAndMacro(stream); + stream << std::endl; + machine.second->writeBitHasAnyMacro(stream); + stream << std::endl; + machine.second->writeBitOrMacro(stream); + stream << std::endl; + machine.second->writeBitClearMacro(stream); + stream << std::endl; + machine.second->writeBitCopyMacro(stream); + stream << std::endl; + machine.second->writeBitAndMacro(stream); + stream << std::endl; + machine.second->writeBitAndNotMacro(stream); + stream << std::endl; + writeTypeDefs(stream); + stream << std::endl; + + } + + writeCommonTypeDefs(stream); + stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeVariables(stream); + stream << std::endl; + } + writeCommonVariables(stream); + stream << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + if (_analyzer->usesEventField("delay")) { + writeInsertWithDelay(stream); + stream << std::endl; + } + writeAdvanceTime(stream); + stream << std::endl; + writeScheduleMachines(stream); + stream << std::endl; + writeRescheduleProcess(stream); + stream << std::endl; + writeDetermineShortestDelay(stream); + stream << std::endl; + } + + if (_machinesAll->size() > 1) { + writeRemovePendingEventsFromInvoker(stream); + stream << std::endl; + } + + writeCancelEvents(stream); + stream << std::endl; + + for (auto machine : *_machinesAll) { + machine.second->writeFSM(stream); + stream << std::endl; + } stream << "init {" << std::endl; - - stream << "/* initialize state and transition information */" << std::endl; - for (auto machine : *_machinesAll) { - machine.second->writeTransitions(stream); - stream << std::endl; - machine.second->writeStates(stream); - stream << std::endl; - - stream << "/* initialize data model variables */" << std::endl; - stream << " " << machine.second->_prefix << "flags[USCXML_CTX_PRISTINE] = true;" << std::endl; - stream << " " << machine.second->_prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - - for (auto initializer : machine.second->_varInitializers) { - stream << _analyzer->adaptCode(beautifyIndentation(initializer, 1), machine.second->_prefix) << std::endl; - } - } - - stream << std::endl; + + stream << "/* initialize state and transition information */" << std::endl; + for (auto machine : *_machinesAll) { + machine.second->writeTransitions(stream); + stream << std::endl; + machine.second->writeStates(stream); + stream << std::endl; + + stream << "/* initialize data model variables */" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_PRISTINE] = true;" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + + for (auto initializer : machine.second->_varInitializers) { + stream << _analyzer->adaptCode(beautifyIndentation(initializer, 1), machine.second->_prefix) << std::endl; + } + } + + stream << std::endl; stream << " run " << _prefix << "step() priority 10;" << std::endl; stream << "}" << std::endl; @@ -315,128 +315,128 @@ void ChartToPromela::writeTo(std::ostream& stream) { } void ChartToPromela::writeBitAndMacro(std::ostream& stream) { - stream << "/** and'ing bits in a with mask */" << std::endl; - stream << "#define " << _prefix << "TRANS_AND(a, mask) \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; - - stream << "#define " << _prefix << "STATES_AND(a, mask) \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; + stream << "/** and'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_AND(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_AND(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; } void ChartToPromela::writeBitAndNotMacro(std::ostream& stream) { - stream << "/** not and'ing bits in a with mask */" << std::endl; - stream << "#define " << _prefix << "TRANS_AND_NOT(a, mask) \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; - - stream << "#define " << _prefix << "STATES_AND_NOT(a, mask) \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; - + stream << "/** not and'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_AND_NOT(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_AND_NOT(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] & !mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + } void ChartToPromela::writeBitCopyMacro(std::ostream& stream) { - stream << "/** copy bits from a to b */" << std::endl; - stream << "#define " << _prefix << "TRANS_COPY(a, b) \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; - } - stream << std::endl; - - stream << "#define " << _prefix << "STATES_COPY(a, b) \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; - } - stream << std::endl; - - + stream << "/** copy bits from a to b */" << std::endl; + stream << "#define " << _prefix << "TRANS_COPY(a, b) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_COPY(a, b) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = b[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + } - + void ChartToPromela::writeBitHasAndMacro(std::ostream& stream) { - stream << "/** is there a common bit in t1 and t2 */" << std::endl; - stream << "#define " << _prefix << "TRANS_HAS_AND(a, b) \\" << std::endl; - + stream << "/** is there a common bit in t1 and t2 */" << std::endl; + stream << "#define " << _prefix << "TRANS_HAS_AND(a, b) \\" << std::endl; + stream << "(false \\" << std::endl; for (size_t i = 0; i < _transitions.size(); i++) { stream << " || a[" << i << "] & b[" << i << "] \\" << std::endl; } stream << ")" << std::endl; - stream << std::endl; + stream << std::endl; - stream << "#define " << _prefix << "STATES_HAS_AND(a, b) \\" << std::endl; - - stream << "(false \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << " || a[" << i << "] & b[" << i << "] \\" << std::endl; - } - stream << ")" << std::endl; - stream << std::endl; + stream << "#define " << _prefix << "STATES_HAS_AND(a, b) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << " || a[" << i << "] & b[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; } void ChartToPromela::writeBitHasAnyMacro(std::ostream& stream) { - stream << "/** is there bit set in a */" << std::endl; - stream << "#define " << _prefix << "TRANS_HAS_ANY(a) \\" << std::endl; - - stream << "(false \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << " || a[" << i << "] \\" << std::endl; - } - stream << ")" << std::endl; - stream << std::endl; - - stream << "#define " << _prefix << "STATES_HAS_ANY(a) \\" << std::endl; - - stream << "(false \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << " || a[" << i << "] \\" << std::endl; - } - stream << ")" << std::endl; - stream << std::endl; - + stream << "/** is there bit set in a */" << std::endl; + stream << "#define " << _prefix << "TRANS_HAS_ANY(a) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << " || a[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; + + stream << "#define " << _prefix << "STATES_HAS_ANY(a) \\" << std::endl; + + stream << "(false \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << " || a[" << i << "] \\" << std::endl; + } + stream << ")" << std::endl; + stream << std::endl; + } void ChartToPromela::writeBitOrMacro(std::ostream& stream) { - stream << "/** or'ing bits in a with mask */" << std::endl; - stream << "#define " << _prefix << "TRANS_OR(a, mask) \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; - - stream << "#define " << _prefix << "STATES_OR(a, mask) \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; - } - stream << std::endl; + stream << "/** or'ing bits in a with mask */" << std::endl; + stream << "#define " << _prefix << "TRANS_OR(a, mask) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_OR(a, mask) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = a[" << i << "] | mask[" << i << "]; \\" << std::endl; + } + stream << std::endl; } void ChartToPromela::writeBitClearMacro(std::ostream& stream) { - stream << "/** clearing all bits of a */" << std::endl; - stream << "#define " << _prefix << "TRANS_CLEAR(a) \\" << std::endl; - for (size_t i = 0; i < _transitions.size(); i++) { - stream << "a[" << i << "] = false; \\" << std::endl; - } - stream << std::endl; - - stream << "#define " << _prefix << "STATES_CLEAR(a) \\" << std::endl; - for (size_t i = 0; i < _states.size(); i++) { - stream << "a[" << i << "] = false; \\" << std::endl; - } - stream << std::endl; - + stream << "/** clearing all bits of a */" << std::endl; + stream << "#define " << _prefix << "TRANS_CLEAR(a) \\" << std::endl; + for (size_t i = 0; i < _transitions.size(); i++) { + stream << "a[" << i << "] = false; \\" << std::endl; + } + stream << std::endl; + + stream << "#define " << _prefix << "STATES_CLEAR(a) \\" << std::endl; + for (size_t i = 0; i < _states.size(); i++) { + stream << "a[" << i << "] = false; \\" << std::endl; + } + stream << std::endl; + } void ChartToPromela::printBitArray(std::ostream& stream, @@ -467,8 +467,8 @@ void ChartToPromela::writeMacros(std::ostream& stream) { stream << "#define USCXML_CTX_SPONTANEOUS 1" << std::endl; stream << "#define USCXML_CTX_TOP_LEVEL_FINAL 2" << std::endl; stream << "#define USCXML_CTX_TRANSITION_FOUND 3" << std::endl; - stream << "#define USCXML_CTX_FINISHED 4" << std::endl; - stream << "#define USCXML_CTX_DEQUEUE_EXTERNAL 5" << std::endl; + stream << "#define USCXML_CTX_FINISHED 4" << std::endl; + stream << "#define USCXML_CTX_DEQUEUE_EXTERNAL 5" << std::endl; stream << std::endl; stream << "#define USCXML_TRANS_SPONTANEOUS 0" << std::endl; @@ -500,105 +500,105 @@ void ChartToPromela::writeMacros(std::ostream& stream) { } void ChartToPromela::writeCommonTypeDefs(std::ostream& stream) { - stream << "/* common type definitions */" << std::endl; - PromelaCodeAnalyzer::PromelaTypedef typeDefs = _analyzer->getTypes(); - if (typeDefs.types.size() == 0) - return; - - std::list<PromelaCodeAnalyzer::PromelaTypedef> individualDefs; - std::list<PromelaCodeAnalyzer::PromelaTypedef> currDefs; - currDefs.push_back(typeDefs); - - while(currDefs.size() > 0) { - if (std::find(individualDefs.begin(), individualDefs.end(), currDefs.front()) == individualDefs.end()) { - individualDefs.push_back(currDefs.front()); - for (std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = currDefs.front().types.begin(); typeIter != currDefs.front().types.end(); typeIter++) { - currDefs.push_back(typeIter->second); - } - } - currDefs.pop_front(); - } - individualDefs.pop_front(); - - for (std::list<PromelaCodeAnalyzer::PromelaTypedef>::reverse_iterator rIter = individualDefs.rbegin(); rIter != individualDefs.rend(); rIter++) { - PromelaCodeAnalyzer::PromelaTypedef currDef = *rIter; - - if (currDef.types.size() == 0 || currDef.name.size() == 0) - continue; - - stream << "typedef " << currDef.name << " {" << std::endl; - if (currDef.name.compare("_event_t") ==0) { - if (_analyzer->usesEventField("delay")) { - // make sure delay is the first member for sorted enqueuing to work - stream << " " << declForRange("delay", 0, _analyzer->largestDelay, true) << ";" << std::endl; + stream << "/* common type definitions */" << std::endl; + PromelaCodeAnalyzer::PromelaTypedef typeDefs = _analyzer->getTypes(); + if (typeDefs.types.size() == 0) + return; + + std::list<PromelaCodeAnalyzer::PromelaTypedef> individualDefs; + std::list<PromelaCodeAnalyzer::PromelaTypedef> currDefs; + currDefs.push_back(typeDefs); + + while(currDefs.size() > 0) { + if (std::find(individualDefs.begin(), individualDefs.end(), currDefs.front()) == individualDefs.end()) { + individualDefs.push_back(currDefs.front()); + for (std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = currDefs.front().types.begin(); typeIter != currDefs.front().types.end(); typeIter++) { + currDefs.push_back(typeIter->second); + } + } + currDefs.pop_front(); + } + individualDefs.pop_front(); + + for (std::list<PromelaCodeAnalyzer::PromelaTypedef>::reverse_iterator rIter = individualDefs.rbegin(); rIter != individualDefs.rend(); rIter++) { + PromelaCodeAnalyzer::PromelaTypedef currDef = *rIter; + + if (currDef.types.size() == 0 || currDef.name.size() == 0) + continue; + + stream << "typedef " << currDef.name << " {" << std::endl; + if (currDef.name.compare("_event_t") ==0) { + if (_analyzer->usesEventField("delay")) { + // make sure delay is the first member for sorted enqueuing to work + stream << " " << declForRange("delay", 0, _analyzer->largestDelay, true) << ";" << std::endl; #if NEW_DELAY_RESHUFFLE #else - stream << " short seqNr;" << std::endl; + stream << " short seqNr;" << std::endl; #endif - } - stream << " " << declForRange("name", 0, _analyzer->getTrie().lastIndex, true) << ";" << std::endl; - if (_analyzer->usesEventField("invokeid")) { - stream << " " << declForRange("invokeid", 0, _machinesAll->size() + 1, true) << ";" << std::endl; - } - if (_analyzer->usesEventField("origin")) { - stream << " " << declForRange("origin", 0, _machinesAll->size() + 1, true) << ";" << std::endl; - } - } - for (std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator tIter = currDef.types.begin(); tIter != currDef.types.end(); tIter++) { - if (currDef.name.compare("_event_t") == 0 && (tIter->first.compare("name") == 0 || - tIter->first.compare("seqNr") == 0 || - tIter->first.compare("invokeid") == 0 || - tIter->first.compare("origin") == 0 || - tIter->first.compare("delay") == 0)) { // special treatment for _event - continue; - } - if (tIter->second.types.size() == 0) { - stream << " " << declForRange(tIter->first, tIter->second.minValue, tIter->second.maxValue, true) << ";" << std::endl; // not further nested - // stream << " int " << tIter->first << ";" << std::endl; // not further nested - } else { - stream << " " << tIter->second.name << " " << tIter->first << ";" << std::endl; - } - } - stream << "};" << std::endl << std::endl; - } - - // stream << "/* typedef instances */" << std::endl; - // PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes(); - // std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = allTypes.types.begin(); - // while(typeIter != allTypes.types.end()) { - // if (typeIter->second.types.size() > 0) { - // // an actual typedef - // stream << "hidden " << typeIter->second.name << " " << typeIter->first << ";" << std::endl; - // } else { - // stream << "hidden " << declForRange(typeIter->first, typeIter->second.minValue, typeIter->second.maxValue) << ";" << std::endl; - // } - // typeIter++; - // } - + } + stream << " " << declForRange("name", 0, _analyzer->getTrie().lastIndex, true) << ";" << std::endl; + if (_analyzer->usesEventField("invokeid")) { + stream << " " << declForRange("invokeid", 0, _machinesAll->size() + 1, true) << ";" << std::endl; + } + if (_analyzer->usesEventField("origin")) { + stream << " " << declForRange("origin", 0, _machinesAll->size() + 1, true) << ";" << std::endl; + } + } + for (std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator tIter = currDef.types.begin(); tIter != currDef.types.end(); tIter++) { + if (currDef.name.compare("_event_t") == 0 && (tIter->first.compare("name") == 0 || + tIter->first.compare("seqNr") == 0 || + tIter->first.compare("invokeid") == 0 || + tIter->first.compare("origin") == 0 || + tIter->first.compare("delay") == 0)) { // special treatment for _event + continue; + } + if (tIter->second.types.size() == 0) { + stream << " " << declForRange(tIter->first, tIter->second.minValue, tIter->second.maxValue, true) << ";" << std::endl; // not further nested + // stream << " int " << tIter->first << ";" << std::endl; // not further nested + } else { + stream << " " << tIter->second.name << " " << tIter->first << ";" << std::endl; + } + } + stream << "};" << std::endl << std::endl; + } + + // stream << "/* typedef instances */" << std::endl; + // PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer->getTypes(); + // std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = allTypes.types.begin(); + // while(typeIter != allTypes.types.end()) { + // if (typeIter->second.types.size() > 0) { + // // an actual typedef + // stream << "hidden " << typeIter->second.name << " " << typeIter->first << ";" << std::endl; + // } else { + // stream << "hidden " << declForRange(typeIter->first, typeIter->second.minValue, typeIter->second.maxValue) << ";" << std::endl; + // } + // typeIter++; + // } + } void ChartToPromela::writeTypeDefs(std::ostream& stream) { - stream << "/* custom type definitions for " << _prefix << " */" << std::endl; + stream << "/* custom type definitions for " << _prefix << " */" << std::endl; } void ChartToPromela::writeCommonVariables(std::ostream& stream) { - stream << "hidden int tmpIndex;" << std::endl; - if (_analyzer->usesComplexEventStruct()) { - stream << "hidden _event_t tmpE;" << std::endl; - } else { - stream << "hidden int tmpE;" << std::endl; - } - - if (_analyzer->hasIndexLessLoops()) - stream << "hidden int _index; /* helper for indexless foreach loops */" << std::endl; - - if (_analyzer->usesEventField("sendid")) - stream << "hidden int _lastSendId = 0; /* sequential counter for send ids */" << std::endl; - - if (_analyzer->usesEventField("delay")) - stream << "hidden short _lastSeqId = 0; /* sequential counter for delayed events */" << std::endl; - stream << std::endl; + stream << "hidden int tmpIndex;" << std::endl; + if (_analyzer->usesComplexEventStruct()) { + stream << "hidden _event_t tmpE;" << std::endl; + } else { + stream << "hidden int tmpE;" << std::endl; + } + + if (_analyzer->hasIndexLessLoops()) + stream << "hidden int _index; /* helper for indexless foreach loops */" << std::endl; + + if (_analyzer->usesEventField("sendid")) + stream << "hidden int _lastSendId = 0; /* sequential counter for send ids */" << std::endl; + + if (_analyzer->usesEventField("delay")) + stream << "hidden short _lastSeqId = 0; /* sequential counter for delayed events */" << std::endl; + stream << std::endl; } @@ -609,65 +609,65 @@ void ChartToPromela::writeVariables(std::ostream& stream) { stream << "bool " << _prefix << "history[" << _states.size() << "];" << std::endl; stream << "bool " << _prefix << "invocations[" << _states.size() << "];" << std::endl; // stream << "bool " << _prefix << "initialized_data[" << _states.size() << "];" << std::endl; - - size_t tolerance = 6; - - if (_analyzer->usesComplexEventStruct()) { - // event is defined with the typedefs - stream << "hidden _event_t " << _prefix << "_event; /* current event */" << std::endl; - stream << "hidden _event_t " << _prefix << "_tmpE; /* temporary event for send */" << std::endl; - stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {_event_t} /* internal queue */" << std::endl; - stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {_event_t} /* external queue */" << std::endl; - if (_allowEventInterleaving) - stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {_event_t} /* temporary queue for external events in transitions */" << std::endl; - } else { - stream << "unsigned " << _prefix << "_event : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* current event */" << std::endl; - stream << "hidden unsigned " << _prefix << "_tmpE : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* temporary event for send */" << std::endl; - stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {int} /* internal queue */" << std::endl; - stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {int} /* external queue */" << std::endl; - if (_allowEventInterleaving) - stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {int} /* temporary queue for external events in transitions */" << std::endl; - } - - if (_transitions.size() > 0) { - stream << std::endl; - stream << "typedef " << _prefix << "transition_t {" << std::endl; - stream << " unsigned source : " << BIT_WIDTH(_states.size()) << ";" << std::endl; - stream << " bool target[" << _states.size() << "];" << std::endl; - stream << " bool type[5];" << std::endl; - stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; - stream << " bool exit_set[" << _states.size() << "];" << std::endl; - stream << "}" << std::endl; + + size_t tolerance = 6; + + if (_analyzer->usesComplexEventStruct()) { + // event is defined with the typedefs + stream << "hidden _event_t " << _prefix << "_event; /* current event */" << std::endl; + stream << "hidden _event_t " << _prefix << "_tmpE; /* temporary event for send */" << std::endl; + stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {_event_t} /* internal queue */" << std::endl; + stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {_event_t} /* external queue */" << std::endl; + if (_allowEventInterleaving) + stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {_event_t} /* temporary queue for external events in transitions */" << std::endl; + } else { + stream << "unsigned " << _prefix << "_event : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* current event */" << std::endl; + stream << "hidden unsigned " << _prefix << "_tmpE : " << BIT_WIDTH(_analyzer->getLiterals().size() + 1) << "; /* temporary event for send */" << std::endl; + stream << "chan " << _prefix << "iQ = [" << (std::max)(_internalQueueLength, (size_t)1) << "] of {int} /* internal queue */" << std::endl; + stream << "chan " << _prefix << "eQ = [" << _externalQueueLength + tolerance << "] of {int} /* external queue */" << std::endl; + if (_allowEventInterleaving) + stream << "chan " << _prefix << "tmpQ = [" << (std::max)(_externalQueueLength + tolerance, (size_t)1) << "] of {int} /* temporary queue for external events in transitions */" << std::endl; + } + + if (_transitions.size() > 0) { + stream << std::endl; + stream << "typedef " << _prefix << "transition_t {" << std::endl; + stream << " unsigned source : " << BIT_WIDTH(_states.size()) << ";" << std::endl; + stream << " bool target[" << _states.size() << "];" << std::endl; + stream << " bool type[5];" << std::endl; + stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; + stream << " bool exit_set[" << _states.size() << "];" << std::endl; + stream << "}" << std::endl; stream << "hidden " << _prefix << "transition_t " << _prefix << "transitions[" << toStr(_transitions.size()) << "];" << std::endl; - stream << std::endl; + stream << std::endl; } - if (_states.size() > 0) { - stream << "typedef " << _prefix << "state_t {" << std::endl; - stream << " unsigned parent : " << BIT_WIDTH(_states.size()) << ";" << std::endl; - stream << " bool children[" << _states.size() << "];" << std::endl; - stream << " bool completion[" << _states.size() << "];" << std::endl; - stream << " bool ancestors[" << _states.size() << "];" << std::endl; - stream << " bool type[8];" << std::endl; - stream << "}" << std::endl; + if (_states.size() > 0) { + stream << "typedef " << _prefix << "state_t {" << std::endl; + stream << " unsigned parent : " << BIT_WIDTH(_states.size()) << ";" << std::endl; + stream << " bool children[" << _states.size() << "];" << std::endl; + stream << " bool completion[" << _states.size() << "];" << std::endl; + stream << " bool ancestors[" << _states.size() << "];" << std::endl; + stream << " bool type[8];" << std::endl; + stream << "}" << std::endl; stream << "hidden " << _prefix << "state_t " << _prefix << "states[" << toStr(_states.size()) << "];" << std::endl; - stream << std::endl; - } - - stream << "typedef " << _prefix << "ctx_t {" << std::endl; - if (_transitions.size() > 0) { - stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; - stream << " bool trans_set[" << _transitions.size() << "];" << std::endl; - } - - stream << " bool target_set[" << _states.size() << "];" << std::endl; - stream << " bool exit_set[" << _states.size() << "];" << std::endl; - stream << " bool entry_set[" << _states.size() << "];" << std::endl; - stream << " bool tmp_states[" << _states.size() << "];" << std::endl; - stream << "}" << std::endl; - stream << "hidden " << _prefix << "ctx_t " << _prefix << "ctx;" << std::endl; - stream << std::endl; - stream << std::endl; + stream << std::endl; + } + + stream << "typedef " << _prefix << "ctx_t {" << std::endl; + if (_transitions.size() > 0) { + stream << " bool conflicts[" << _transitions.size() << "];" << std::endl; + stream << " bool trans_set[" << _transitions.size() << "];" << std::endl; + } + + stream << " bool target_set[" << _states.size() << "];" << std::endl; + stream << " bool exit_set[" << _states.size() << "];" << std::endl; + stream << " bool entry_set[" << _states.size() << "];" << std::endl; + stream << " bool tmp_states[" << _states.size() << "];" << std::endl; + stream << "}" << std::endl; + stream << "hidden " << _prefix << "ctx_t " << _prefix << "ctx;" << std::endl; + stream << std::endl; + stream << std::endl; std::set<std::string> processedIdentifiers; @@ -723,12 +723,12 @@ void ChartToPromela::writeVariables(std::ostream& stream) { } if (typeIter->first == "_event" - || typeIter->first == "config" - || typeIter->first == "_ioprocessors" - || typeIter->first == "_SESSIONID" - || typeIter->first == "_NAME" - || !std::any_of(typeIter->first.begin(), typeIter->first.end(), ::islower) - ) { + || typeIter->first == "config" + || typeIter->first == "_ioprocessors" + || typeIter->first == "_SESSIONID" + || typeIter->first == "_NAME" + || !std::any_of(typeIter->first.begin(), typeIter->first.end(), ::islower) + ) { typeIter++; continue; } @@ -743,41 +743,41 @@ void ChartToPromela::writeVariables(std::ostream& stream) { typeIter++; } - if (_analyzer->getTypes().types.find("_ioprocessors") != _analyzer->getTypes().types.end()) { - stream << "hidden _ioprocessors_t " << _prefix << "_ioprocessors;" << std::endl; - _varInitializers.push_front("_ioprocessors.scxml.location = " + (_invokerid.size() > 0 ? _analyzer->macroForLiteral(_invokerid) : "1") + ";"); - } + if (_analyzer->getTypes().types.find("_ioprocessors") != _analyzer->getTypes().types.end()) { + stream << "hidden _ioprocessors_t " << _prefix << "_ioprocessors;" << std::endl; + _varInitializers.push_front("_ioprocessors.scxml.location = " + (_invokerid.size() > 0 ? _analyzer->macroForLiteral(_invokerid) : "1") + ";"); + } - stream << "hidden int " << _prefix << "procid; /* the process id running this machine */" << std::endl; + stream << "hidden int " << _prefix << "procid; /* the process id running this machine */" << std::endl; } - + void ChartToPromela::writeStrings(std::ostream& stream) { - stream << "/* states, events and string literals */" << std::endl; - std::set<std::string> literals = _analyzer->getLiterals(); - - { - for (size_t i = 0; i < _states.size(); i++) { - if (HAS_ATTR(_states[i], "id")) { - stream << "#define " << _prefix << _analyzer->macroForLiteral(ATTR(_states[i], "id")) << " " << toStr(i); - stream << " /* index for state " << ATTR(_states[i], "id") << " */" << std::endl; - } - } - } - - { - size_t i = 0; - for (auto machine : *_machinesAll) { - i++; - stream << "#define " << _analyzer->macroForLiteral(machine.second->_invokerid) << " " << toStr(i); - stream << " /* index for invoker " << machine.second->_invokerid << " */" << std::endl; - } - } - - for (auto literal : literals) { - stream << "#define " << _analyzer->macroForLiteral(literal) << " " << _analyzer->indexForLiteral(literal) << " /* " << literal << " */" << std::endl; - } + stream << "/* states, events and string literals */" << std::endl; + std::set<std::string> literals = _analyzer->getLiterals(); + + { + for (size_t i = 0; i < _states.size(); i++) { + if (HAS_ATTR(_states[i], "id")) { + stream << "#define " << _prefix << _analyzer->macroForLiteral(ATTR(_states[i], "id")) << " " << toStr(i); + stream << " /* index for state " << ATTR(_states[i], "id") << " */" << std::endl; + } + } + } + + { + size_t i = 0; + for (auto machine : *_machinesAll) { + i++; + stream << "#define " << _analyzer->macroForLiteral(machine.second->_invokerid) << " " << toStr(i); + stream << " /* index for invoker " << machine.second->_invokerid << " */" << std::endl; + } + } + + for (auto literal : literals) { + stream << "#define " << _analyzer->macroForLiteral(literal) << " " << _analyzer->indexForLiteral(literal) << " /* " << literal << " */" << std::endl; + } } void ChartToPromela::writeTransitions(std::ostream& stream) { @@ -797,7 +797,7 @@ void ChartToPromela::writeTransitions(std::ostream& stream) { stream << " " << _prefix << "transitions[" << toStr(i) << "].target[" << toStr(j) << "] = 1;" << std::endl; } } - + if (!HAS_ATTR(transition, "event")) stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_SPONTANEOUS] = 1;" << std::endl; @@ -898,64 +898,64 @@ void ChartToPromela::writeStates(std::ostream& stream) { } void ChartToPromela::writeRaiseDoneDate(std::ostream& stream, const DOMElement* donedata, size_t indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - std::list<DOMElement*> contents = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "content", donedata); - if (contents.size() > 0) { - auto& content = contents.front(); - - // an expression - if (HAS_ATTR(content, "expr")) { - stream << dataToAssignments(_prefix + "_tmpE.data", Data(ADAPT_SRC(ATTR(content, "expr")), Data::INTERPRETED)); - return; - } - - std::list<DOMNode*> textChilds = DOMUtils::filterChildType(DOMNode::TEXT_NODE, content); - std::stringstream ss; - for (auto text : textChilds) { - ss << X(text->getNodeValue()).str(); - } - - // text childs - std::string value = boost::trim_copy(ss.str()); - if (value.size() > 0) { - Data d = Data::fromJSON(value); - if (!d.empty()) { - stream << dataToAssignments(_prefix + "_tmpE.data", d); - } else { - if (!isNumeric(value.c_str(), 10)) { - stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::VERBATIM)); - } else { - stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::INTERPRETED)); - } - } - return; - } - } - - std::list<DOMElement*> params = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "param", donedata); - if (params.size() > 0) { - Data d; - for (auto& param : params) { - if (!HAS_ATTR(param, "name")) - continue; - std::string name = ATTR(param, "name"); - std::string expr; - if (HAS_ATTR(param, "expr")) { - expr = ATTR(param, "expr"); - } else if (HAS_ATTR(param, "location")) { - expr = ATTR(param, "location"); - } - - d[name] = Data(expr, Data::INTERPRETED); - } - stream << dataToAssignments(_prefix + "_tmpE.data", d); - - } - + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + std::list<DOMElement*> contents = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "content", donedata); + if (contents.size() > 0) { + auto& content = contents.front(); + + // an expression + if (HAS_ATTR(content, "expr")) { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(ADAPT_SRC(ATTR(content, "expr")), Data::INTERPRETED)); + return; + } + + std::list<DOMNode*> textChilds = DOMUtils::filterChildType(DOMNode::TEXT_NODE, content); + std::stringstream ss; + for (auto text : textChilds) { + ss << X(text->getNodeValue()).str(); + } + + // text childs + std::string value = boost::trim_copy(ss.str()); + if (value.size() > 0) { + Data d = Data::fromJSON(value); + if (!d.empty()) { + stream << dataToAssignments(_prefix + "_tmpE.data", d); + } else { + if (!isNumeric(value.c_str(), 10)) { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::VERBATIM)); + } else { + stream << dataToAssignments(_prefix + "_tmpE.data", Data(value, Data::INTERPRETED)); + } + } + return; + } + } + + std::list<DOMElement*> params = DOMUtils::filterChildElements(XML_PREFIX(donedata).str() + "param", donedata); + if (params.size() > 0) { + Data d; + for (auto& param : params) { + if (!HAS_ATTR(param, "name")) + continue; + std::string name = ATTR(param, "name"); + std::string expr; + if (HAS_ATTR(param, "expr")) { + expr = ATTR(param, "expr"); + } else if (HAS_ATTR(param, "location")) { + expr = ATTR(param, "location"); + } + + d[name] = Data(expr, Data::INTERPRETED); + } + stream << dataToAssignments(_prefix + "_tmpE.data", d); + + } + } void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent) { @@ -1049,18 +1049,18 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO writeIfBlock(stream, condChain, indent); } else if(TAGNAME(element) == "assign") { - - std::list<DOMNode*> assignTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, element, true); - assert(assignTexts.size() > 0); - stream << beautifyIndentation(ADAPT_SRC(boost::trim_copy(X(assignTexts.front()->getNodeValue()).str())), indent + 1) << std::endl; - + + std::list<DOMNode*> assignTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, element, true); + assert(assignTexts.size() > 0); + stream << beautifyIndentation(ADAPT_SRC(boost::trim_copy(X(assignTexts.front()->getNodeValue()).str())), indent + 1) << std::endl; + } else if(TAGNAME(element) == "send" || TAGNAME(element) == "raise") { std::string targetQueue; - - stream << padding << "if" << std::endl; - stream << padding << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] || " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; - padding += " "; + stream << padding << "if" << std::endl; + stream << padding << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] || " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + + padding += " "; std::string insertOp = "!"; if (TAGNAME(element) == "raise") { targetQueue = _prefix + "iQ"; @@ -1112,12 +1112,12 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO if (_analyzer->usesEventField("origintype") && !boost::ends_with(targetQueue, "iQ")) { typeAssignSS << padding << " " << _prefix << "_tmpE.origintype = " << _analyzer->macroForLiteral("http://www.w3.org/TR/scxml/#SCXMLEventProcessor") << ";" << std::endl; } - - if (_analyzer->usesEventField("origin") && !boost::ends_with(targetQueue, "iQ")) { - typeAssignSS << padding << " " << _prefix << "_tmpE.origin = " << _analyzer->macroForLiteral(_invokerid) << ";" << std::endl; - } - if (_analyzer->usesEventField("delay")) { + if (_analyzer->usesEventField("origin") && !boost::ends_with(targetQueue, "iQ")) { + typeAssignSS << padding << " " << _prefix << "_tmpE.origin = " << _analyzer->macroForLiteral(_invokerid) << ";" << std::endl; + } + + if (_analyzer->usesEventField("delay")) { #if NEW_DELAY_RESHUFFLE #else // insertOp += "!"; @@ -1198,14 +1198,14 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO } stream << typeAssignSS.str(); - stream << "#if TRACE_EXECUTION" << std::endl; - if (_analyzer->usesComplexEventStruct()) { - stream << "printf(\"%d: Sending " << event << " (%d) to " << targetQueue << "\\n\", _pid, " << _prefix << TMP_EVENT_NAME << " );" << std::endl; - } else { - stream << "printf(\"Sending " << event << " (%d) to " << targetQueue << "\\n\", " << _prefix << TMP_EVENT_NAME << " );" << std::endl; - } - stream << "#endif" << std::endl; - stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + if (_analyzer->usesComplexEventStruct()) { + stream << "printf(\"%d: Sending " << event << " (%d) to " << targetQueue << "\\n\", _pid, " << _prefix << TMP_EVENT_NAME << " );" << std::endl; + } else { + stream << "printf(\"Sending " << event << " (%d) to " << targetQueue << "\\n\", " << _prefix << TMP_EVENT_NAME << " );" << std::endl; + } + stream << "#endif" << std::endl; + stream << std::endl; stream << padding << " " << targetQueue << insertOp << _prefix <<"_tmpE;" << std::endl; @@ -1218,12 +1218,12 @@ void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DO stream << padding << targetQueue << insertOp << event << ";" << std::endl; } } - stream << padding << "skip;" << std::endl; + stream << padding << "skip;" << std::endl; - padding = padding.substr(0, padding.size() - 2); - stream << padding << "}" << std::endl; - stream << padding << ":: else -> skip;" << std::endl; - stream << padding << "fi" << std::endl; + padding = padding.substr(0, padding.size() - 2); + stream << padding << "}" << std::endl; + stream << padding << ":: else -> skip;" << std::endl; + stream << padding << "fi" << std::endl; } else if(TAGNAME(element) == "cancel") { if (HAS_ATTR(element, "sendid")) { @@ -1243,97 +1243,97 @@ void ChartToPromela::writeFSM(std::ostream& stream) { stream << "/* machine microstep function */" << std::endl; stream << "#define " << _prefix << "USCXML_NUMBER_STATES " << _states.size() << std::endl; stream << "#define " << _prefix << "USCXML_NUMBER_TRANS " << _transitions.size() << std::endl; - stream << std::endl; + stream << std::endl; stream << "proctype " << _prefix << "step() { atomic {" << std::endl; - stream << std::endl; - stream << _prefix << "procid = _pid;" << std::endl; - - size_t largestBitWidth = (_states.size() > _transitions.size() ? - BIT_WIDTH(_states.size() + 1) : - BIT_WIDTH(_transitions.size() + 1)); - - stream << "unsigned"; - stream << " i : " << largestBitWidth << ", "; - stream << " j : " << largestBitWidth << ", "; - stream << " k : " << largestBitWidth << ";" << std::endl; - stream << std::endl; - - std::list<DOMElement*> globalScripts = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "script", _scxml, false); - if (globalScripts.size() > 0) { - stream << "/* run global scripts */" << std::endl; - stream << "d_step { " << std::endl; - - for (auto globalScript : globalScripts) { - TRACE_EXECUTION("Processing executable content for global script"); - - writeExecContent(stream, globalScript, 2); - } - stream << "} /* d_step */" << std::endl; - stream << std::endl; - } - - stream << std::endl; - stream << "/* ---------------------------- */" << std::endl; - stream << _prefix << "MICROSTEP:" << std::endl; + stream << std::endl; + stream << _prefix << "procid = _pid;" << std::endl; + + size_t largestBitWidth = (_states.size() > _transitions.size() ? + BIT_WIDTH(_states.size() + 1) : + BIT_WIDTH(_transitions.size() + 1)); + + stream << "unsigned"; + stream << " i : " << largestBitWidth << ", "; + stream << " j : " << largestBitWidth << ", "; + stream << " k : " << largestBitWidth << ";" << std::endl; + stream << std::endl; + + std::list<DOMElement*> globalScripts = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "script", _scxml, false); + if (globalScripts.size() > 0) { + stream << "/* run global scripts */" << std::endl; + stream << "d_step { " << std::endl; + + for (auto globalScript : globalScripts) { + TRACE_EXECUTION("Processing executable content for global script"); + + writeExecContent(stream, globalScript, 2); + } + stream << "} /* d_step */" << std::endl; + stream << std::endl; + } + + stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << _prefix << "MICROSTEP:" << std::endl; stream << "do" << std::endl; stream << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; - stream << " /* Run until machine is finished */" << std::endl; - stream << std::endl; + stream << " /* Run until machine is finished */" << std::endl; + stream << std::endl; - TRACE_EXECUTION("Taking a step"); + TRACE_EXECUTION("Taking a step"); #if 0 - writeFSMRescheduleMachines(stream); - stream << std::endl; - writeFSMMacrostep(stream); - stream << std::endl; - writeFSMDequeueInternalOrSpontaneousEvent(stream); + writeFSMRescheduleMachines(stream); + stream << std::endl; + writeFSMMacrostep(stream); + stream << std::endl; + writeFSMDequeueInternalOrSpontaneousEvent(stream); #else - writeFSMDequeueEvent(stream); + writeFSMDequeueEvent(stream); #endif - stream << std::endl; - stream << "d_step { skip;" << std::endl; - - stream << std::endl; - writeFSMSelectTransitions(stream); - stream << std::endl; - - - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; - stream << " /* only process anything if we found transitions or are on initial entry */" << std::endl; - - writeFSMRememberHistory(stream); - stream << std::endl; - writeFSMEstablishEntrySet(stream); - stream << std::endl; - writeFSMExitStates(stream); - stream << std::endl; - writeFSMTakeTransitions(stream); - stream << std::endl; - writeFSMEnterStates(stream); - stream << std::endl; + stream << std::endl; + stream << "d_step { skip;" << std::endl; + + stream << std::endl; + writeFSMSelectTransitions(stream); + stream << std::endl; + + + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; + stream << " /* only process anything if we found transitions or are on initial entry */" << std::endl; + + writeFSMRememberHistory(stream); + stream << std::endl; + writeFSMEstablishEntrySet(stream); + stream << std::endl; + writeFSMExitStates(stream); + stream << std::endl; + writeFSMTakeTransitions(stream); + stream << std::endl; + writeFSMEnterStates(stream); + stream << std::endl; // TRACE_EXECUTION("Exited States") - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi /* USCXML_CTX_TRANSITION_FOUND */" << std::endl; - stream << " } skip; /* d_step */" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi /* USCXML_CTX_TRANSITION_FOUND */" << std::endl; + stream << " } skip; /* d_step */" << std::endl; - stream << "} /* !USCXML_CTX_FINISHED */" << std::endl; + stream << "} /* !USCXML_CTX_FINISHED */" << std::endl; stream << ":: else -> break;" << std::endl; stream << "od" << std::endl; - stream << std::endl; - - writeFSMTerminateMachine(stream); - stream << std::endl; - - TRACE_EXECUTION("Done"); + stream << std::endl; + + writeFSMTerminateMachine(stream); + stream << std::endl; + + TRACE_EXECUTION("Done"); stream << "} } /* atomic, step() */" << std::endl; @@ -1343,1391 +1343,1391 @@ void ChartToPromela::writeFSM(std::ostream& stream) { #if 0 void ChartToPromela::writeFSMRescheduleMachines(std::ostream& stream) { - if (_analyzer->usesEventField("delay") && _machinesAll->size() > 1) { - stream << " /* Determine machines with smallest delay and set their process priority */" << std::endl; - stream << " scheduleMachines();" << std::endl << std::endl; - stream << std::endl; - - stream << " /* we may return to find ourselves terminated */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; - stream << " goto " << _prefix << "TERMINATE_MACHINE;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - } + if (_analyzer->usesEventField("delay") && _machinesAll->size() > 1) { + stream << " /* Determine machines with smallest delay and set their process priority */" << std::endl; + stream << " scheduleMachines();" << std::endl << std::endl; + stream << std::endl; + + stream << " /* we may return to find ourselves terminated */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; + stream << " goto " << _prefix << "TERMINATE_MACHINE;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + } } - + void ChartToPromela::writeFSMMacrostep(std::ostream& stream) { - - stream << " /* Dequeue an external event */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] = false;" << std::endl; - - stream << " if" << std::endl; - stream << " :: !" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] && len(" << _prefix << "iQ) == 0 -> {" << std::endl; - - stream << " /* manage invocations */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " /* uninvoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; - - TRACE_EXECUTION_V("Uninvoking in state %d", "i"); - - stream << " if" << std::endl; - - for (size_t i = 0; i < _states.size(); i++) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); - if (invokers.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - for (auto invokeElem : invokers) { - if (_machinesNested.find(invokeElem) == _machinesNested.end()) - continue; - ChartToPromela* invoker = _machinesNested[invokeElem]; - stream << " " << invoker->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; - } - stream << " }" << std::endl; - } - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " " << _prefix << "invocations[i] = false;" << std::endl; - - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; - - stream << " /* invoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; - stream << " if" << std::endl; - - for (size_t i = 0; i < _states.size(); i++) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); - if (invokers.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - for (auto invokeElem : invokers) { - if (_machinesNested.find(invokeElem) == _machinesNested.end()) - continue; - ChartToPromela* invoker = _machinesNested[invokeElem]; - - // pass variables via namelist - if (HAS_ATTR(invokeElem, "namelist")) { - std::list<std::string> namelist = tokenize(ATTR_CAST(invokeElem, "namelist")); - for (auto name : namelist) { - if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { - stream << " " << invoker->_prefix << name << " = " << _prefix << name << ";" << std::endl; - } - } - } - - // pass variables via params - std::list<DOMElement*> invokeParams = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + + "param", invokeElem); - for (auto param : invokeParams) { - std::string name = ATTR(param, "name"); - std::string expression = ATTR(param, "expr"); - if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { - stream << " " << invoker->_prefix << name << " = " << ADAPT_SRC(expression) << ";" << std::endl; - } - } - - TRACE_EXECUTION_V("Invoking in state %d", "i"); - - stream << " run " << invoker->_prefix << "step() priority 20;" << std::endl; - if (HAS_ATTR(invokeElem, "idlocation")) { - stream << " " << ADAPT_SRC(ATTR(invokeElem, "idlocation")) << " = "; - stream << _analyzer->macroForLiteral(invoker->_invokerid) << ";" << std::endl; - } - - } - stream << " " << _prefix << "invocations[i] = true;" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - } - - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << " /* Not sure if this should be before the invocation due to auto-forwarding */" << std::endl; - stream << " do" << std::endl; - stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; - stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; - - if (_machinesNested.size() > 0) { - stream << std::endl; - stream << " /* auto-forward event */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - - std::string insertOp = "!"; - if (_analyzer->usesEventField("delay")) { - // insertOp += "!"; - } - - - for (auto state : _states) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "invoke", state, false); - if (invokers.size() > 0) { - stream << " :: i == " << ATTR(state, "documentOrder") << " && " << _prefix << "invocations[i] -> { " << std::endl; - for (auto invoker : invokers) { - assert(_machinesNested.find(invoker) != _machinesNested.end()); - if (HAS_ATTR(invoker, "autoforward") && stringIsTrue(ATTR(invoker, "autoforward"))) { - stream << " " << _machinesNested[invoker]->_prefix << "eQ " << insertOp << " " << _prefix << "_event;" << std::endl; - if (_analyzer->usesEventField("delay")) { - stream << " insertWithDelay(" << _machinesNested[invoker]->_prefix << "eQ);" << std::endl; - } - TRACE_EXECUTION("Auto forwarded event"); - } - } - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - } - - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - - stream << std::endl; - stream << " /* finalize event */" << std::endl; - stream << " if" << std::endl; - - for (auto machine : _machinesNested) { - - stream << " :: " << _prefix << "_event.invokeid == " << _analyzer->macroForLiteral(machine.second->_invokerid) << " -> {" << std::endl; - std::list<DOMElement*> finalizers = DOMUtils::filterChildElements(XML_PREFIX(machine.first).str() + "finalize", machine.first, false); - - TRACE_EXECUTION("Finalizing event") - - for (auto finalize : finalizers) { - writeExecContent(stream, finalize, 4); - } - stream << " skip" << std::endl; - stream << " }" << std::endl; - } - stream << " :: else -> skip;" << std::endl; - - stream << " fi" << std::endl; - - } - - TRACE_EXECUTION("Deqeued an external event"); - stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] = true;" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; - // stream << " :: else -> quit;" << std::endl; - stream << " od;" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; + + stream << " /* Dequeue an external event */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] = false;" << std::endl; + + stream << " if" << std::endl; + stream << " :: !" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] && len(" << _prefix << "iQ) == 0 -> {" << std::endl; + + stream << " /* manage invocations */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " /* uninvoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; + + TRACE_EXECUTION_V("Uninvoking in state %d", "i"); + + stream << " if" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + stream << " " << invoker->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + } + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " " << _prefix << "invocations[i] = false;" << std::endl; + + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << " /* invoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; + stream << " if" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + + // pass variables via namelist + if (HAS_ATTR(invokeElem, "namelist")) { + std::list<std::string> namelist = tokenize(ATTR_CAST(invokeElem, "namelist")); + for (auto name : namelist) { + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << _prefix << name << ";" << std::endl; + } + } + } + + // pass variables via params + std::list<DOMElement*> invokeParams = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + + "param", invokeElem); + for (auto param : invokeParams) { + std::string name = ATTR(param, "name"); + std::string expression = ATTR(param, "expr"); + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << ADAPT_SRC(expression) << ";" << std::endl; + } + } + + TRACE_EXECUTION_V("Invoking in state %d", "i"); + + stream << " run " << invoker->_prefix << "step() priority 20;" << std::endl; + if (HAS_ATTR(invokeElem, "idlocation")) { + stream << " " << ADAPT_SRC(ATTR(invokeElem, "idlocation")) << " = "; + stream << _analyzer->macroForLiteral(invoker->_invokerid) << ";" << std::endl; + } + + } + stream << " " << _prefix << "invocations[i] = true;" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + stream << std::endl; + + stream << " /* Not sure if this should be before the invocation due to auto-forwarding */" << std::endl; + stream << " do" << std::endl; + stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; + + if (_machinesNested.size() > 0) { + stream << std::endl; + stream << " /* auto-forward event */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + + std::string insertOp = "!"; + if (_analyzer->usesEventField("delay")) { + // insertOp += "!"; + } + + + for (auto state : _states) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "invoke", state, false); + if (invokers.size() > 0) { + stream << " :: i == " << ATTR(state, "documentOrder") << " && " << _prefix << "invocations[i] -> { " << std::endl; + for (auto invoker : invokers) { + assert(_machinesNested.find(invoker) != _machinesNested.end()); + if (HAS_ATTR(invoker, "autoforward") && stringIsTrue(ATTR(invoker, "autoforward"))) { + stream << " " << _machinesNested[invoker]->_prefix << "eQ " << insertOp << " " << _prefix << "_event;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << " insertWithDelay(" << _machinesNested[invoker]->_prefix << "eQ);" << std::endl; + } + TRACE_EXECUTION("Auto forwarded event"); + } + } + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + + stream << std::endl; + stream << " /* finalize event */" << std::endl; + stream << " if" << std::endl; + + for (auto machine : _machinesNested) { + + stream << " :: " << _prefix << "_event.invokeid == " << _analyzer->macroForLiteral(machine.second->_invokerid) << " -> {" << std::endl; + std::list<DOMElement*> finalizers = DOMUtils::filterChildElements(XML_PREFIX(machine.first).str() + "finalize", machine.first, false); + + TRACE_EXECUTION("Finalizing event") + + for (auto finalize : finalizers) { + writeExecContent(stream, finalize, 4); + } + stream << " skip" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + + stream << " fi" << std::endl; + + } + + TRACE_EXECUTION("Deqeued an external event"); + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] = true;" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + // stream << " :: else -> quit;" << std::endl; + stream << " od;" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; } - + void ChartToPromela::writeFSMDequeueInternalOrSpontaneousEvent(std::ostream& stream) { - stream << " if" << std::endl; - stream << " :: !" << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] -> {" << std::endl; - stream << " /* Try with a spontaneous event or dequeue an internal event */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; - stream << " /* We try with a spontaneous event */" << std::endl; - stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " /* We try with an internal event */" << std::endl; - stream << " assert(len(" << _prefix << "iQ) > 0);" << std::endl; - stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "flags[USCXML_CTX_DEQUEUED_EXTERNAL] -> {" << std::endl; + stream << " /* Try with a spontaneous event or dequeue an internal event */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; + stream << " /* We try with a spontaneous event */" << std::endl; + stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " /* We try with an internal event */" << std::endl; + stream << " assert(len(" << _prefix << "iQ) > 0);" << std::endl; + stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; } #endif - + #if 1 void ChartToPromela::writeFSMDequeueEvent(std::ostream& stream) { - stream << " /* Dequeue an event */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = false;" << std::endl; - stream << " if" << std::endl; - stream << " ::" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; - stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; - - TRACE_EXECUTION("Trying with a spontaneous event"); - - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: len(" << _prefix << "iQ) != 0 -> {" << std::endl; - stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; - - TRACE_EXECUTION("Deqeued an internal event"); - - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = true;" << std::endl; - stream << " }" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; - - stream << std::endl; - - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] -> {" << std::endl; - stream << " /* manage invocations */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " d_step { " << std::endl; - stream << " /* uninvoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; - - TRACE_EXECUTION_V("Uninvoking in state %d", "i"); - - stream << " if" << std::endl; - - for (size_t i = 0; i < _states.size(); i++) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); - if (invokers.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - for (auto invokeElem : invokers) { - if (_machinesNested.find(invokeElem) == _machinesNested.end()) - continue; - ChartToPromela* invoker = _machinesNested[invokeElem]; - stream << " " << invoker->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; - } - stream << " }" << std::endl; - } - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " " << _prefix << "invocations[i] = false;" << std::endl; - - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " } /* d_step */" << std::endl; - - stream << std::endl; - - - - stream << " /* invoke */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; - stream << " if" << std::endl; - - for (size_t i = 0; i < _states.size(); i++) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); - if (invokers.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - for (auto invokeElem : invokers) { - if (_machinesNested.find(invokeElem) == _machinesNested.end()) - continue; - ChartToPromela* invoker = _machinesNested[invokeElem]; - - // pass variables via namelist - if (HAS_ATTR(invokeElem, "namelist")) { - std::list<std::string> namelist = tokenize(ATTR_CAST(invokeElem, "namelist")); - for (auto name : namelist) { - if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { - stream << " " << invoker->_prefix << name << " = " << _prefix << name << ";" << std::endl; - } - } - } - - // pass variables via params - std::list<DOMElement*> invokeParams = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + + "param", invokeElem); - for (auto param : invokeParams) { - std::string name = ATTR(param, "name"); - std::string expression = ATTR(param, "expr"); - if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { - stream << " " << invoker->_prefix << name << " = " << ADAPT_SRC(expression) << ";" << std::endl; - } - } - - TRACE_EXECUTION_V("Invoking in state %d", "i"); - - stream << " run " << invoker->_prefix << "step() priority 20;" << std::endl; - if (HAS_ATTR(invokeElem, "idlocation")) { - stream << " " << ADAPT_SRC(ATTR(invokeElem, "idlocation")) << " = "; - stream << _analyzer->macroForLiteral(invoker->_invokerid) << ";" << std::endl; - } - - } - stream << " " << _prefix << "invocations[i] = true;" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - } - - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - - stream << std::endl; - - if (_analyzer->usesEventField("delay") && _machinesAll->size() > 1) { - stream << " /* Determine machines with smallest delay and set their process priority */" << std::endl; - stream << " scheduleMachines();" << std::endl << std::endl; - } - - stream << " /* we may return to find ourselves terminated */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; - stream << " goto " << _prefix << "TERMINATE_MACHINE;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - - stream << " /* Not sure if this should be before the invocation due to auto-forwarding */" << std::endl; - stream << " if" << std::endl; - stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; - stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; - - if (_machinesNested.size() > 0) { - stream << std::endl; - stream << " d_step {" << std::endl; - stream << " /* auto-forward event */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - - std::string insertOp = "!"; - if (_analyzer->usesEventField("delay")) { - // insertOp += "!"; - } - - - for (auto state : _states) { - std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "invoke", state, false); - if (invokers.size() > 0) { - stream << " :: i == " << ATTR(state, "documentOrder") << " && " << _prefix << "invocations[i] -> { " << std::endl; - for (auto invoker : invokers) { - assert(_machinesNested.find(invoker) != _machinesNested.end()); - if (HAS_ATTR(invoker, "autoforward") && stringIsTrue(ATTR(invoker, "autoforward"))) { - stream << " " << _machinesNested[invoker]->_prefix << "eQ " << insertOp << " " << _prefix << "_event;" << std::endl; - if (_analyzer->usesEventField("delay")) { - stream << " insertWithDelay(" << _machinesNested[invoker]->_prefix << "eQ);" << std::endl; - } - TRACE_EXECUTION("Auto forwarded event"); - } - } - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - } - - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - - stream << std::endl; - stream << " /* finalize event */" << std::endl; - stream << " if" << std::endl; - - for (auto machine : _machinesNested) { - - stream << " :: " << _prefix << "_event.invokeid == " << _analyzer->macroForLiteral(machine.second->_invokerid) << " -> {" << std::endl; - std::list<DOMElement*> finalizers = DOMUtils::filterChildElements(XML_PREFIX(machine.first).str() + "finalize", machine.first, false); - - TRACE_EXECUTION("Finalizing event") - - for (auto finalize : finalizers) { - writeExecContent(stream, finalize, 4); - } - stream << " skip" << std::endl; - stream << " }" << std::endl; - } - stream << " :: else -> skip;" << std::endl; - - stream << " fi" << std::endl; - stream << " } /* d_step */" << std::endl; - - } - - TRACE_EXECUTION("Deqeued an external event"); - - stream << " }" << std::endl; - // stream << " :: else -> quit;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; + stream << " /* Dequeue an event */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = false;" << std::endl; + stream << " if" << std::endl; + stream << " ::" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; + stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; + + TRACE_EXECUTION("Trying with a spontaneous event"); + + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "iQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; + + TRACE_EXECUTION("Deqeued an internal event"); + + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] = true;" << std::endl; + stream << " }" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_DEQUEUE_EXTERNAL] -> {" << std::endl; + stream << " /* manage invocations */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " d_step { " << std::endl; + stream << " /* uninvoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << std::endl; + + TRACE_EXECUTION_V("Uninvoking in state %d", "i"); + + stream << " if" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + stream << " " << invoker->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + } + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " " << _prefix << "invocations[i] = false;" << std::endl; + + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " } /* d_step */" << std::endl; + + stream << std::endl; + + + + stream << " /* invoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "config[i] && !" << _prefix << "invocations[i] -> {" << std::endl; + stream << " if" << std::endl; + + for (size_t i = 0; i < _states.size(); i++) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "invoke" , _states[i]); + if (invokers.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + for (auto invokeElem : invokers) { + if (_machinesNested.find(invokeElem) == _machinesNested.end()) + continue; + ChartToPromela* invoker = _machinesNested[invokeElem]; + + // pass variables via namelist + if (HAS_ATTR(invokeElem, "namelist")) { + std::list<std::string> namelist = tokenize(ATTR_CAST(invokeElem, "namelist")); + for (auto name : namelist) { + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << _prefix << name << ";" << std::endl; + } + } + } + + // pass variables via params + std::list<DOMElement*> invokeParams = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + + "param", invokeElem); + for (auto param : invokeParams) { + std::string name = ATTR(param, "name"); + std::string expression = ATTR(param, "expr"); + if (invoker->_dataModelVars.find(name) != invoker->_dataModelVars.end()) { + stream << " " << invoker->_prefix << name << " = " << ADAPT_SRC(expression) << ";" << std::endl; + } + } + + TRACE_EXECUTION_V("Invoking in state %d", "i"); + + stream << " run " << invoker->_prefix << "step() priority 20;" << std::endl; + if (HAS_ATTR(invokeElem, "idlocation")) { + stream << " " << ADAPT_SRC(ATTR(invokeElem, "idlocation")) << " = "; + stream << _analyzer->macroForLiteral(invoker->_invokerid) << ";" << std::endl; + } + + } + stream << " " << _prefix << "invocations[i] = true;" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + + stream << std::endl; + + if (_analyzer->usesEventField("delay") && _machinesAll->size() > 1) { + stream << " /* Determine machines with smallest delay and set their process priority */" << std::endl; + stream << " scheduleMachines();" << std::endl << std::endl; + } + + stream << " /* we may return to find ourselves terminated */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; + stream << " goto " << _prefix << "TERMINATE_MACHINE;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + + stream << " /* Not sure if this should be before the invocation due to auto-forwarding */" << std::endl; + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; + + if (_machinesNested.size() > 0) { + stream << std::endl; + stream << " d_step {" << std::endl; + stream << " /* auto-forward event */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + + std::string insertOp = "!"; + if (_analyzer->usesEventField("delay")) { + // insertOp += "!"; + } + + + for (auto state : _states) { + std::list<DOMElement*> invokers = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "invoke", state, false); + if (invokers.size() > 0) { + stream << " :: i == " << ATTR(state, "documentOrder") << " && " << _prefix << "invocations[i] -> { " << std::endl; + for (auto invoker : invokers) { + assert(_machinesNested.find(invoker) != _machinesNested.end()); + if (HAS_ATTR(invoker, "autoforward") && stringIsTrue(ATTR(invoker, "autoforward"))) { + stream << " " << _machinesNested[invoker]->_prefix << "eQ " << insertOp << " " << _prefix << "_event;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << " insertWithDelay(" << _machinesNested[invoker]->_prefix << "eQ);" << std::endl; + } + TRACE_EXECUTION("Auto forwarded event"); + } + } + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + + stream << std::endl; + stream << " /* finalize event */" << std::endl; + stream << " if" << std::endl; + + for (auto machine : _machinesNested) { + + stream << " :: " << _prefix << "_event.invokeid == " << _analyzer->macroForLiteral(machine.second->_invokerid) << " -> {" << std::endl; + std::list<DOMElement*> finalizers = DOMUtils::filterChildElements(XML_PREFIX(machine.first).str() + "finalize", machine.first, false); + + TRACE_EXECUTION("Finalizing event") + + for (auto finalize : finalizers) { + writeExecContent(stream, finalize, 4); + } + stream << " skip" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + + stream << " fi" << std::endl; + stream << " } /* d_step */" << std::endl; + + } + + TRACE_EXECUTION("Deqeued an external event"); + + stream << " }" << std::endl; + // stream << " :: else -> quit;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; } #endif void ChartToPromela::writeFSMSelectTransitions(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << _prefix << "SELECT_TRANSITIONS:" << std::endl; - - stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.target_set)" << std::endl; - stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.exit_set)" << std::endl; - - if (_transitions.size() > 0) { - stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.conflicts)" << std::endl; - stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.trans_set)" << std::endl; - - stream << "#if TRACE_EXECUTION" << std::endl; - if (_machinesAll->size() > 1) { - stream << "printf(\"%d: Establishing optimal transition set for event %d\\n\", _pid, " << _prefix << EVENT_NAME << " );" << std::endl; - } else { - stream << "printf(\"Establishing optimal transition set for event %d\\n\", " << _prefix << EVENT_NAME << " );" << std::endl; - } - stream << "#endif" << std::endl; - stream << std::endl; - - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Configuration: \");" << std::endl; - printBitArray(stream, _prefix + "config", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; - - stream << " /* only select non-history, non-initial transitions */" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] &&" << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; - - stream << " if" << std::endl; - stream << " :: /* is the transition active? */" << std::endl; - stream << " " << _prefix << "config[" << _prefix << "transitions[i].source] && " << std::endl; - stream << std::endl; - stream << " /* is it non-conflicting? */" << std::endl; - stream << " !" << _prefix << "ctx.conflicts[i] && " << std::endl; - stream << std::endl; - stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; - stream << " ((" << _prefix << EVENT_NAME << " == USCXML_EVENT_SPONTANEOUS && " << std::endl; - stream << " " << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS]) || " << std::endl; - stream << " (" << _prefix << EVENT_NAME << " != USCXML_EVENT_SPONTANEOUS && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS])) &&" << std::endl; - stream << std::endl; - stream << " /* is it matching and enabled? */" << std::endl; - stream << " (false " << std::endl; - - - for (auto i = 0; i < _transitions.size(); i++) { - stream << " || (i == " << toStr(i); - if (HAS_ATTR(_transitions[i], "event") && ATTR(_transitions[i], "event") != "*") { - stream << " && (false"; - std::list<std::string> eventLiterals = tokenize(ATTR(_transitions[i], "event")); - for (auto eventLiteral : eventLiterals) { - if (boost::ends_with(eventLiteral, ".*")) { - eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 2); - } - if (boost::ends_with(eventLiteral, ".")) { - eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 1); - } - std::list<TrieNode*> events =_analyzer->getTrie().getWordsWithPrefix(eventLiteral); - for (auto event : events) { - stream << " || " << _prefix << EVENT_NAME << " == " << _analyzer->macroForLiteral(event->value); - } - } - stream << ")"; - } - if (HAS_ATTR(_transitions[i], "cond")) { - stream << " && " << ADAPT_SRC(ATTR(_transitions[i], "cond")); - } - stream << ")" << std::endl; - } - - stream << " ) -> {" << std::endl; - - stream << " /* remember that we found a transition */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; - stream << std::endl; - - stream << " /* transitions that are pre-empted */" << std::endl; - stream << " " << _prefix << "TRANS_OR(" << _prefix << "ctx.conflicts, " << _prefix << "transitions[i].conflicts)" << std::endl; - stream << std::endl; - - stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.target_set, " << _prefix << "transitions[i].target)" << std::endl; - stream << std::endl; - - stream << " /* states that will be left */" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.exit_set, " << _prefix << "transitions[i].exit_set)" << std::endl; - stream << std::endl; - - stream << " " << _prefix << "ctx.trans_set[i] = true;" << std::endl; - - - stream << " }" << std::endl; - stream << " :: else {" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - - stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.exit_set, " << _prefix << "config)" << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Selected Transitions: \");" << std::endl; - printBitArray(stream, _prefix + "ctx.trans_set", _transitions.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - } - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Target Set: \");" << std::endl; - printBitArray(stream, _prefix + "ctx.target_set", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Exit Set: \");" << std::endl; - printBitArray(stream, _prefix + "ctx.exit_set", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - - stream << " if" << std::endl; - stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; - stream << " /* Enter initial configuration */" << std::endl; - stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.target_set, " << _prefix << "states[0].completion)" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; - - TRACE_EXECUTION("Entering initial default completion"); - - // stream << " goto " << _prefix << "ESTABLISH_ENTRY_SET;" << std::endl; - stream << std::endl; - - stream << " }" << std::endl; - stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; - - TRACE_EXECUTION("Found transitions"); - - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; - stream << " }" << std::endl; - stream << " :: else {" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = false;" << std::endl; - - TRACE_EXECUTION("Found NO transitions"); - - // stream << " goto " << _prefix << "MICROSTEP;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << _prefix << "SELECT_TRANSITIONS:" << std::endl; + + stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.target_set)" << std::endl; + stream << _prefix << "STATES_CLEAR(" << _prefix << "ctx.exit_set)" << std::endl; + + if (_transitions.size() > 0) { + stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.conflicts)" << std::endl; + stream << _prefix << "TRANS_CLEAR(" << _prefix << "ctx.trans_set)" << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + if (_machinesAll->size() > 1) { + stream << "printf(\"%d: Establishing optimal transition set for event %d\\n\", _pid, " << _prefix << EVENT_NAME << " );" << std::endl; + } else { + stream << "printf(\"Establishing optimal transition set for event %d\\n\", " << _prefix << EVENT_NAME << " );" << std::endl; + } + stream << "#endif" << std::endl; + stream << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Configuration: \");" << std::endl; + printBitArray(stream, _prefix + "config", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + + stream << " /* only select non-history, non-initial transitions */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] &&" << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: /* is the transition active? */" << std::endl; + stream << " " << _prefix << "config[" << _prefix << "transitions[i].source] && " << std::endl; + stream << std::endl; + stream << " /* is it non-conflicting? */" << std::endl; + stream << " !" << _prefix << "ctx.conflicts[i] && " << std::endl; + stream << std::endl; + stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; + stream << " ((" << _prefix << EVENT_NAME << " == USCXML_EVENT_SPONTANEOUS && " << std::endl; + stream << " " << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS]) || " << std::endl; + stream << " (" << _prefix << EVENT_NAME << " != USCXML_EVENT_SPONTANEOUS && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_SPONTANEOUS])) &&" << std::endl; + stream << std::endl; + stream << " /* is it matching and enabled? */" << std::endl; + stream << " (false " << std::endl; + + + for (auto i = 0; i < _transitions.size(); i++) { + stream << " || (i == " << toStr(i); + if (HAS_ATTR(_transitions[i], "event") && ATTR(_transitions[i], "event") != "*") { + stream << " && (false"; + std::list<std::string> eventLiterals = tokenize(ATTR(_transitions[i], "event")); + for (auto eventLiteral : eventLiterals) { + if (boost::ends_with(eventLiteral, ".*")) { + eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 2); + } + if (boost::ends_with(eventLiteral, ".")) { + eventLiteral = eventLiteral.substr(0, eventLiteral.size() - 1); + } + std::list<TrieNode*> events =_analyzer->getTrie().getWordsWithPrefix(eventLiteral); + for (auto event : events) { + stream << " || " << _prefix << EVENT_NAME << " == " << _analyzer->macroForLiteral(event->value); + } + } + stream << ")"; + } + if (HAS_ATTR(_transitions[i], "cond")) { + stream << " && " << ADAPT_SRC(ATTR(_transitions[i], "cond")); + } + stream << ")" << std::endl; + } + + stream << " ) -> {" << std::endl; + + stream << " /* remember that we found a transition */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; + stream << std::endl; + + stream << " /* transitions that are pre-empted */" << std::endl; + stream << " " << _prefix << "TRANS_OR(" << _prefix << "ctx.conflicts, " << _prefix << "transitions[i].conflicts)" << std::endl; + stream << std::endl; + + stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.target_set, " << _prefix << "transitions[i].target)" << std::endl; + stream << std::endl; + + stream << " /* states that will be left */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.exit_set, " << _prefix << "transitions[i].exit_set)" << std::endl; + stream << std::endl; + + stream << " " << _prefix << "ctx.trans_set[i] = true;" << std::endl; + + + stream << " }" << std::endl; + stream << " :: else {" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.exit_set, " << _prefix << "config)" << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Selected Transitions: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.trans_set", _transitions.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + } + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Target Set: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.target_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Exit Set: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.exit_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; + stream << " /* Enter initial configuration */" << std::endl; + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.target_set, " << _prefix << "states[0].completion)" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = true;" << std::endl; + + TRACE_EXECUTION("Entering initial default completion"); + + // stream << " goto " << _prefix << "ESTABLISH_ENTRY_SET;" << std::endl; + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; + + TRACE_EXECUTION("Found transitions"); + + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << " }" << std::endl; + stream << " :: else {" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = false;" << std::endl; + + TRACE_EXECUTION("Found NO transitions"); + + // stream << " goto " << _prefix << "MICROSTEP;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; } void ChartToPromela::writeFSMRememberHistory(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << "/* REMEMBER_HISTORY: */" << std::endl; - TRACE_EXECUTION("Save history configurations"); - - stream << " if" << std::endl; - stream << " :: " << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; - stream << " /* only remember history on non-initial entry */" << std::endl; - - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; - stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "ctx.exit_set[" << _prefix << "states[i].parent] -> {" << std::endl; - - stream << " /* a history state whose parent is about to be exited */" << std::endl; - TRACE_EXECUTION_V("history state %d is about to be exited", "i"); - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"COMPLET: \");" << std::endl; - printBitArray(stream, _prefix + "states[i].completion", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - - stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; - - stream << std::endl; - stream << " /* set those states who were enabled */" << std::endl; - stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "config)" << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"CONFIG : \");" << std::endl; - printBitArray(stream, _prefix + "config", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"TMP_STS: \");" << std::endl; - printBitArray(stream, _prefix + "ctx.tmp_states", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; - - stream << std::endl; - stream << " /* clear current history with completion mask */" << std::endl; - stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "history, " << _prefix << "states[i].completion)" << std::endl; - stream << std::endl; - - stream << " /* set history */" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "history, " << _prefix << "ctx.tmp_states)" << std::endl; - - stream << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"History: \");" << std::endl; - printBitArray(stream, _prefix + "history", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << "/* REMEMBER_HISTORY: */" << std::endl; + TRACE_EXECUTION("Save history configurations"); + + stream << " if" << std::endl; + stream << " :: " << _prefix << "STATES_HAS_ANY(" << _prefix << "config) -> {" << std::endl; + stream << " /* only remember history on non-initial entry */" << std::endl; + + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; + stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.exit_set[" << _prefix << "states[i].parent] -> {" << std::endl; + + stream << " /* a history state whose parent is about to be exited */" << std::endl; + TRACE_EXECUTION_V("history state %d is about to be exited", "i"); + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"COMPLET: \");" << std::endl; + printBitArray(stream, _prefix + "states[i].completion", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; + + stream << std::endl; + stream << " /* set those states who were enabled */" << std::endl; + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "config)" << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"CONFIG : \");" << std::endl; + printBitArray(stream, _prefix + "config", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"TMP_STS: \");" << std::endl; + printBitArray(stream, _prefix + "ctx.tmp_states", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << " /* clear current history with completion mask */" << std::endl; + stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "history, " << _prefix << "states[i].completion)" << std::endl; + stream << std::endl; + + stream << " /* set history */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "history, " << _prefix << "ctx.tmp_states)" << std::endl; + + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"History: \");" << std::endl; + printBitArray(stream, _prefix + "history", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; } - + void ChartToPromela::writeFSMEstablishEntrySet(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << _prefix << "ESTABLISH_ENTRY_SET:" << std::endl; - stream << " /* calculate new entry set */" << std::endl; - stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.target_set)" << std::endl; - stream << std::endl; - - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - - stream << " if" << std::endl; - stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; - stream << " /* ancestor completion */" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].ancestors)" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << " /* iterate for descendants */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; - stream << " if" << std::endl; - - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_PARALLEL] -> {" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; - stream << " }" << std::endl; - - - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; - stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; - - TRACE_EXECUTION_V("Descendant completion for history state %d", "i") - - stream << " if" << std::endl; - stream << " :: !" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "history)"; - // bit_has_and(stream, _prefix + "states[i].completion", _prefix + "history", _states.size(), 5); - stream << " && !" << _prefix << "config[" << _prefix << "states[i].parent]" << " -> {" << std::endl; - stream << " /* nothing set for history, look for a default transition */" << std::endl; - TRACE_EXECUTION("Fresh history in target set") - if (_transitions.size() > 0) { - stream << " j = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; - stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; - - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; - stream << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] &&" << std::endl; - stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "transitions[j].target, " << _prefix << "states[i].children)"; - // bit_has_and(stream, _prefix + "transitions[j].target", _prefix + "states[i].children", _states.size(), 10); - stream << " ) -> {" << std::endl; - stream << " k = i + 1" << std::endl; - stream << " do" << std::endl; - stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; - stream << " break;" << std::endl; - stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " k = k + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " break;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od" << std::endl; - } - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - - TRACE_EXECUTION("Established history in target set") - stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; - stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "history)" << std::endl; - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.tmp_states)" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HAS_HISTORY] ||" << std::endl; - stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> { " << std::endl; - stream << " /* a deep history state with nested histories -> more completion */" << std::endl; - TRACE_EXECUTION("DEEP HISTORY") - stream << " j = i + 1;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "states[i].completion[j] &&" << std::endl; - stream << " " << _prefix << "ctx.entry_set[j] && " << std::endl; - stream << " " << _prefix << "states[j].type[USCXML_STATE_HAS_HISTORY]) -> {" << std::endl; - stream << " k = j + 1;" << std::endl; - stream << " do" << std::endl; - stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " /* add nested history to entry_set */" << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "states[k].type[USCXML_STATE_HISTORY_DEEP] ||" << std::endl; - stream << " " << _prefix << "states[k].type[USCXML_STATE_HISTORY_SHALLOW]) &&" << std::endl; - stream << " " << _prefix << "states[j].children[k] -> {" << std::endl; - stream << " /* a nested history state */" << std::endl; - stream << " " << _prefix << "ctx.entry_set[k] = true;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " k = k + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " }" << std::endl; - stream << " fi;" << std::endl; - - stream << " }" << std::endl; - - if (_transitions.size() > 0) { - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_INITIAL] -> {" << std::endl; - - TRACE_EXECUTION_V("Descendant completion for initial state %d", "i") - - stream << " j = 0" << std::endl; - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; - stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; - stream << " " << _prefix << "ctx.entry_set[i] = false;" << std::endl; - - TRACE_EXECUTION_V("Adding transition %d!", "j"); - - - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; - stream << std::endl; - - stream << " k = i + 1;" << std::endl; - stream << " do" << std::endl; - stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; - - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; - stream << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " fi" << std::endl; - stream << " k = k + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break" << std::endl; - stream << " od;" << std::endl; - - stream << " }" << std::endl; - } - - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_COMPOUND] -> {" << std::endl; - - // TRACE_EXECUTION_V("Descendant completion for compound state %d", "i") - - stream << " /* we need to check whether one child is already in entry_set */" << std::endl; - stream << " if" << std::endl; - stream << " :: (" << std::endl; - stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].children)"; - stream << " && " << std::endl; - stream << " (!" << _prefix << "STATES_HAS_AND(" << _prefix << "config, " << _prefix << "states[i].children)"; - // bit_has_and(stream, _prefix + "config", _prefix + "states[i].children", _states.size(), 5); - stream << " || " << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.exit_set, " << _prefix << "states[i].children)" << std::endl; - stream << ")) " << std::endl; - stream << " -> {" << std::endl; - - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; - - stream << " if" << std::endl; - stream << " :: (" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "states[i].children)"; - // bit_has_and(stream, _prefix + "states[i].completion", _prefix + "states[i].children", _states.size(), 6); - stream << std::endl; - stream << " ) -> {" << std::endl; - stream << " /* deep completion */" << std::endl; - stream << " j = i + 1;" << std::endl; - - // TRACE_EXECUTION_V("Deep completion for compound state %d", "i") - - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES - 1 -> {" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].completion[j] -> {" << std::endl; - - stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[j].ancestors)" << std::endl; - stream << std::endl; - - stream << " /* completion of compound is single state */" << std::endl; - stream << " break;" << std::endl; - stream << " } " << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; - - stream << std::endl; - stream << "#if TRACE_EXECUTION" << std::endl; - stream << "printf(\"Entry Set\");" << std::endl; - printBitArray(stream, _prefix + "ctx.entry_set", _states.size()); - stream << "printf(\"\\n\");" << std::endl; - stream << "#endif" << std::endl; - stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << _prefix << "ESTABLISH_ENTRY_SET:" << std::endl; + stream << " /* calculate new entry set */" << std::endl; + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.target_set)" << std::endl; + stream << std::endl; + + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; + stream << " /* ancestor completion */" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].ancestors)" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + stream << std::endl; + + stream << " /* iterate for descendants */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.entry_set[i] -> {" << std::endl; + stream << " if" << std::endl; + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_PARALLEL] -> {" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; + stream << " }" << std::endl; + + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] ||" << std::endl; + stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> {" << std::endl; + + TRACE_EXECUTION_V("Descendant completion for history state %d", "i") + + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "history)"; + // bit_has_and(stream, _prefix + "states[i].completion", _prefix + "history", _states.size(), 5); + stream << " && !" << _prefix << "config[" << _prefix << "states[i].parent]" << " -> {" << std::endl; + stream << " /* nothing set for history, look for a default transition */" << std::endl; + TRACE_EXECUTION("Fresh history in target set") + if (_transitions.size() > 0) { + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; + stream << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] &&" << std::endl; + stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "transitions[j].target, " << _prefix << "states[i].children)"; + // bit_has_and(stream, _prefix + "transitions[j].target", _prefix + "states[i].children", _states.size(), 10); + stream << " ) -> {" << std::endl; + stream << " k = i + 1" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; + stream << " break;" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od" << std::endl; + } + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + + TRACE_EXECUTION("Established history in target set") + stream << " " << _prefix << "STATES_COPY(" << _prefix << "ctx.tmp_states, " << _prefix << "states[i].completion)" << std::endl; + stream << " " << _prefix << "STATES_AND(" << _prefix << "ctx.tmp_states, " << _prefix << "history)" << std::endl; + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "ctx.tmp_states)" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_HAS_HISTORY] ||" << std::endl; + stream << " " << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] -> { " << std::endl; + stream << " /* a deep history state with nested histories -> more completion */" << std::endl; + TRACE_EXECUTION("DEEP HISTORY") + stream << " j = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[i].completion[j] &&" << std::endl; + stream << " " << _prefix << "ctx.entry_set[j] && " << std::endl; + stream << " " << _prefix << "states[j].type[USCXML_STATE_HAS_HISTORY]) -> {" << std::endl; + stream << " k = j + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " /* add nested history to entry_set */" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[k].type[USCXML_STATE_HISTORY_DEEP] ||" << std::endl; + stream << " " << _prefix << "states[k].type[USCXML_STATE_HISTORY_SHALLOW]) &&" << std::endl; + stream << " " << _prefix << "states[j].children[k] -> {" << std::endl; + stream << " /* a nested history state */" << std::endl; + stream << " " << _prefix << "ctx.entry_set[k] = true;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " }" << std::endl; + stream << " fi;" << std::endl; + + stream << " }" << std::endl; + + if (_transitions.size() > 0) { + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_INITIAL] -> {" << std::endl; + + TRACE_EXECUTION_V("Descendant completion for initial state %d", "i") + + stream << " j = 0" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + stream << " " << _prefix << "ctx.trans_set[j] = true;" << std::endl; + stream << " " << _prefix << "ctx.entry_set[i] = false;" << std::endl; + + TRACE_EXECUTION_V("Adding transition %d!", "j"); + + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "transitions[j].target)" << std::endl; + stream << std::endl; + + stream << " k = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[k].ancestors)" << std::endl; + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break" << std::endl; + stream << " od;" << std::endl; + + stream << " }" << std::endl; + } + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_COMPOUND] -> {" << std::endl; + + // TRACE_EXECUTION_V("Descendant completion for compound state %d", "i") + + stream << " /* we need to check whether one child is already in entry_set */" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << std::endl; + stream << " !" << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].children)"; + stream << " && " << std::endl; + stream << " (!" << _prefix << "STATES_HAS_AND(" << _prefix << "config, " << _prefix << "states[i].children)"; + // bit_has_and(stream, _prefix + "config", _prefix + "states[i].children", _states.size(), 5); + stream << " || " << _prefix << "STATES_HAS_AND(" << _prefix << "ctx.exit_set, " << _prefix << "states[i].children)" << std::endl; + stream << ")) " << std::endl; + stream << " -> {" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[i].completion)" << std::endl; + + stream << " if" << std::endl; + stream << " :: (" << _prefix << "STATES_HAS_AND(" << _prefix << "states[i].completion, " << _prefix << "states[i].children)"; + // bit_has_and(stream, _prefix + "states[i].completion", _prefix + "states[i].children", _states.size(), 6); + stream << std::endl; + stream << " ) -> {" << std::endl; + stream << " /* deep completion */" << std::endl; + stream << " j = i + 1;" << std::endl; + + // TRACE_EXECUTION_V("Deep completion for compound state %d", "i") + + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES - 1 -> {" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].completion[j] -> {" << std::endl; + + stream << " " << _prefix << "STATES_OR(" << _prefix << "ctx.entry_set, " << _prefix << "states[j].ancestors)" << std::endl; + stream << std::endl; + + stream << " /* completion of compound is single state */" << std::endl; + stream << " break;" << std::endl; + stream << " } " << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + stream << std::endl; + + stream << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Entry Set\");" << std::endl; + printBitArray(stream, _prefix + "ctx.entry_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << std::endl; } void ChartToPromela::writeFSMExitStates(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << "/* EXIT_STATES: */" << std::endl; - stream << " i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; - stream << " do" << std::endl; - stream << " :: i > 0 -> {" << std::endl; - stream << " i = i - 1;" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "ctx.exit_set[i] && " << _prefix << "config[i] -> {" << std::endl; - stream << " /* call all on-exit handlers */" << std::endl; - - TRACE_EXECUTION_V("Exiting state %d", "i"); - - stream << " if" << std::endl; - for (auto i = 0; i < _states.size(); i++) { - std::list<DOMElement*> onexits = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); - if (onexits.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); - for (auto onexit : onexits) - writeExecContent(stream, onexit, 3); - stream << " }" << std::endl; - } - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - - stream << " " << _prefix << "config[i] = false;" << std::endl; - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << "/* EXIT_STATES: */" << std::endl; + stream << " i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; + stream << " do" << std::endl; + stream << " :: i > 0 -> {" << std::endl; + stream << " i = i - 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.exit_set[i] && " << _prefix << "config[i] -> {" << std::endl; + stream << " /* call all on-exit handlers */" << std::endl; + + TRACE_EXECUTION_V("Exiting state %d", "i"); + + stream << " if" << std::endl; + for (auto i = 0; i < _states.size(); i++) { + std::list<DOMElement*> onexits = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); + if (onexits.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); + for (auto onexit : onexits) + writeExecContent(stream, onexit, 3); + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + + stream << " " << _prefix << "config[i] = false;" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + stream << std::endl; } void ChartToPromela::writeFSMTakeTransitions(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << "/* TAKE_TRANSITIONS: */" << std::endl; - if (_transitions.size() > 0) { - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "ctx.trans_set[i] && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] && " << std::endl; - stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; - stream << " /* Call executable content in normal transition */" << std::endl; - - TRACE_EXECUTION_V("Taking transition %d", "i"); - - stream << " if" << std::endl; - for (auto i = 0; i < _transitions.size(); i++) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - TRACE_EXECUTION_V("Processing executable content for transition %d", "i"); - writeExecContent(stream, _transitions[i], 4); - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - stream << " :: else ->skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; - } + stream << "/* ---------------------------- */" << std::endl; + stream << "/* TAKE_TRANSITIONS: */" << std::endl; + if (_transitions.size() > 0) { + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "ctx.trans_set[i] && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_HISTORY] && " << std::endl; + stream << " !" << _prefix << "transitions[i].type[USCXML_TRANS_INITIAL] -> {" << std::endl; + stream << " /* Call executable content in normal transition */" << std::endl; + + TRACE_EXECUTION_V("Taking transition %d", "i"); + + stream << " if" << std::endl; + for (auto i = 0; i < _transitions.size(); i++) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for transition %d", "i"); + writeExecContent(stream, _transitions[i], 4); + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; + } } void ChartToPromela::writeFSMEnterStates(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << "/* ENTER_STATES: */" << std::endl; - stream << " i = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "ctx.entry_set[i] &&" << std::endl; - stream << " !" << _prefix << "config[i] && " << std::endl; - stream << " /* these are no proper states */" << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] && " << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] && " << std::endl; - stream << " !" << _prefix << "states[i].type[USCXML_STATE_INITIAL]" << std::endl; - stream << " ) -> {" << std::endl; - - TRACE_EXECUTION_V("Entering state %d", "i"); - - stream << " " << _prefix << "config[i] = true;" << std::endl; - stream << std::endl; - + stream << "/* ---------------------------- */" << std::endl; + stream << "/* ENTER_STATES: */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "ctx.entry_set[i] &&" << std::endl; + stream << " !" << _prefix << "config[i] && " << std::endl; + stream << " /* these are no proper states */" << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] && " << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_HISTORY_SHALLOW] && " << std::endl; + stream << " !" << _prefix << "states[i].type[USCXML_STATE_INITIAL]" << std::endl; + stream << " ) -> {" << std::endl; + + TRACE_EXECUTION_V("Entering state %d", "i"); + + stream << " " << _prefix << "config[i] = true;" << std::endl; + stream << std::endl; + #if 0 - stream << " if" << std::endl; - stream << " :: !" << _prefix << "initialized_data[i] -> {" << std::endl; - stream << " /* TODO: late data binding not supported yet */" << std::endl; - stream << " " << _prefix << "initialized_data[i] = true;" << std::endl; - stream << " skip" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "initialized_data[i] -> {" << std::endl; + stream << " /* TODO: late data binding not supported yet */" << std::endl; + stream << " " << _prefix << "initialized_data[i] = true;" << std::endl; + stream << " skip" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; #endif - - stream << " /* Process executable content for entering a state */" << std::endl; - stream << " if" << std::endl; - for (auto i = 0; i < _states.size(); i++) { - std::list<DOMElement*> onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onentry" , _states[i]); - if (onentries.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - TRACE_EXECUTION_V("Processing executable content for entering state %d", "i"); - for (auto onentry : onentries) - writeExecContent(stream, onentry, 5); - stream << " }" << std::endl; - } - } - stream << " :: else ->skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - - stream << " /* take history and initial transitions */" << std::endl; - if (_transitions.size() > 0) { - stream << " j = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: (" << _prefix << "ctx.trans_set[j] &&" << std::endl; - stream << " (" << _prefix << "transitions[j].type[USCXML_TRANS_HISTORY] ||" << std::endl; - stream << " " << _prefix << "transitions[j].type[USCXML_TRANS_INITIAL]) && " << std::endl; - stream << " " << _prefix << "states[" << _prefix << "transitions[j].source].parent == i) -> {" << std::endl; - stream << " /* Call executable content in history or initial transition */" << std::endl; - stream << " if" << std::endl; - for (auto i = 0; i < _transitions.size(); i++) { - stream << " :: j == " << toStr(i) << " -> {" << std::endl; - TRACE_EXECUTION_V("Processing executable content for transition %d", "j"); - - writeExecContent(stream, _transitions[i], 8); - stream << " skip;" << std::endl; - stream << " }" << std::endl; - } - stream << " :: else ->skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - } - - stream << " /* handle final states */" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[i].type[USCXML_STATE_FINAL] -> {" << std::endl; - - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[" << _prefix << "states[i].parent].children[1] -> {" << std::endl; - stream << " /* exit topmost SCXML state */" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] = true;" << std::endl; - stream << " " << _prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - stream << " /* raise done event */" << std::endl; - stream << " if" << std::endl; - - std::string insertOp = "!"; - // if (_analyzer->usesEventField("delay")) - // insertOp += "!"; - - for (auto state : _states) { - if (state->getParentNode() == NULL || state->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE) - continue; - - if (!isFinal(state)) - continue; - - DOMElement* parent = static_cast<DOMElement*>(state->getParentNode()); - if (!HAS_ATTR(parent, "id")) - continue; - - std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR_CAST(state->getParentNode(), "id")); - - stream << " :: (i == " << ATTR(state, "documentOrder") << ") -> {" << std::endl; - - if (_analyzer->usesComplexEventStruct()) { - std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 7); - stream << typeReset << std::endl; - stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; - - std::list<DOMElement*> donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); - if (donedatas.size() > 0) { - writeRaiseDoneDate(stream, donedatas.front(), 8); - } - - doneEvent = _prefix + "_tmpE"; - } - - - stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; - stream << " }" << std::endl; - - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " }" << std::endl; - stream << " fi" << std::endl; - - stream << " /**" << std::endl; - stream << " * are we the last final state to leave a parallel state?:" << std::endl; - stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl; - stream << " * 2. Find all states for which these parallels are ancestors" << std::endl; - stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl; - stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; - stream << " */" << std::endl; - stream << " j = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[j].type[USCXML_STATE_PARALLEL] && " << _prefix << "states[i].ancestors[j] -> {" << std::endl; - stream << " " << _prefix << "STATES_CLEAR(" << _prefix << "ctx.tmp_states)" << std::endl; - - stream << " k = 0;" << std::endl; - stream << " do" << std::endl; - stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[k].ancestors[j] && " << _prefix << "config[k] -> {" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "states[k].type[USCXML_STATE_FINAL] -> {" << std::endl; - - stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "ctx.tmp_states, " << _prefix << "states[k].ancestors)" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - - stream << " " << _prefix << "ctx.tmp_states[k] = true;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " k = k + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << " if" << std::endl; - stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "ctx.tmp_states) -> {" << std::endl; - stream << " if" << std::endl; - - for (auto state : _states) { - if (isParallel(state) && HAS_ATTR(state, "id")) { - stream << " :: j == " << toStr(ATTR(state, "documentOrder")) << " -> {" << std::endl; - - std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR(state, "id")); - - if (_analyzer->usesComplexEventStruct()) { - std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 10); - stream << typeReset << std::endl; - stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; - - std::list<DOMElement*> donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); - if (donedatas.size() > 0) { - writeRaiseDoneDate(stream, donedatas.front(), 11); - } - doneEvent = _prefix + "_tmpE"; - } - - stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; - stream << " }" << std::endl; - } - } - - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " j = j + 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << std::endl; - - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " i = i + 1;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od;" << std::endl; + + stream << " /* Process executable content for entering a state */" << std::endl; + stream << " if" << std::endl; + for (auto i = 0; i < _states.size(); i++) { + std::list<DOMElement*> onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onentry" , _states[i]); + if (onentries.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for entering state %d", "i"); + for (auto onentry : onentries) + writeExecContent(stream, onentry, 5); + stream << " }" << std::endl; + } + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + + stream << " /* take history and initial transitions */" << std::endl; + if (_transitions.size() > 0) { + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "ctx.trans_set[j] &&" << std::endl; + stream << " (" << _prefix << "transitions[j].type[USCXML_TRANS_HISTORY] ||" << std::endl; + stream << " " << _prefix << "transitions[j].type[USCXML_TRANS_INITIAL]) && " << std::endl; + stream << " " << _prefix << "states[" << _prefix << "transitions[j].source].parent == i) -> {" << std::endl; + stream << " /* Call executable content in history or initial transition */" << std::endl; + stream << " if" << std::endl; + for (auto i = 0; i < _transitions.size(); i++) { + stream << " :: j == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for transition %d", "j"); + + writeExecContent(stream, _transitions[i], 8); + stream << " skip;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + } + + stream << " /* handle final states */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_FINAL] -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[" << _prefix << "states[i].parent].children[1] -> {" << std::endl; + stream << " /* exit topmost SCXML state */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " /* raise done event */" << std::endl; + stream << " if" << std::endl; + + std::string insertOp = "!"; + // if (_analyzer->usesEventField("delay")) + // insertOp += "!"; + + for (auto state : _states) { + if (state->getParentNode() == NULL || state->getParentNode()->getNodeType() != DOMNode::ELEMENT_NODE) + continue; + + if (!isFinal(state)) + continue; + + DOMElement* parent = static_cast<DOMElement*>(state->getParentNode()); + if (!HAS_ATTR(parent, "id")) + continue; + + std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR_CAST(state->getParentNode(), "id")); + + stream << " :: (i == " << ATTR(state, "documentOrder") << ") -> {" << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 7); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; + + std::list<DOMElement*> donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); + if (donedatas.size() > 0) { + writeRaiseDoneDate(stream, donedatas.front(), 8); + } + + doneEvent = _prefix + "_tmpE"; + } + + + stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; + stream << " }" << std::endl; + + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " }" << std::endl; + stream << " fi" << std::endl; + + stream << " /**" << std::endl; + stream << " * are we the last final state to leave a parallel state?:" << std::endl; + stream << " * 1. Gather all parallel states in our ancestor chain" << std::endl; + stream << " * 2. Find all states for which these parallels are ancestors" << std::endl; + stream << " * 3. Iterate all active final states and remove their ancestors" << std::endl; + stream << " * 4. If a state remains, not all children of a parallel are final" << std::endl; + stream << " */" << std::endl; + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[j].type[USCXML_STATE_PARALLEL] && " << _prefix << "states[i].ancestors[j] -> {" << std::endl; + stream << " " << _prefix << "STATES_CLEAR(" << _prefix << "ctx.tmp_states)" << std::endl; + + stream << " k = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < " << _prefix << "USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[k].ancestors[j] && " << _prefix << "config[k] -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[k].type[USCXML_STATE_FINAL] -> {" << std::endl; + + stream << " " << _prefix << "STATES_AND_NOT(" << _prefix << "ctx.tmp_states, " << _prefix << "states[k].ancestors)" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + + stream << " " << _prefix << "ctx.tmp_states[k] = true;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " k = k + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "STATES_HAS_ANY(" << _prefix << "ctx.tmp_states) -> {" << std::endl; + stream << " if" << std::endl; + + for (auto state : _states) { + if (isParallel(state) && HAS_ATTR(state, "id")) { + stream << " :: j == " << toStr(ATTR(state, "documentOrder")) << " -> {" << std::endl; + + std::string doneEvent = _analyzer->macroForLiteral("done.state." + ATTR(state, "id")); + + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 10); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << doneEvent << ";" << std::endl; + + std::list<DOMElement*> donedatas = DOMUtils::filterChildElements(XML_PREFIX(state).str() + "donedata" , state); + if (donedatas.size() > 0) { + writeRaiseDoneDate(stream, donedatas.front(), 11); + } + doneEvent = _prefix + "_tmpE"; + } + + stream << " " << _prefix << "iQ" << insertOp << doneEvent << ";" << std::endl; + stream << " }" << std::endl; + } + } + + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " i = i + 1;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od;" << std::endl; } void ChartToPromela::writeFSMTerminateMachine(std::ostream& stream) { - stream << "/* ---------------------------- */" << std::endl; - stream << _prefix << "TERMINATE_MACHINE:" << std::endl; - - stream << "skip; d_step {" << std::endl; - - TRACE_EXECUTION("Machine finished"); - - stream << "/* exit all remaining states */" << std::endl; - stream << "i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; - stream << "do" << std::endl; - stream << ":: i > 0 -> {" << std::endl; - stream << " i = i - 1;" << std::endl; - stream << " if" << std::endl; - stream << " :: " << _prefix << "config[i] && " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; - stream << " /* call all on exit handlers */" << std::endl; - stream << " if" << std::endl; - for (auto i = 0; i < _states.size(); i++) { - std::list<DOMElement*> onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); - if (onentries.size() > 0) { - stream << " :: i == " << toStr(i) << " -> {" << std::endl; - TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); - for (auto onentry : onentries) - writeExecContent(stream, onentry, 2); - stream << " }" << std::endl; - } - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << std::endl; - stream << " skip;" << std::endl; - stream << " " << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << std::endl; - - stream << " if" << std::endl; - stream << " :: " << _prefix << "invocations[i] -> {" << std::endl; - stream << " /* cancel invocations */" << std::endl; - stream << " " << _prefix << "invocations[i] = false;" << std::endl; - stream << " if" << std::endl; - - for (auto machine : _machinesNested) { - stream << " :: i == " << ATTR_CAST(machine.first->getParentNode(), "documentOrder") << " -> {" << std::endl; - stream << " " << machine.second->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; - stream << " }" << std::endl; - } - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - - stream << " skip;" << std::endl; - stream << std::endl; - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << "}" << std::endl; - stream << ":: else -> break;" << std::endl; - stream << "od;" << std::endl; - - stream << std::endl; - - if (_machinesAll->size() > 1 && _analyzer->usesEventField("delay")) { - /* TODO: We nee to clear all events if we were canceled */ - TRACE_EXECUTION("Removing pending events"); - stream << "removePendingEventsFromInvoker(" << _analyzer->macroForLiteral(_invokerid) << ")" << std::endl; - } - - - if (_parent != NULL) { - stream << "/* send done event */" << std::endl; - stream << "if" << std::endl; - stream << ":: " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; - - if (_analyzer->usesComplexEventStruct()) { - std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 2); - stream << typeReset << std::endl; - stream << " " << _prefix << "_tmpE.name = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; - - if (_analyzer->usesEventField("invokeid")) { - stream << " " << _prefix << "_tmpE.invokeid = " << _analyzer->macroForLiteral(_invokerid) << std::endl; - } - - } else { - stream << " " << _prefix << "_tmpE = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; - } - - - TRACE_EXECUTION("Sending DONE.INVOKE"); - - stream << " " << _parent->_prefix << "eQ!" << _prefix << "_tmpE;" << std::endl; - if (_analyzer->usesEventField("delay")) { - stream << " insertWithDelay(" << _parent->_prefix << "eQ);" << std::endl; - } - stream << "}" << std::endl; - stream << ":: else -> skip" << std::endl; - stream << "fi;" << std::endl; - stream << std::endl; - - } - stream << "} /* d_step */" << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << _prefix << "TERMINATE_MACHINE:" << std::endl; + + stream << "skip; d_step {" << std::endl; + + TRACE_EXECUTION("Machine finished"); + + stream << "/* exit all remaining states */" << std::endl; + stream << "i = " << _prefix << "USCXML_NUMBER_STATES;" << std::endl; + stream << "do" << std::endl; + stream << ":: i > 0 -> {" << std::endl; + stream << " i = i - 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "config[i] && " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + stream << " /* call all on exit handlers */" << std::endl; + stream << " if" << std::endl; + for (auto i = 0; i < _states.size(); i++) { + std::list<DOMElement*> onentries = DOMUtils::filterChildElements(XML_PREFIX(_states[i]).str() + "onexit" , _states[i]); + if (onentries.size() > 0) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + TRACE_EXECUTION_V("Processing executable content for exiting state %d", "i"); + for (auto onentry : onentries) + writeExecContent(stream, onentry, 2); + stream << " }" << std::endl; + } + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + stream << " skip;" << std::endl; + stream << " " << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << " if" << std::endl; + stream << " :: " << _prefix << "invocations[i] -> {" << std::endl; + stream << " /* cancel invocations */" << std::endl; + stream << " " << _prefix << "invocations[i] = false;" << std::endl; + stream << " if" << std::endl; + + for (auto machine : _machinesNested) { + stream << " :: i == " << ATTR_CAST(machine.first->getParentNode(), "documentOrder") << " -> {" << std::endl; + stream << " " << machine.second->_prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + stream << " }" << std::endl; + } + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + + stream << " skip;" << std::endl; + stream << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << "}" << std::endl; + stream << ":: else -> break;" << std::endl; + stream << "od;" << std::endl; + + stream << std::endl; + + if (_machinesAll->size() > 1 && _analyzer->usesEventField("delay")) { + /* TODO: We nee to clear all events if we were canceled */ + TRACE_EXECUTION("Removing pending events"); + stream << "removePendingEventsFromInvoker(" << _analyzer->macroForLiteral(_invokerid) << ")" << std::endl; + } + + + if (_parent != NULL) { + stream << "/* send done event */" << std::endl; + stream << "if" << std::endl; + stream << ":: " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + std::string typeReset = _analyzer->getTypeReset(_prefix + "_tmpE", _analyzer->getType("_event"), 2); + stream << typeReset << std::endl; + stream << " " << _prefix << "_tmpE.name = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; + + if (_analyzer->usesEventField("invokeid")) { + stream << " " << _prefix << "_tmpE.invokeid = " << _analyzer->macroForLiteral(_invokerid) << std::endl; + } + + } else { + stream << " " << _prefix << "_tmpE = " << _analyzer->macroForLiteral("done.invoke." + _invokerid) << std::endl; + } + + + TRACE_EXECUTION("Sending DONE.INVOKE"); + + stream << " " << _parent->_prefix << "eQ!" << _prefix << "_tmpE;" << std::endl; + if (_analyzer->usesEventField("delay")) { + stream << " insertWithDelay(" << _parent->_prefix << "eQ);" << std::endl; + } + stream << "}" << std::endl; + stream << ":: else -> skip" << std::endl; + stream << "fi;" << std::endl; + stream << std::endl; + + } + stream << "} /* d_step */" << std::endl; } - + void ChartToPromela::writeIfBlock(std::ostream& stream, std::list<DOMElement*>& condChain, size_t indent) { if (condChain.size() == 0) return; @@ -2884,332 +2884,332 @@ std::string ChartToPromela::declForRange(const std::string& identifier, long min } void ChartToPromela::writeDetermineShortestDelay(std::ostream& stream, int indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - stream << padding << "inline determineSmallestDelay(smallestDelay, queue) {" << std::endl; - // stream << padding << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); - stream << padding << " if" << std::endl; - stream << padding << " :: len(queue) > 0 -> {" << std::endl; - stream << padding << " queue?<tmpE>;" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: (tmpE.delay < smallestDelay) -> { smallestDelay = tmpE.delay; }" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << "}" << std::endl; + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline determineSmallestDelay(smallestDelay, queue) {" << std::endl; + // stream << padding << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + stream << padding << " if" << std::endl; + stream << padding << " :: len(queue) > 0 -> {" << std::endl; + stream << padding << " queue?<tmpE>;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: (tmpE.delay < smallestDelay) -> { smallestDelay = tmpE.delay; }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "}" << std::endl; } void ChartToPromela::writeScheduleMachines(std::ostream& stream, int indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - stream << padding << "inline scheduleMachines() {" << std::endl; - std::list<std::string> queues; - queues.push_back("eQ"); - - if (_allowEventInterleaving) - queues.push_back("tmpQ"); - - stream << " /* schedule state-machines with regard to their event's delay */" << std::endl; - stream << " skip;" << std::endl; - stream << " d_step {" << std::endl; - - stream << std::endl << "/* determine smallest delay */" << std::endl; - stream << " int smallestDelay = 2147483647;" << std::endl; - - for (auto machine : *_machinesAll) { - for (auto queue : queues) { - stream << " determineSmallestDelay(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; - } - } - - TRACE_EXECUTION_V("Smallest delay is %d", "smallestDelay"); - - stream << std::endl << "/* prioritize processes with lowest delay or internal events */" << std::endl; - - for (auto machine : *_machinesAll) { - stream << " rescheduleProcess(smallestDelay, " - << machine.second->_prefix << "procid, " - << machine.second->_prefix << "iQ, " - << machine.second->_prefix << "eQ"; - if (_allowEventInterleaving) { - stream << ", " << machine.second->_prefix << "tmpQ);" << std::endl; - } else { - stream << ");" << std::endl; - } - } - - stream << std::endl << "/* advance time by subtracting the smallest delay from all event delays */" << std::endl; - stream << " if" << std::endl; - stream << " :: (smallestDelay > 0) -> {" << std::endl; - for (auto machine : *_machinesAll) { - for (auto queue : queues) { - stream << " advanceTime(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; - } - } - stream << " }" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi;" << std::endl; - stream << " }" << std::endl; - stream << " set_priority(_pid, 10);" << std::endl << std::endl; - stream << padding << "}" << std::endl; + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline scheduleMachines() {" << std::endl; + std::list<std::string> queues; + queues.push_back("eQ"); + + if (_allowEventInterleaving) + queues.push_back("tmpQ"); + + stream << " /* schedule state-machines with regard to their event's delay */" << std::endl; + stream << " skip;" << std::endl; + stream << " d_step {" << std::endl; + + stream << std::endl << "/* determine smallest delay */" << std::endl; + stream << " int smallestDelay = 2147483647;" << std::endl; + + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " determineSmallestDelay(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + + TRACE_EXECUTION_V("Smallest delay is %d", "smallestDelay"); + + stream << std::endl << "/* prioritize processes with lowest delay or internal events */" << std::endl; + + for (auto machine : *_machinesAll) { + stream << " rescheduleProcess(smallestDelay, " + << machine.second->_prefix << "procid, " + << machine.second->_prefix << "iQ, " + << machine.second->_prefix << "eQ"; + if (_allowEventInterleaving) { + stream << ", " << machine.second->_prefix << "tmpQ);" << std::endl; + } else { + stream << ");" << std::endl; + } + } + + stream << std::endl << "/* advance time by subtracting the smallest delay from all event delays */" << std::endl; + stream << " if" << std::endl; + stream << " :: (smallestDelay > 0) -> {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " advanceTime(smallestDelay, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << " }" << std::endl; + stream << " set_priority(_pid, 10);" << std::endl << std::endl; + stream << padding << "}" << std::endl; } void ChartToPromela::writeAdvanceTime(std::ostream& stream, int indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - stream << padding << "inline advanceTime(increment, queue) {" << std::endl; - stream << padding << " tmpIndex = 0;" << std::endl; - stream << padding << " do" << std::endl; - stream << padding << " :: tmpIndex < len(queue) -> {" << std::endl; - stream << padding << " queue?tmpE;" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: tmpE.delay >= increment -> tmpE.delay = tmpE.delay - increment;" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi" << std::endl; - stream << padding << " queue!tmpE;" << std::endl; - stream << padding << " tmpIndex++;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> break;" << std::endl; - stream << padding << " od" << std::endl; - stream << padding << "}" << std::endl; + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + stream << padding << "inline advanceTime(increment, queue) {" << std::endl; + stream << padding << " tmpIndex = 0;" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: tmpIndex < len(queue) -> {" << std::endl; + stream << padding << " queue?tmpE;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: tmpE.delay >= increment -> tmpE.delay = tmpE.delay - increment;" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi" << std::endl; + stream << padding << " queue!tmpE;" << std::endl; + stream << padding << " tmpIndex++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "}" << std::endl; } void ChartToPromela::writeInsertWithDelay(std::ostream& stream, int indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - uint32_t maxExternalQueueLength = 1; - for(auto machine : *_machinesAll) { - maxExternalQueueLength = MAX(maxExternalQueueLength, machine.second->_externalQueueLength); - } - - maxExternalQueueLength += 6; - - if (maxExternalQueueLength <= 1) { - stream << padding << "/* noop for external queues with length <= 1 */" << std::endl; - stream << padding << "inline insertWithDelay(queue) {}" << std::endl; - } - - stream << padding << "hidden _event_t _iwdQ[" << maxExternalQueueLength - 1 << "];" << std::endl; - stream << padding << "hidden int _iwdQLength = 0;" << std::endl; - stream << padding << "hidden int _iwdIdx1 = 0;" << std::endl; - stream << padding << "hidden int _iwdIdx2 = 0;" << std::endl; - stream << padding << "hidden _event_t _iwdTmpE;" << std::endl; - stream << padding << "hidden _event_t _iwdLastE;" << std::endl; - stream << padding << "bool _iwdInserted = false;" << std::endl; - stream << padding << "" << std::endl; - stream << padding << "/* last event in given queue is potentially at wrong position */" << std::endl; - stream << padding << "inline insertWithDelay(queue) {" << std::endl; - stream << padding << " d_step {" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " /* only process for non-trivial queues */" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: len(queue) > 1 -> {" << std::endl; - - TRACE_EXECUTION("Reshuffling events") - - stream << padding << "" << std::endl; - stream << padding << " /* move all events but last over and remember the last one */" << std::endl; - stream << padding << " _iwdIdx1 = 0;" << std::endl; - stream << padding << " _iwdQLength = len(queue) - 1;" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " do" << std::endl; - stream << padding << " :: _iwdIdx1 < _iwdQLength -> {" << std::endl; - stream << padding << " queue?_iwdTmpE;" << std::endl; - stream << padding << " _iwdQ[_iwdIdx1].name = _iwdTmpE.name;" << std::endl; - - stream << _analyzer->getTypeAssignment("_iwdQ[_iwdIdx1]", "_iwdTmpE", _analyzer->getType("_event"), 8); - - stream << padding << " _iwdIdx1++;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> break;" << std::endl; - stream << padding << " od" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " queue?_iwdLastE;" << std::endl; - - stream << padding << "" << std::endl; - stream << padding << " /* _iwdQ now contains all but last item in _iwdLastE */" << std::endl; - stream << padding << " assert(len(queue) == 0);" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " /* reinsert into queue and place _iwdLastE correctly */" << std::endl; - stream << padding << " _iwdInserted = false;" << std::endl; - stream << padding << " _iwdIdx2 = 0;" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " do" << std::endl; - stream << padding << " :: _iwdIdx2 < _iwdIdx1 -> {" << std::endl; - stream << padding << " _iwdTmpE.name = _iwdQ[_iwdIdx2].name;" << std::endl; - - stream << _analyzer->getTypeAssignment("_iwdTmpE", "_iwdQ[_iwdIdx2]", _analyzer->getType("_event"), 4); - - stream << padding << "" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: _iwdTmpE.delay > _iwdLastE.delay && !_iwdInserted -> {" << std::endl; - stream << padding << " queue!_iwdLastE;" << std::endl; - TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); - - stream << padding << " _iwdInserted = true;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> skip" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " queue!_iwdTmpE;" << std::endl; - TRACE_EXECUTION_V("Event %d has delay %d", "_iwdTmpE.name, _iwdTmpE.delay"); - - stream << padding << " _iwdIdx2++;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> break;" << std::endl; - stream << padding << " od" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: !_iwdInserted -> {" << std::endl; - stream << padding << " queue!_iwdLastE;" << std::endl; - TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); - stream << padding << " }" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << "" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << "}" << std::endl; + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + uint32_t maxExternalQueueLength = 1; + for(auto machine : *_machinesAll) { + maxExternalQueueLength = MAX(maxExternalQueueLength, machine.second->_externalQueueLength); + } + + maxExternalQueueLength += 6; + + if (maxExternalQueueLength <= 1) { + stream << padding << "/* noop for external queues with length <= 1 */" << std::endl; + stream << padding << "inline insertWithDelay(queue) {}" << std::endl; + } + + stream << padding << "hidden _event_t _iwdQ[" << maxExternalQueueLength - 1 << "];" << std::endl; + stream << padding << "hidden int _iwdQLength = 0;" << std::endl; + stream << padding << "hidden int _iwdIdx1 = 0;" << std::endl; + stream << padding << "hidden int _iwdIdx2 = 0;" << std::endl; + stream << padding << "hidden _event_t _iwdTmpE;" << std::endl; + stream << padding << "hidden _event_t _iwdLastE;" << std::endl; + stream << padding << "bool _iwdInserted = false;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << "/* last event in given queue is potentially at wrong position */" << std::endl; + stream << padding << "inline insertWithDelay(queue) {" << std::endl; + stream << padding << " d_step {" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " /* only process for non-trivial queues */" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: len(queue) > 1 -> {" << std::endl; + + TRACE_EXECUTION("Reshuffling events") + + stream << padding << "" << std::endl; + stream << padding << " /* move all events but last over and remember the last one */" << std::endl; + stream << padding << " _iwdIdx1 = 0;" << std::endl; + stream << padding << " _iwdQLength = len(queue) - 1;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: _iwdIdx1 < _iwdQLength -> {" << std::endl; + stream << padding << " queue?_iwdTmpE;" << std::endl; + stream << padding << " _iwdQ[_iwdIdx1].name = _iwdTmpE.name;" << std::endl; + + stream << _analyzer->getTypeAssignment("_iwdQ[_iwdIdx1]", "_iwdTmpE", _analyzer->getType("_event"), 8); + + stream << padding << " _iwdIdx1++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " queue?_iwdLastE;" << std::endl; + + stream << padding << "" << std::endl; + stream << padding << " /* _iwdQ now contains all but last item in _iwdLastE */" << std::endl; + stream << padding << " assert(len(queue) == 0);" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " /* reinsert into queue and place _iwdLastE correctly */" << std::endl; + stream << padding << " _iwdInserted = false;" << std::endl; + stream << padding << " _iwdIdx2 = 0;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " do" << std::endl; + stream << padding << " :: _iwdIdx2 < _iwdIdx1 -> {" << std::endl; + stream << padding << " _iwdTmpE.name = _iwdQ[_iwdIdx2].name;" << std::endl; + + stream << _analyzer->getTypeAssignment("_iwdTmpE", "_iwdQ[_iwdIdx2]", _analyzer->getType("_event"), 4); + + stream << padding << "" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: _iwdTmpE.delay > _iwdLastE.delay && !_iwdInserted -> {" << std::endl; + stream << padding << " queue!_iwdLastE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); + + stream << padding << " _iwdInserted = true;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " queue!_iwdTmpE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d", "_iwdTmpE.name, _iwdTmpE.delay"); + + stream << padding << " _iwdIdx2++;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> break;" << std::endl; + stream << padding << " od" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: !_iwdInserted -> {" << std::endl; + stream << padding << " queue!_iwdLastE;" << std::endl; + TRACE_EXECUTION_V("Event %d has delay %d (last)", "_iwdLastE.name, _iwdLastE.delay"); + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << "}" << std::endl; } void ChartToPromela::writeRescheduleProcess(std::ostream& stream, int indent) { - std::string padding; - for (size_t i = 0; i < indent; i++) { - padding += " "; - } - - if (_allowEventInterleaving) { - stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ, tempQ) {" << std::endl; - } else { - stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ) {" << std::endl; - } - // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); - - stream << padding << " set_priority(procId, 1);" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: len(internalQ) > 0 -> set_priority(procId, 10);" << std::endl; - stream << padding << " :: else {" << std::endl; - stream << padding << " if" << std::endl; - - stream << padding << " :: len(externalQ) > 0 -> {" << std::endl; - stream << padding << " externalQ?<tmpE>;" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << " }" << std::endl; - - if (_allowEventInterleaving) { - stream << padding << " :: len(tempQ) > 0 -> {" << std::endl; - stream << padding << " tempQ?<tmpE>;" << std::endl; - stream << padding << " if" << std::endl; - stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << " }" << std::endl; - } - - stream << padding << " :: else -> skip;" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << " }" << std::endl; - stream << padding << " fi;" << std::endl; - stream << padding << "}" << std::endl; + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + if (_allowEventInterleaving) { + stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ, tempQ) {" << std::endl; + } else { + stream << padding << "inline rescheduleProcess(smallestDelay, procId, internalQ, externalQ) {" << std::endl; + } + // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + + stream << padding << " set_priority(procId, 1);" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: len(internalQ) > 0 -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else {" << std::endl; + stream << padding << " if" << std::endl; + + stream << padding << " :: len(externalQ) > 0 -> {" << std::endl; + stream << padding << " externalQ?<tmpE>;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + + if (_allowEventInterleaving) { + stream << padding << " :: len(tempQ) > 0 -> {" << std::endl; + stream << padding << " tempQ?<tmpE>;" << std::endl; + stream << padding << " if" << std::endl; + stream << padding << " :: smallestDelay == tmpE.delay -> set_priority(procId, 10);" << std::endl; + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + } + + stream << padding << " :: else -> skip;" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << " }" << std::endl; + stream << padding << " fi;" << std::endl; + stream << padding << "}" << std::endl; } void ChartToPromela::writeCancelEvents(std::ostream& stream, int indent) { - std::list<std::string> queues; - queues.push_back("eQ"); - if (_allowEventInterleaving) - queues.push_back("tmpQ"); - - stream << "inline cancelSendId(sendIdentifier, source) {" << std::endl; - for (auto machine : *_machinesAll) { - for (auto queue : queues) { - stream << " cancelSendIdOnQueue(sendIdentifier, source, " << machine.second->_prefix << queue << ");" << std::endl; - } - } - stream << "}" << std::endl; - stream << std::endl; - - - stream << "inline cancelSendIdOnQueue(sendIdentifier, source, queue) {" << std::endl; - stream << " tmpIndex = 0;" << std::endl; - // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); - stream << " do" << std::endl; - stream << " :: tmpIndex < len(queue) -> {" << std::endl; - stream << " queue?tmpE;" << std::endl; - stream << " if" << std::endl; - stream << " :: tmpE.sendid != sendIdentifier || tmpE.origin != source || tmpE.delay == 0 -> queue!tmpE;" << std::endl; - stream << " :: else -> skip;" << std::endl; - stream << " fi" << std::endl; - stream << " tmpIndex++;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << "}" << std::endl; + std::list<std::string> queues; + queues.push_back("eQ"); + if (_allowEventInterleaving) + queues.push_back("tmpQ"); + + stream << "inline cancelSendId(sendIdentifier, source) {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " cancelSendIdOnQueue(sendIdentifier, source, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + stream << "}" << std::endl; + stream << std::endl; + + + stream << "inline cancelSendIdOnQueue(sendIdentifier, source, queue) {" << std::endl; + stream << " tmpIndex = 0;" << std::endl; + // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + stream << " do" << std::endl; + stream << " :: tmpIndex < len(queue) -> {" << std::endl; + stream << " queue?tmpE;" << std::endl; + stream << " if" << std::endl; + stream << " :: tmpE.sendid != sendIdentifier || tmpE.origin != source || tmpE.delay == 0 -> queue!tmpE;" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi" << std::endl; + stream << " tmpIndex++;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << "}" << std::endl; } void ChartToPromela::writeRemovePendingEventsFromInvoker(std::ostream& stream, int indent) { - std::list<std::string> queues; - queues.push_back("eQ"); - if (_allowEventInterleaving) - queues.push_back("tmpQ"); - - stream << "inline removePendingEventsFromInvoker(invoker) {" << std::endl; - for (auto machine : *_machinesAll) { - for (auto queue : queues) { - stream << " removePendingEventsFromInvokerOnQueue(invoker, " << machine.second->_prefix << queue << ");" << std::endl; - } - } - stream << "}" << std::endl; - stream << std::endl; - - stream << "inline removePendingEventsFromInvokerOnQueue(invoker, queue) {" << std::endl; - stream << " tmpIndex = len(queue);" << std::endl; - // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); - stream << " do" << std::endl; - stream << " :: tmpIndex > 0 -> {" << std::endl; - stream << " queue?tmpE;" << std::endl; - stream << " if" << std::endl; - stream << " :: false || "; - if (_analyzer->usesEventField("delay")) - stream << "tmpE.delay == 0 || "; - if (_analyzer->usesEventField("invokeid")) - stream << "tmpE.invokeid != invoker" << std::endl; - stream << " -> {" << std::endl; - - TRACE_EXECUTION_V("Reenqueing event %d", "tmpE.name"); - - stream << " queue!tmpE;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> {" << std::endl; - - TRACE_EXECUTION_V("Dropping event %d", "tmpE.name"); - - stream << " skip;" << std::endl; - stream << " }" << std::endl; - stream << " fi" << std::endl; - stream << " tmpIndex = tmpIndex - 1;" << std::endl; - stream << " }" << std::endl; - stream << " :: else -> break;" << std::endl; - stream << " od" << std::endl; - stream << "}" << std::endl; + std::list<std::string> queues; + queues.push_back("eQ"); + if (_allowEventInterleaving) + queues.push_back("tmpQ"); + + stream << "inline removePendingEventsFromInvoker(invoker) {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " removePendingEventsFromInvokerOnQueue(invoker, " << machine.second->_prefix << queue << ");" << std::endl; + } + } + stream << "}" << std::endl; + stream << std::endl; + + stream << "inline removePendingEventsFromInvokerOnQueue(invoker, queue) {" << std::endl; + stream << " tmpIndex = len(queue);" << std::endl; + // stream << _analyzer->getTypeReset("tmpE", _analyzer->getType("_event"), " "); + stream << " do" << std::endl; + stream << " :: tmpIndex > 0 -> {" << std::endl; + stream << " queue?tmpE;" << std::endl; + stream << " if" << std::endl; + stream << " :: false || "; + if (_analyzer->usesEventField("delay")) + stream << "tmpE.delay == 0 || "; + if (_analyzer->usesEventField("invokeid")) + stream << "tmpE.invokeid != invoker" << std::endl; + stream << " -> {" << std::endl; + + TRACE_EXECUTION_V("Reenqueing event %d", "tmpE.name"); + + stream << " queue!tmpE;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + + TRACE_EXECUTION_V("Dropping event %d", "tmpE.name"); + + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << " tmpIndex = tmpIndex - 1;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> break;" << std::endl; + stream << " od" << std::endl; + stream << "}" << std::endl; } diff --git a/src/uscxml/transform/ChartToPromela.h b/src/uscxml/transform/ChartToPromela.h index b8b513e..ac7f26a 100644 --- a/src/uscxml/transform/ChartToPromela.h +++ b/src/uscxml/transform/ChartToPromela.h @@ -40,55 +40,55 @@ public: protected: ChartToPromela(const Interpreter& other) : ChartToC(other) { - _prefix = "U" + _md5.substr(0, 8) + "_"; - } + _prefix = "U" + _md5.substr(0, 8) + "_"; + } void writeTransitions(std::ostream& stream); void writeStates(std::ostream& stream); - - void writeCommonTypeDefs(std::ostream& stream); - void writeCommonVariables(std::ostream& stream); - void writeTypeDefs(std::ostream& stream); - void writeVariables(std::ostream& stream); + + void writeCommonTypeDefs(std::ostream& stream); + void writeCommonVariables(std::ostream& stream); + void writeTypeDefs(std::ostream& stream); + void writeVariables(std::ostream& stream); // void writeTypeDefs(std::ostream& stream); // void writeTypes(std::ostream& stream); void writeMacros(std::ostream& stream); void writeFSM(std::ostream& stream); - void writeFSMDequeueEvent(std::ostream& stream); + void writeFSMDequeueEvent(std::ostream& stream); // void writeFSMRescheduleMachines(std::ostream& stream); // void writeFSMMacrostep(std::ostream& stream); // void writeFSMDequeueInternalOrSpontaneousEvent(std::ostream& stream); - void writeFSMSelectTransitions(std::ostream& stream); - void writeFSMRememberHistory(std::ostream& stream); - void writeFSMEstablishEntrySet(std::ostream& stream); - void writeFSMExitStates(std::ostream& stream); - void writeFSMTakeTransitions(std::ostream& stream); - void writeFSMEnterStates(std::ostream& stream); - void writeFSMTerminateMachine(std::ostream& stream); + void writeFSMSelectTransitions(std::ostream& stream); + void writeFSMRememberHistory(std::ostream& stream); + void writeFSMEstablishEntrySet(std::ostream& stream); + void writeFSMExitStates(std::ostream& stream); + void writeFSMTakeTransitions(std::ostream& stream); + void writeFSMEnterStates(std::ostream& stream); + void writeFSMTerminateMachine(std::ostream& stream); void writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent = 0); - void writeRaiseDoneDate(std::ostream& stream, const XERCESC_NS::DOMElement* donedata, size_t indent = 0); - - void writeStrings(std::ostream& stream); - - void writeCancelEvents(std::ostream& stream, int indent = 0); - void writeScheduleMachines(std::ostream& stream, int indent = 0); - void writeDetermineShortestDelay(std::ostream& stream, int indent = 0); - void writeRescheduleProcess(std::ostream& stream, int indent = 0); - void writeInsertWithDelay(std::ostream& stream, int indent = 0); - void writeAdvanceTime(std::ostream& stream, int indent = 0); - void writeRemovePendingEventsFromInvoker(std::ostream& stream, int indent = 0); - - void prepare(); - - void writeBitClearMacro(std::ostream& stream); - void writeBitHasAndMacro(std::ostream& stream); - void writeBitHasAnyMacro(std::ostream& stream); - void writeBitOrMacro(std::ostream& stream); - void writeBitCopyMacro(std::ostream& stream); - void writeBitAndMacro(std::ostream& stream); - void writeBitAndNotMacro(std::ostream& stream); + void writeRaiseDoneDate(std::ostream& stream, const XERCESC_NS::DOMElement* donedata, size_t indent = 0); + + void writeStrings(std::ostream& stream); + + void writeCancelEvents(std::ostream& stream, int indent = 0); + void writeScheduleMachines(std::ostream& stream, int indent = 0); + void writeDetermineShortestDelay(std::ostream& stream, int indent = 0); + void writeRescheduleProcess(std::ostream& stream, int indent = 0); + void writeInsertWithDelay(std::ostream& stream, int indent = 0); + void writeAdvanceTime(std::ostream& stream, int indent = 0); + void writeRemovePendingEventsFromInvoker(std::ostream& stream, int indent = 0); + + void prepare(); + + void writeBitClearMacro(std::ostream& stream); + void writeBitHasAndMacro(std::ostream& stream); + void writeBitHasAnyMacro(std::ostream& stream); + void writeBitOrMacro(std::ostream& stream); + void writeBitCopyMacro(std::ostream& stream); + void writeBitAndMacro(std::ostream& stream); + void writeBitAndNotMacro(std::ostream& stream); void printBitArray(std::ostream& stream, const std::string& array, @@ -101,17 +101,17 @@ protected: ChartToPromela* _parent = NULL; std::string _invokerid; - size_t _internalQueueLength = 7; - size_t _externalQueueLength = 7; - bool _allowEventInterleaving = false; - + size_t _internalQueueLength = 7; + size_t _externalQueueLength = 7; + bool _allowEventInterleaving = false; + std::map<std::string, XERCESC_NS::DOMElement* > _machinesPerId; std::map<std::string, XERCESC_NS::DOMElement* >* _machinesAllPerId = NULL; std::map<XERCESC_NS::DOMElement*, ChartToPromela*> _machinesNested; std::map<XERCESC_NS::DOMElement*, ChartToPromela*>* _machinesAll = NULL; std::set<std::string> _dataModelVars; - std::list<std::string> _varInitializers; // pending initializations for arrays + std::list<std::string> _varInitializers; // pending initializations for arrays std::string beautifyIndentation(const std::string& code, size_t indent = 0); void writeIfBlock(std::ostream& stream, std::list<XERCESC_NS::DOMElement*>& condChain, size_t indent = 0); diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp index 5061e33..071d863 100644 --- a/src/uscxml/transform/ChartToVHDL.cpp +++ b/src/uscxml/transform/ChartToVHDL.cpp @@ -37,1363 +37,1371 @@ namespace uscxml { - using namespace XERCESC_NS; - - Transformer ChartToVHDL::transform(const Interpreter &other) { - ChartToVHDL *c2c = new ChartToVHDL(other); - - return std::shared_ptr<TransformerImpl>(c2c); - } - - ChartToVHDL::ChartToVHDL(const Interpreter &other) : ChartToC(other), _eventTrie(".") { - } - - ChartToVHDL::~ChartToVHDL() { - } - - void ChartToVHDL::checkDocument() { - // filter unsupported stuff - std::list<DOMElement *> unsupported; - unsupported = DOMUtils::inDocumentOrder({ - XML_PREFIX(_scxml).str() + "datamodel", - XML_PREFIX(_scxml).str() + "data", - XML_PREFIX(_scxml).str() + "assign", - XML_PREFIX(_scxml).str() + "donedata", - XML_PREFIX(_scxml).str() + "content", - XML_PREFIX(_scxml).str() + "param", - XML_PREFIX(_scxml).str() + "script", - XML_PREFIX(_scxml).str() + "parallel", - XML_PREFIX(_scxml).str() + "history", - XML_PREFIX(_scxml).str() + "if", - XML_PREFIX(_scxml).str() + "foreach", - XML_PREFIX(_scxml).str() + "send", - XML_PREFIX(_scxml).str() + "cancel", - XML_PREFIX(_scxml).str() + "invoke", - XML_PREFIX(_scxml).str() + "finalize" - }, _scxml); - - std::stringstream ss; - if (unsupported.size() > 0) { - for (auto elem : unsupported) { - ss << " " << DOMUtils::xPathForNode(elem) << " unsupported" << std::endl; - } - throw std::runtime_error("Unsupported elements found:\n" + ss.str()); - } - - unsupported = DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "transition"}, _scxml); - - for (auto transition : unsupported) { - if (HAS_ATTR(transition, "cond")) { - ERROR_PLATFORM_THROW("transition with conditions not supported!"); - } - if (!HAS_ATTR(transition, "target")) { - ERROR_PLATFORM_THROW("targetless transition not supported!"); - } - } - - } - - void ChartToVHDL::findEvents() { - // elements with an event attribute - std::list<DOMElement *> withEvents = DOMUtils::inDocumentOrder({ - XML_PREFIX(_scxml).str() + "raise", - XML_PREFIX(_scxml).str() + "send", - XML_PREFIX(_scxml).str() + "transition", - }, _scxml); - - for (auto withEvent : withEvents) { +using namespace XERCESC_NS; + +Transformer ChartToVHDL::transform(const Interpreter &other) { + ChartToVHDL *c2c = new ChartToVHDL(other); + + return std::shared_ptr<TransformerImpl>(c2c); +} + +ChartToVHDL::ChartToVHDL(const Interpreter &other) : ChartToC(other), _eventTrie(".") { +} + +ChartToVHDL::~ChartToVHDL() { +} + +void ChartToVHDL::checkDocument() { + // filter unsupported stuff + std::list<DOMElement *> unsupported; + unsupported = DOMUtils::inDocumentOrder({ + XML_PREFIX(_scxml).str() + "datamodel", + XML_PREFIX(_scxml).str() + "data", + XML_PREFIX(_scxml).str() + "assign", + XML_PREFIX(_scxml).str() + "donedata", + XML_PREFIX(_scxml).str() + "content", + XML_PREFIX(_scxml).str() + "param", + XML_PREFIX(_scxml).str() + "script", + XML_PREFIX(_scxml).str() + "parallel", + XML_PREFIX(_scxml).str() + "history", + XML_PREFIX(_scxml).str() + "if", + XML_PREFIX(_scxml).str() + "foreach", + XML_PREFIX(_scxml).str() + "send", + XML_PREFIX(_scxml).str() + "cancel", + XML_PREFIX(_scxml).str() + "invoke", + XML_PREFIX(_scxml).str() + "finalize" + }, _scxml); + + std::stringstream ss; + if (unsupported.size() > 0) { + for (auto elem : unsupported) { + ss << " " << DOMUtils::xPathForNode(elem) << " unsupported" << std::endl; + } + throw std::runtime_error("Unsupported elements found:\n" + ss.str()); + } + + unsupported = DOMUtils::inDocumentOrder({XML_PREFIX(_scxml).str() + "transition"}, _scxml); + + for (auto transition : unsupported) { + if (HAS_ATTR(transition, "cond")) { + ERROR_PLATFORM_THROW("transition with conditions not supported!"); + } + if (!HAS_ATTR(transition, "target")) { + ERROR_PLATFORM_THROW("targetless transition not supported!"); + } + } + +} + +void ChartToVHDL::findEvents() { + // elements with an event attribute + std::list<DOMElement *> withEvents = DOMUtils::inDocumentOrder({ + XML_PREFIX(_scxml).str() + "raise", + XML_PREFIX(_scxml).str() + "send", + XML_PREFIX(_scxml).str() + "transition", + }, _scxml); + + for (auto withEvent : withEvents) { // if (HAS_ATTR_CAST(withEvent, "event")) { // if (ATTR_CAST(withEvent, "event") != "*") // _eventTrie.addWord(ATTR_CAST(withEvent, "event")); // } - // Tokenized version below - - if (HAS_ATTR_CAST(withEvent, "event")) { - std::string eventNames = ATTR_CAST(withEvent, "event"); - std::list<std::string> events = tokenize(eventNames); - for (std::list<std::string>::iterator eventIter = events.begin(); - eventIter != events.end(); eventIter++) { - std::string eventName = *eventIter; - if (boost::ends_with(eventName, "*")) - eventName = eventName.substr(0, eventName.size() - 1); - if (boost::ends_with(eventName, ".")) - eventName = eventName.substr(0, eventName.size() - 1); - if (eventName.size() > 0) - _eventTrie.addWord(eventName); - } - - //TODO implement "done" event - // --> enter a final from a compound state not <scxml> (also prevent setting completed_o) - // --> all final children from a parallel are entered - //TODO implement error events --> set by output logic to a signal line - } - - - } - - _execContent = DOMUtils::inDocumentOrder({ - XML_PREFIX(_scxml).str() + "raise", - XML_PREFIX(_scxml).str() + "send" - }, _scxml); - - } - - bool ChartToVHDL::filterSupportedExecContent(DOMElement *execContentElement) { - return (TAGNAME(execContentElement) == XML_PREFIX(_scxml).str() + "raise" || - TAGNAME(execContentElement) == XML_PREFIX(_scxml).str() + "send"); - } - - void ChartToVHDL::writeTo(std::ostream &stream) { - // checkDocument(); - findEvents(); - - - stream << "-- generated from " << std::string(_baseURL) << std::endl; - stream << "-- run as " << std::endl; - stream << "-- ghdl --clean && ghdl -a foo.vhdl && ghdl -e tb && ./tb --stop-time=10ms --vcd=tb.vcd" << - std::endl; - stream << "-- gtkwave tb.vcd" << std::endl; - stream << std::endl; - - writeTypes(stream); - writeFiFo(stream); - writeEventController(stream); - writeMicroStepper(stream); - writeTestbench(stream); - } - - void ChartToVHDL::writeTypes(std::ostream &stream) { - std::string seperator; - - stream << "-- required global types" << std::endl; - stream << "library IEEE;" << std::endl; - stream << "use IEEE.std_logic_1164.all;" << std::endl; - stream << std::endl; - stream << "package machine" << _md5 << " is" << std::endl; - // create state type - stream << " subtype state_type is std_logic_vector( "; - stream << _states.size() - 1; - stream << " downto 0);" << std::endl; - - std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); - stream << " type event_type is ( hwe_null, "; - seperator = ""; - - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << seperator << "hwe_" << escapeMacro((*eventIter)->value); - seperator = ", "; - } - stream << " );" << std::endl; - - stream << "end machine" << _md5 << ";" << std::endl; - stream << std::endl; - stream << "-- END needed global types" << std::endl; - } - - void ChartToVHDL::writeIncludes(std::ostream &stream) { - // Add controler specific stuff here - stream << "library IEEE;" << std::endl; - stream << "use IEEE.std_logic_1164.all;" << std::endl; - stream << "use work.machine" << _md5 << ".all;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeTestbench(std::ostream &stream) { - - stream << "-- TESTBENCH" << std::endl; - writeIncludes(stream); - stream << std::endl; - - stream << "-- empty entity" << std::endl; - stream << "entity tb is" << std::endl; - stream << "end entity tb;" << std::endl; - stream << std::endl; - - stream << "architecture behavioral of tb is" << std::endl; - stream << std::endl; - - // modules - stream << " -- Module declaration" << std::endl; - stream << " component micro_stepper is" << std::endl; - stream << " port (" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk :in std_logic;" << std::endl; - stream << " rst_i :in std_logic;" << std::endl; - stream << " en :in std_logic;" << std::endl; - stream << " next_event_i :in event_type;" << std::endl; - stream << " next_event_we_i :in std_logic;" << std::endl; - stream << " --outputs" << std::endl; - stream << " error_o :out std_logic;" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") << "_o :out std_logic;" - << std::endl; - } - } - - stream << " completed_o :out std_logic" << std::endl; - stream << " );" << std::endl; - stream << " end component;" << std::endl; - stream << std::endl; - - stream << " component event_controller is" << std::endl; - stream << " port(" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk :in std_logic;" << std::endl; - stream << " rst_i :in std_logic;" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") - << "_i :in std_logic;" << std::endl; - } - } - stream << " --outputs" << std::endl; - stream << " micro_stepper_en_o :out std_logic;" << std::endl; - stream << " event_o :out event_type;" << std::endl; - stream << " event_we_o :out std_logic" << std::endl; - // stream << " done_o :out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end component; " << std::endl; - - // signals - stream << " -- input" << std::endl; - stream << " signal clk : std_logic := '0';" << std::endl; - stream << " signal reset : std_logic;" << std::endl; - stream << " signal dut_enable : std_logic;" << std::endl; - stream << " signal next_event_we_i : std_logic;" << std::endl; - stream << " signal next_event_i : event_type;" << std::endl; - stream << std::endl; - - stream << " -- output" << std::endl; - stream << " signal error_o, completed_o : std_logic;" << std::endl; - stream << std::endl; - - stream << " -- wiring" << std::endl; - for (auto state : _states) { - stream << " signal state_active_" << ATTR(state, "documentOrder") - << "_sig : std_logic;" << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " signal entry_set_" << ATTR(state, "documentOrder") - << "_sig : std_logic;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " signal exit_set_" << ATTR(state, "documentOrder") - << "_sig : std_logic;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " signal transition_set_" << ATTR(transition, "postFixOrder") - << "_sig : std_logic;" << std::endl; - } - } - - // wiring - stream << "begin" << std::endl; - stream << " clk <= not clk after 20 ns; -- 25 MHz clock frequency" << std::endl; - stream << " reset <= '1', '0' after 100 ns; -- generates reset signal: --__" << std::endl; - stream << std::endl; - - stream << " -- Module instantiation" << std::endl; - stream << " dut : micro_stepper" << std::endl; - stream << " port map (" << std::endl; - stream << " clk => clk," << std::endl; - stream << " rst_i => reset," << std::endl; - stream << " en => dut_enable," << std::endl; - stream << std::endl; - - stream << " next_event_i => next_event_i," << std::endl; - stream << " next_event_we_i => next_event_we_i," << std::endl; - stream << " error_o => error_o," << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") - << "_o => state_active_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") - << "_o => entry_set_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") - << "_o => exit_set_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") - << "_o => transition_set_" << ATTR(transition, "postFixOrder") - << "_sig," << std::endl; - } - } - - stream << " completed_o => completed_o" << std::endl; - stream << " );" << std::endl; - stream << std::endl; - - stream << " ec : event_controller" << std::endl; - stream << " port map (" << std::endl; - stream << " clk => clk," << std::endl; - stream << " rst_i => reset," << std::endl; - stream << std::endl; - - stream << " event_o => next_event_i," << std::endl; - stream << " event_we_o => next_event_we_i," << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") - << "_i => state_active_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") - << "_i => entry_set_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") - << "_i => exit_set_" << ATTR(state, "documentOrder") - << "_sig," << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") - << "_i => transition_set_" << ATTR(transition, "postFixOrder") - << "_sig," << std::endl; - } - } - - stream << " micro_stepper_en_o => dut_enable" << std::endl; - // stream << " done_o => open" << std::endl; - stream << " );" << std::endl; - stream << std::endl; - - // find pass state - std::list<DOMElement *> topLevelFinal = - DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "final", _scxml); - - std::string passStateNo = ""; - for (auto final : topLevelFinal) { - if (ATTR(final, "id") == "pass") { - passStateNo = ATTR(final, "documentOrder"); - } - } - - stream << " -- Test observation" << std::endl; - stream << " process (clk)" << std::endl; - stream << " variable count_clk : integer := 0;" << std::endl; - stream << " begin" << std::endl; - stream << " if rising_edge(clk) then" << std::endl; - stream << " count_clk := count_clk + 1;" << std::endl; - stream << " if (completed_o = '1') then" << std::endl; - if (!passStateNo.empty()) { - stream << " assert (state_active_" << passStateNo; - stream << "_sig = '1') report \"Complted with errors\" severity error;" << std::endl; - } - stream << " -- stop simulation" << std::endl; - stream << " assert false report \"Simulation Finished\" severity failure;" << std::endl; - stream << " else" << std::endl; - stream << " -- state machine not completed" << std::endl; - stream << " -- check if it is time to stop waiting (100 clk per state+transition+excontent)" << std::endl; - int tolleratedClocks = (_transitions.size() + _states.size() + _execContent.size()) * 100; - stream << " assert (count_clk < " << tolleratedClocks; - stream << ") report \"Clock count exceed\" severity failure;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << " end process;" << std::endl; - - stream << "end architecture;" << std::endl; - stream << "-- END TESTBENCH" << std::endl; - - } - - void ChartToVHDL::writeExContentBlock(std::ostream &stream, - std::string index, std::list<DOMElement *> commandSequence) { - // index should be [entry, transition, exit]_<index of state/transition>_<optional index for block> - - // write clock blocks - } - - void ChartToVHDL::writeEventController(std::ostream &stream) { - // Add controler specific stuff here - // create hardware top level - stream << "-- Event Controller Logic" << std::endl; - writeIncludes(stream); - stream << "entity event_controller is" << std::endl; - stream << "port(" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk :in std_logic;" << std::endl; - stream << " rst_i :in std_logic;" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") - << "_i :in std_logic;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") - << "_i :in std_logic;" << std::endl; - } - } - - stream << " --outputs" << std::endl; - stream << " micro_stepper_en_o :out std_logic;" << std::endl; - stream << " event_o :out event_type;" << std::endl; - stream << " event_we_o :out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end event_controller; " << std::endl; - - stream << std::endl; - stream << "architecture behavioral of event_controller is " << std::endl; - stream << std::endl; - - // Add signals and components - stream << "signal rst : std_logic;" << std::endl; - stream << "signal micro_stepper_en : std_logic;" << std::endl; - stream << "signal cmpl_buf : std_logic;" << std::endl; - stream << "signal completed_sig : std_logic;" << std::endl; - stream << "signal event_bus : event_type;" << std::endl; - stream << "signal event_we : std_logic;" << std::endl; - - for (int i = 0; i < _execContent.size(); i++) { - stream << "signal done_" << toStr(i) << "_sig : std_logic;" << std::endl; - stream << "signal start_" << toStr(i) << "_sig : std_logic;" << std::endl; - } - - stream << "-- sequence input line" << std::endl; - for (int i = 0; i < _execContent.size(); i++) { - stream << "signal seq_" << toStr(i) << "_sig : std_logic;" << std::endl; - } - stream << std::endl; - - stream << "begin" << std::endl; - stream << std::endl; - // system signal mapping - stream << "rst <= rst_i;" << std::endl; - stream << "micro_stepper_en_o <= micro_stepper_en;" << std::endl; - stream << "event_o <= event_bus;" << std::endl; - stream << "event_we_o <= event_we;" << std::endl; - stream << std::endl; - - // stall management - stream << "-- stalling microstepper" << std::endl; - stream << "micro_stepper_en <= completed_sig or not ( '0' "; - for (auto state : _states) { - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << std::endl << " or entry_set_" << ATTR(state, "documentOrder") - << "_i"; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << std::endl << " or exit_set_" << ATTR(state, "documentOrder") - << "_i"; - } - } - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << std::endl << " or transition_set_" << ATTR(transition, "postFixOrder") - << "_i"; - } - } - stream << ");" << std::endl; - stream << std::endl; - - // sequential code operation - stream << "-- seq code block " << std::endl; - stream << "ex_content_block : process (clk, rst) " << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - for (int i = 0; i < _execContent.size(); i++) { - stream << " done_" << toStr(i) << "_sig <= '0';" << std::endl; - } - stream << " event_bus <= hwe_null;" << std::endl; - stream << " event_we <= '0';" << std::endl; - stream << " cmpl_buf <= '0';" << std::endl; - stream << " completed_sig <= '0';" << std::endl; - stream << " elsif rising_edge(clk) then" << std::endl; - - stream << " if micro_stepper_en = '1' then" << std::endl; - stream << " cmpl_buf <= '0' ;" << std::endl; - stream << " else" << std::endl; - stream << " cmpl_buf <= seq_" << toStr(_execContent.size() - 1) - << "_sig;" << std::endl; - stream << " end if;" << std::endl; - stream << " completed_sig <= cmpl_buf;" << std::endl << std::endl; - - size_t i = 0; - std::string seperator = " "; - for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { - DOMElement *exContentElem = *ecIter; - - if (filterSupportedExecContent(exContentElem)) { - - stream << seperator << "if start_" << toStr(i) << "_sig = '1' then" - << std::endl; - stream << " event_bus <= hwe_" << escapeMacro(ATTR(exContentElem, "event")) - << ";" << std::endl; - stream << " done_" << toStr(i) << "_sig <= '1';" << std::endl; - stream << " event_we <= '1';" << std::endl; - seperator = " els"; - } - } - stream << " elsif micro_stepper_en = '1' then" << std::endl; - i = 0; - //for (auto exContentElem : _execContent) { - for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { - DOMElement *exContentElem = *ecIter; - if (filterSupportedExecContent(exContentElem)) { - stream << " done_" << toStr(i) << "_sig <= '0';" << std::endl; - } - } - stream << " event_we <= '0';" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - - i = 0; - for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { - // start lines - stream << "start_" << toStr(i) << "_sig <= " - << getLineForExecContent(*ecIter) << " and " - << "not done_" << toStr(i) << "_sig"; - - // if not needed, since seq_0_sig is hard coded as '1'. + // Tokenized version below + + if (HAS_ATTR_CAST(withEvent, "event")) { + std::string eventNames = ATTR_CAST(withEvent, "event"); + std::list<std::string> events = tokenize(eventNames); + for (std::list<std::string>::iterator eventIter = events.begin(); + eventIter != events.end(); eventIter++) { + std::string eventName = *eventIter; + if (boost::ends_with(eventName, "*")) + eventName = eventName.substr(0, eventName.size() - 1); + if (boost::ends_with(eventName, ".")) + eventName = eventName.substr(0, eventName.size() - 1); + if (eventName.size() > 0) + _eventTrie.addWord(eventName); + } + + //TODO implement "done" event + // --> enter a final from a compound state not <scxml> (also prevent setting completed_o) + // --> all final children from a parallel are entered + //TODO implement error events --> set by output logic to a signal line + } + + + } + + _execContent = DOMUtils::inDocumentOrder({ + XML_PREFIX(_scxml).str() + "raise", + XML_PREFIX(_scxml).str() + "send" + }, _scxml); + +} + +bool ChartToVHDL::filterSupportedExecContent(DOMElement *execContentElement) { + return (TAGNAME(execContentElement) == XML_PREFIX(_scxml).str() + "raise" || + TAGNAME(execContentElement) == XML_PREFIX(_scxml).str() + "send"); +} + +void ChartToVHDL::writeTo(std::ostream &stream) { + // checkDocument(); + findEvents(); + + + stream << "-- generated from " << std::string(_baseURL) << std::endl; + stream << "-- run as " << std::endl; + stream << "-- ghdl --clean && ghdl -a foo.vhdl && ghdl -e tb && ./tb --stop-time=10ms --vcd=tb.vcd" << + std::endl; + stream << "-- gtkwave tb.vcd" << std::endl; + stream << std::endl; + + writeTypes(stream); + writeFiFo(stream); + writeEventController(stream); + writeMicroStepper(stream); + writeTestbench(stream); +} + +void ChartToVHDL::writeTypes(std::ostream &stream) { + std::string seperator; + + stream << "-- required global types" << std::endl; + stream << "library IEEE;" << std::endl; + stream << "use IEEE.std_logic_1164.all;" << std::endl; + stream << std::endl; + stream << "package machine" << _md5 << " is" << std::endl; + // create state type + stream << " subtype state_type is std_logic_vector( "; + stream << _states.size() - 1; + stream << " downto 0);" << std::endl; + + std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); + stream << " type event_type is ( hwe_null, "; + seperator = ""; + + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << seperator << "hwe_" << escapeMacro((*eventIter)->value); + seperator = ", "; + } + stream << " );" << std::endl; + + stream << "end machine" << _md5 << ";" << std::endl; + stream << std::endl; + stream << "-- END needed global types" << std::endl; +} + +void ChartToVHDL::writeIncludes(std::ostream &stream) { + // Add controler specific stuff here + stream << "library IEEE;" << std::endl; + stream << "use IEEE.std_logic_1164.all;" << std::endl; + stream << "use work.machine" << _md5 << ".all;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeTestbench(std::ostream &stream) { + + stream << "-- TESTBENCH" << std::endl; + writeIncludes(stream); + stream << "use std.env.all;" << std::endl; + stream << std::endl; + + stream << "-- empty entity" << std::endl; + stream << "entity tb is" << std::endl; + stream << "end entity tb;" << std::endl; + stream << std::endl; + + stream << "architecture behavioral of tb is" << std::endl; + stream << std::endl; + + // modules + stream << " -- Module declaration" << std::endl; + stream << " component micro_stepper is" << std::endl; + stream << " port (" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk :in std_logic;" << std::endl; + stream << " rst_i :in std_logic;" << std::endl; + stream << " en :in std_logic;" << std::endl; + stream << " next_event_i :in event_type;" << std::endl; + stream << " next_event_we_i :in std_logic;" << std::endl; + stream << " --outputs" << std::endl; + stream << " error_o :out std_logic;" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") << "_o :out std_logic;" + << std::endl; + } + } + + stream << " completed_o :out std_logic" << std::endl; + stream << " );" << std::endl; + stream << " end component;" << std::endl; + stream << std::endl; + + stream << " component event_controller is" << std::endl; + stream << " port(" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk :in std_logic;" << std::endl; + stream << " rst_i :in std_logic;" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") + << "_i :in std_logic;" << std::endl; + } + } + stream << " --outputs" << std::endl; + stream << " micro_stepper_en_o :out std_logic;" << std::endl; + stream << " event_o :out event_type;" << std::endl; + stream << " event_we_o :out std_logic" << std::endl; + // stream << " done_o :out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end component; " << std::endl; + + // signals + stream << " -- input" << std::endl; + stream << " signal clk : std_logic := '0';" << std::endl; + stream << " signal reset : std_logic;" << std::endl; + stream << " signal dut_enable : std_logic;" << std::endl; + stream << " signal next_event_we_i : std_logic;" << std::endl; + stream << " signal next_event_i : event_type;" << std::endl; + stream << std::endl; + + stream << " -- output" << std::endl; + stream << " signal error_o, completed_o : std_logic;" << std::endl; + stream << std::endl; + + stream << " -- wiring" << std::endl; + for (auto state : _states) { + stream << " signal state_active_" << ATTR(state, "documentOrder") + << "_sig : std_logic;" << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " signal entry_set_" << ATTR(state, "documentOrder") + << "_sig : std_logic;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " signal exit_set_" << ATTR(state, "documentOrder") + << "_sig : std_logic;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " signal transition_set_" << ATTR(transition, "postFixOrder") + << "_sig : std_logic;" << std::endl; + } + } + + // wiring + stream << "begin" << std::endl; + stream << " clk <= not clk after 20 ns; -- 25 MHz clock frequency" << std::endl; + stream << " reset <= '1', '0' after 100 ns; -- generates reset signal: --__" << std::endl; + stream << std::endl; + + stream << " -- Module instantiation" << std::endl; + stream << " dut : micro_stepper" << std::endl; + stream << " port map (" << std::endl; + stream << " clk => clk," << std::endl; + stream << " rst_i => reset," << std::endl; + stream << " en => dut_enable," << std::endl; + stream << std::endl; + + stream << " next_event_i => next_event_i," << std::endl; + stream << " next_event_we_i => next_event_we_i," << std::endl; + stream << " error_o => error_o," << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") + << "_o => state_active_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") + << "_o => entry_set_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") + << "_o => exit_set_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") + << "_o => transition_set_" << ATTR(transition, "postFixOrder") + << "_sig," << std::endl; + } + } + + stream << " completed_o => completed_o" << std::endl; + stream << " );" << std::endl; + stream << std::endl; + + stream << " ec : event_controller" << std::endl; + stream << " port map (" << std::endl; + stream << " clk => clk," << std::endl; + stream << " rst_i => reset," << std::endl; + stream << std::endl; + + stream << " event_o => next_event_i," << std::endl; + stream << " event_we_o => next_event_we_i," << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") + << "_i => state_active_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") + << "_i => entry_set_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") + << "_i => exit_set_" << ATTR(state, "documentOrder") + << "_sig," << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") + << "_i => transition_set_" << ATTR(transition, "postFixOrder") + << "_sig," << std::endl; + } + } + + stream << " micro_stepper_en_o => dut_enable" << std::endl; + // stream << " done_o => open" << std::endl; + stream << " );" << std::endl; + stream << std::endl; + + // find pass state + std::list<DOMElement *> topLevelFinal = + DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "final", _scxml); + + std::string passStateNo = ""; + for (auto final : topLevelFinal) { + if (ATTR(final, "id") == "pass") { + passStateNo = ATTR(final, "documentOrder"); + } + } + + stream << " -- Test observation" << std::endl; + stream << " process (clk)" << std::endl; + stream << " variable count_clk : integer := 0;" << std::endl; + stream << " begin" << std::endl; + stream << " if rising_edge(clk) then" << std::endl; + stream << " count_clk := count_clk + 1;" << std::endl; + stream << " if (completed_o = '1') then" << std::endl; + if (!passStateNo.empty()) { + stream << " assert (state_active_" << passStateNo; + stream << "_sig = '1') report \"Complted with errors\" severity error;" << std::endl; + } + stream << " -- stop simulation" << std::endl; + stream << " finish(1);" << std::endl; +// -- For both STOP and FINISH the STATUS values are those used +// -- in the Verilog $finish task +// -- 0 prints nothing +// -- 1 prints simulation time and location +// -- 2 prints simulation time, location, and statistics about +// -- the memory and CPU times used in simulation + //stream << " assert false report \"Simulation Finished\" severity failure;" << std::endl; + stream << " else" << std::endl; + stream << " -- state machine not completed" << std::endl; + stream << " -- check if it is time to stop waiting (100 clk per state+transition+excontent)" << std::endl; + int tolleratedClocks = (_transitions.size() + _states.size() + _execContent.size()) * 100; + stream << " assert (count_clk < " << tolleratedClocks; + stream << ") report \"Clock count exceed\" severity failure;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << " end process;" << std::endl; + + stream << "end architecture;" << std::endl; + stream << "-- END TESTBENCH" << std::endl; + +} + +void ChartToVHDL::writeExContentBlock(std::ostream &stream, + std::string index, std::list<DOMElement *> commandSequence) { + // index should be [entry, transition, exit]_<index of state/transition>_<optional index for block> + + // write clock blocks +} + +void ChartToVHDL::writeEventController(std::ostream &stream) { + // Add controler specific stuff here + // create hardware top level + stream << "-- Event Controller Logic" << std::endl; + writeIncludes(stream); + stream << "entity event_controller is" << std::endl; + stream << "port(" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk :in std_logic;" << std::endl; + stream << " rst_i :in std_logic;" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") + << "_i :in std_logic;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") + << "_i :in std_logic;" << std::endl; + } + } + + stream << " --outputs" << std::endl; + stream << " micro_stepper_en_o :out std_logic;" << std::endl; + stream << " event_o :out event_type;" << std::endl; + stream << " event_we_o :out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end event_controller; " << std::endl; + + stream << std::endl; + stream << "architecture behavioral of event_controller is " << std::endl; + stream << std::endl; + + // Add signals and components + stream << "signal rst : std_logic;" << std::endl; + stream << "signal micro_stepper_en : std_logic;" << std::endl; + stream << "signal cmpl_buf : std_logic;" << std::endl; + stream << "signal completed_sig : std_logic;" << std::endl; + stream << "signal event_bus : event_type;" << std::endl; + stream << "signal event_we : std_logic;" << std::endl; + + for (int i = 0; i < _execContent.size(); i++) { + stream << "signal done_" << toStr(i) << "_sig : std_logic;" << std::endl; + stream << "signal start_" << toStr(i) << "_sig : std_logic;" << std::endl; + } + + stream << "-- sequence input line" << std::endl; + for (int i = 0; i < _execContent.size(); i++) { + stream << "signal seq_" << toStr(i) << "_sig : std_logic;" << std::endl; + } + stream << std::endl; + + stream << "begin" << std::endl; + stream << std::endl; + // system signal mapping + stream << "rst <= rst_i;" << std::endl; + stream << "micro_stepper_en_o <= micro_stepper_en;" << std::endl; + stream << "event_o <= event_bus;" << std::endl; + stream << "event_we_o <= event_we;" << std::endl; + stream << std::endl; + + // stall management + stream << "-- stalling microstepper" << std::endl; + stream << "micro_stepper_en <= completed_sig or not ( '0' "; + for (auto state : _states) { + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << std::endl << " or entry_set_" << ATTR(state, "documentOrder") + << "_i"; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << std::endl << " or exit_set_" << ATTR(state, "documentOrder") + << "_i"; + } + } + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << std::endl << " or transition_set_" << ATTR(transition, "postFixOrder") + << "_i"; + } + } + stream << ");" << std::endl; + stream << std::endl; + + // sequential code operation + stream << "-- seq code block " << std::endl; + stream << "ex_content_block : process (clk, rst) " << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + for (int i = 0; i < _execContent.size(); i++) { + stream << " done_" << toStr(i) << "_sig <= '0';" << std::endl; + } + stream << " event_bus <= hwe_null;" << std::endl; + stream << " event_we <= '0';" << std::endl; + stream << " cmpl_buf <= '0';" << std::endl; + stream << " completed_sig <= '0';" << std::endl; + stream << " elsif rising_edge(clk) then" << std::endl; + + stream << " if micro_stepper_en = '1' then" << std::endl; + stream << " cmpl_buf <= '0' ;" << std::endl; + stream << " else" << std::endl; + stream << " cmpl_buf <= seq_" << toStr(_execContent.size() - 1) + << "_sig;" << std::endl; + stream << " end if;" << std::endl; + stream << " completed_sig <= cmpl_buf;" << std::endl << std::endl; + + size_t i = 0; + std::string seperator = " "; + for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { + DOMElement *exContentElem = *ecIter; + + if (filterSupportedExecContent(exContentElem)) { + + stream << seperator << "if start_" << toStr(i) << "_sig = '1' then" + << std::endl; + stream << " event_bus <= hwe_" << escapeMacro(ATTR(exContentElem, "event")) + << ";" << std::endl; + stream << " done_" << toStr(i) << "_sig <= '1';" << std::endl; + stream << " event_we <= '1';" << std::endl; + seperator = " els"; + } + } + stream << " elsif micro_stepper_en = '1' then" << std::endl; + i = 0; + //for (auto exContentElem : _execContent) { + for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { + DOMElement *exContentElem = *ecIter; + if (filterSupportedExecContent(exContentElem)) { + stream << " done_" << toStr(i) << "_sig <= '0';" << std::endl; + } + } + stream << " event_we <= '0';" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; + + i = 0; + for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { + // start lines + stream << "start_" << toStr(i) << "_sig <= " + << getLineForExecContent(*ecIter) << " and " + << "not done_" << toStr(i) << "_sig"; + + // if not needed, since seq_0_sig is hard coded as '1'. // if (i != 0) { // if not first element - stream << " and seq_" << toStr(i) << "_sig"; + stream << " and seq_" << toStr(i) << "_sig"; // } - stream << ";" << std::endl; - - } - - stream << "seq_0_sig <= '1';" << std::endl; - - if (_execContent.size() > 1) { - i = 0; - for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { - // prevent writing seq_0_sig since this should be hardcoded to '1' - if (i != 0) { - // seq lines (input if process i is in seqence now) - stream << "seq_" << toStr(i) << "_sig <= " - << "done_" << toStr(i - 1) << "_sig or " - << "( not " - << getLineForExecContent(*ecIter); - stream << " and seq_" << toStr(i - 1) << "_sig"; - stream << " );" << std::endl; - } - } - } - stream << std::endl; - - stream << "end behavioral; " << std::endl; - stream << "-- END Event Controller Logic" << std::endl; - stream << std::endl; - } - - std::string ChartToVHDL::getLineForExecContent(const DOMNode *elem) { - const DOMNode *ecBlock = elem; - while (ecBlock) { - if (ecBlock->getNodeType() == DOMNode::ELEMENT_NODE) { - std::string localName = LOCALNAME_CAST(ecBlock); - if (localName == XML_PREFIX(_scxml).str() + "transition") { - return "transition_set_" + ATTR_CAST(ecBlock, "postFixOrder") + "_i"; - } - - if (localName == XML_PREFIX(_scxml).str() + "onentry") { - return "entry_set_" + ATTR_CAST(ecBlock->getParentNode(), "documentOrder") + "_i"; - } - - if (localName == XML_PREFIX(_scxml).str() + "onexit") { - return "exit_set_" + ATTR_CAST(ecBlock->getParentNode(), "documentOrder") + "_i"; - } - - } - ecBlock = ecBlock->getParentNode(); - } - - return ""; - } - - void ChartToVHDL::writeMicroStepper(std::ostream &stream) { - // create MicroStepper top level - stream << "-- FSM Logic" << std::endl; - writeIncludes(stream); - stream << "entity micro_stepper is" << std::endl; - stream << "port(" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk :in std_logic;" << std::endl; - stream << " rst_i :in std_logic;" << std::endl; - stream << " en :in std_logic;" << std::endl; - stream << " next_event_i :in event_type;" << std::endl; - stream << " next_event_we_i :in std_logic;" << std::endl; - stream << " --outputs" << std::endl; - stream << " error_o :out std_logic;" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << " entry_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << " exit_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << " transition_set_" << ATTR(transition, "postFixOrder") << "_o :out std_logic;" - << std::endl; - } - } - - stream << " completed_o :out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end micro_stepper; " << std::endl; - - stream << std::endl; - stream << "architecture behavioral of micro_stepper is " << std::endl; - stream << std::endl; - - // Add signals and components - writeSignalsAndComponents(stream); - - stream << std::endl; - stream << "begin" << std::endl; - stream << std::endl; - - // signal mapping - writeModuleInstantiation(stream); - - // signal handler - writeSpontaneousHandler(stream); - writeErrorHandler(stream); - writeInternalEventHandler(stream); - writeStateHandler(stream); - writeResetHandler(stream); - - // combinatorial logic for Sn+1 - writeOptimalTransitionSetSelection(stream); - writeExitSet(stream); - writeCompleteEntrySet(stream); - writeEntrySet(stream); - //writeDefaultCompletions(stream); - writeActiveStateNplusOne(stream); - - // connect output signals - writeSystemSignalMapping(stream); - - - stream << std::endl; - stream << "end behavioral; " << std::endl; - stream << "-- END FSM Logic" << std::endl; - } - - void ChartToVHDL::writeFiFo(std::ostream &stream) { - // taken from: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ - // alternativly take fifo logic for a ram device: http://www.eng.auburn.edu/~strouce/class/elec4200/vhdlmods.pdf - stream << "-- standard FIFO buffer" << std::endl; - writeIncludes(stream); - stream << "" << std::endl; - stream << "entity std_fifo is" << std::endl; - stream << "generic (" << std::endl; - stream << " constant FIFO_DEPTH : positive := 256" << std::endl; - stream << ");" << std::endl; - stream << "port ( " << std::endl; - stream << " clk : in std_logic;" << std::endl; - stream << " rst : in std_logic;" << std::endl; - stream << " write_en : in std_logic;" << std::endl; - stream << " read_en : in std_logic;" << std::endl; - stream << " data_in : in event_type;" << std::endl; - stream << " data_out : out event_type;" << std::endl; - stream << " empty : out std_logic;" << std::endl; - stream << " full : out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end std_fifo;" << std::endl; - stream << "" << std::endl; - stream << "architecture behavioral of std_fifo is" << std::endl; - stream << "begin" << std::endl; - stream << "-- Memory Pointer Process" << std::endl; - stream << "fifo_proc : process (clk)" << std::endl; - stream << " type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of event_type;" << std::endl; - stream << " variable Memory : FIFO_Memory;" << std::endl; - stream << "" << std::endl; - stream << " variable Head : natural range 0 to FIFO_DEPTH - 1;" << std::endl; - stream << " variable Tail : natural range 0 to FIFO_DEPTH - 1;" << std::endl; - stream << "" << std::endl; - stream << " variable Looped : boolean;" << std::endl; - stream << "begin" << std::endl; - stream << " if rising_edge(clk) then" << std::endl; - stream << " if rst = '1' then" << std::endl; - stream << " Head := 0;" << std::endl; - stream << " Tail := 0;" << std::endl; - stream << "" << std::endl; - stream << " Looped := false;" << std::endl; - stream << "" << std::endl; - stream << " full <= '0';" << std::endl; - stream << " empty <= '1';" << std::endl; - stream << " else" << std::endl; - stream << " if (read_en = '1') then" << std::endl; - stream << " if ((Looped = true) or (Head /= Tail)) then" << std::endl; - stream << " -- Update data output" << std::endl; - stream << " data_out <= Memory(Tail);" << std::endl; - stream << " " << std::endl; - stream << " -- Update Tail pointer as needed" << std::endl; - stream << " if (Tail = FIFO_DEPTH - 1) then" << std::endl; - stream << " Tail := 0;" << std::endl; - stream << " " << std::endl; - stream << " Looped := false;" << std::endl; - stream << " else" << std::endl; - stream << " Tail := Tail + 1;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " if (write_en = '1') then" << std::endl; - stream << " if ((Looped = false) or (Head /= Tail)) then" << std::endl; - stream << " -- Write Data to Memory" << std::endl; - stream << " Memory(Head) := data_in;" << std::endl; - stream << " " << std::endl; - stream << " -- Increment Head pointer as needed" << std::endl; - stream << " if (Head = FIFO_DEPTH - 1) then" << std::endl; - stream << " Head := 0;" << std::endl; - stream << " " << std::endl; - stream << " Looped := true;" << std::endl; - stream << " else" << std::endl; - stream << " Head := Head + 1;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " -- Update empty and full flags" << std::endl; - stream << " if (Head = Tail) then" << std::endl; - stream << " if Looped then" << std::endl; - stream << " full <= '1';" << std::endl; - stream << " else" << std::endl; - stream << " empty <= '1';" << std::endl; - stream << " end if;" << std::endl; - stream << " else" << std::endl; - stream << " empty <= '0';" << std::endl; - stream << " full <= '0';" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << "" << std::endl; - stream << "end behavioral;" << std::endl; - stream << "-- END standard FIFO buffer" << std::endl; - } - - void ChartToVHDL::writeSignalsAndComponents(std::ostream &stream) { - // create internal signals - stream << "-- system signals" << std::endl; - stream << "signal stall : std_logic;" << std::endl; - stream << "signal completed_sig : std_logic;" << std::endl; - stream << "signal rst : std_logic;" << std::endl; - stream << std::endl; - - stream << "-- state signals" << std::endl; - - std::list<std::string> signalDecls; - - for (auto state : _states) { - std::string parent = ATTR(state, "parent"); - - signalDecls.push_back("signal state_active_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal state_next_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal in_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal in_exit_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - - // not needed for <scxml> state - if (parent.size() != 0) { - signalDecls.push_back( - "signal in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - } - } - - signalDecls.sort(); - for (std::list<std::string>::iterator iter = signalDecls.begin(); iter != signalDecls.end(); iter++) { - stream << *iter << std::endl; - } - stream << std::endl; - - - stream << "-- transition signals" << std::endl; - stream << "signal spontaneous_en : std_logic;" << std::endl; - stream << "signal spontaneous_active : std_logic;" << std::endl; - stream << "signal optimal_transition_set_combined_sig : std_logic;" << std::endl; - - for (auto transition : _transitions) { - stream << "signal in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig : std_logic;" - << std::endl; - } - stream << std::endl; - - stream << "-- event signals" << std::endl; - stream << "signal int_event_write_en : std_logic;" << std::endl; - stream << "signal int_event_read_en : std_logic;" << std::endl; - stream << "signal int_event_empty : std_logic;" << std::endl; - stream << "signal int_event_input : event_type;" << std::endl; - stream << "signal int_event_output : event_type;" << std::endl; - stream << "signal next_event_re : std_logic;" << std::endl; - stream << "signal next_event_dequeued : std_logic;" << std::endl; - stream << "signal next_event : event_type;" << std::endl; - stream << "signal event_consumed : std_logic;" << std::endl; - stream << std::endl; - - std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << "signal event_" << escapeMacro((*eventIter)->value) << "_sig : std_logic;" << std::endl; - } - stream << std::endl; - - stream << "-- error signals" << std::endl; - stream << "signal reg_error_out : std_logic;" << std::endl; - stream << "signal error_full_int_event_fifo : std_logic;" << std::endl; - stream << std::endl; - - // add components - stream << "-- event FIFO" << std::endl; - stream << "component std_fifo is" << std::endl; - stream << "port ( " << std::endl; - stream << " clk : in std_logic;" << std::endl; - stream << " rst : in std_logic;" << std::endl; - stream << " write_en : in std_logic;" << std::endl; - stream << " read_en : in std_logic;" << std::endl; - stream << " data_in : in event_type;" << std::endl; - stream << " data_out : out event_type;" << std::endl; - stream << " empty : out std_logic;" << std::endl; - stream << " full : out std_logic" << std::endl; // we calculate how much we need - stream << ");" << std::endl; - stream << "end component;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeModuleInstantiation(std::ostream &stream) { - // instantiate event fifo - stream << "int_event_fifo : component std_fifo " << std::endl; - stream << "port map ( " << std::endl; - stream << " clk => clk," << std::endl; - stream << " rst => rst_i," << std::endl; - stream << " write_en => int_event_write_en," << std::endl; - stream << " read_en => int_event_read_en," << std::endl; - stream << " data_in => int_event_input," << std::endl; - stream << " data_out => int_event_output," << std::endl; - stream << " empty => int_event_empty," << std::endl; - stream << " full => error_full_int_event_fifo" << std::endl; // we calculate how much we need - stream << ");" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeErrorHandler(std::ostream &stream) { - // sets error output signal if an error occures somewhere - stream << "-- error handler" << std::endl; - stream << "-- sets error output signal if an error occures somewhere" << std::endl; - stream << "error_handler : process (clk, rst) " << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - stream << " reg_error_out <= '0';" << std::endl; - stream << " elsif rising_edge(clk) then" << std::endl; - stream << " reg_error_out <= error_full_int_event_fifo;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeResetHandler(std::ostream &stream) { - stream << "-- reset handler" << std::endl; - stream << "rst <= rst_i;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeSpontaneousHandler(std::ostream &stream) { - // sets spontaneous signal - stream << "-- spontaneous handler" << std::endl; - stream << "spontaneous_handler : process (clk, rst) " << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - stream << " spontaneous_en <= '1';" << std::endl; - stream << " elsif rising_edge(clk) and stall = '0' then" << std::endl; - stream << " if spontaneous_en = '1' then" << std::endl; - stream << " spontaneous_en <= optimal_transition_set_combined_sig;" << std::endl; - stream << " else" << std::endl; - //if new event is dequeued then 1 else stay 0 - stream << " spontaneous_en <= next_event_dequeued;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeInternalEventHandler(std::ostream &stream) { - // Add controler specific stuff here - stream << "-- event handler" << std::endl; - stream << "-- pops events and set event signals" << std::endl; - stream << "event_handler : process (clk, rst) " << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - - std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; - } - - stream << " next_event_dequeued <= '0';" << std::endl; - stream << " event_consumed <= '0';" << std::endl; - - stream << " elsif falling_edge(clk) and stall = '0' then" << std::endl; - - VContainer eventConsumed = VOR; - for (auto transition : _transitions) { - - if (HAS_ATTR(transition, "event") == true) { - *eventConsumed += VLINE("in_optimal_transition_set_" - + ATTR(transition, "postFixOrder") + "_sig"); - } - } - - VBranch *tree = (VASSIGN, - VLINE("event_consumed"), - eventConsumed); - tree->print(stream); - stream << ";" << std::endl; - - stream << " if int_event_empty = '0' then " << std::endl; - stream << " case next_event is " << std::endl; - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << " when hwe_" - << escapeMacro((*eventIter)->value) << " =>" << std::endl; - for (std::list<TrieNode *>::iterator eventIter2 = eventNames.begin(); - eventIter2 != eventNames.end(); eventIter2++) { - stream << " event_" << escapeMacro((*eventIter2)->value); - if (escapeMacro((*eventIter)->value) == escapeMacro((*eventIter2)->value)) { - stream << "_sig <= '1';" << std::endl; - } else { - stream << "_sig <= '0';" << std::endl; - } - } - stream << " next_event_dequeued <= '1';" << std::endl; - } - stream << " when others =>" << std::endl; - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; - } - stream << " next_event_dequeued <= '0';" << std::endl; - stream << " end case;" << std::endl; - stream << " elsif int_event_empty = '1' and event_consumed = '1' then" << std::endl; - - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; - } - stream << " next_event_dequeued <= '0';" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - - stream << "next_event_re <= not int_event_empty and not stall; " << std::endl; - stream << "next_event <= int_event_output; " << std::endl; - stream << "int_event_write_en <= next_event_we_i; " << std::endl; - stream << "int_event_input <= next_event_i; " << std::endl; - stream << "int_event_read_en <= not stall; --not spontaneous_en and " << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeActiveStateNplusOne(std::ostream &stream) { - stream << "-- active configuration" << std::endl; - - for (auto state : _states) { - std::string parent = ATTR(state, "parent"); - - // special case for <scxml> to start the state machine - if (parent.size() == 0) { - stream << " state_next_" << ATTR(state, "documentOrder") << "_sig <= " << - "not completed_sig;" << std::endl; - continue; - } - - VBranch *tree = (VASSIGN, - VLINE("state_next_" + ATTR(state, "documentOrder") + "_sig"), - (VOR, - VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), - (VAND, (VNOT, VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig")), - VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig")) - )); - - tree->print(stream); - stream << ";" << std::endl; - - } - } - - void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream &stream) { - stream << "-- optimal transition set selection" << std::endl; - VContainer optimalTransitions = VOR; - VContainer spontaneoursActive = VOR; - - for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++) { - DOMElement *transition = *transIter; - std::string conflicts = ATTR(transition, "conflictBools"); - - - VContainer nameMatchers = VOR; - if (HAS_ATTR(transition, "event")) { - std::list<std::string> eventDescs = tokenize(ATTR(transition, "event")); - for (std::list<std::string>::iterator descIter = eventDescs.begin(); - descIter != eventDescs.end(); descIter++) { - std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix( - (*descIter) == "*" ? "" : *descIter); - for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); - eventIter != eventNames.end(); eventIter++) { - *nameMatchers += VLINE("event_" + escapeMacro((*eventIter)->value) + "_sig"); - } - } - } else { - *nameMatchers += VLINE("'1'"); - } - - VContainer conflicters = VOR; - for (size_t j = 0; j < strTo<size_t>(ATTR(transition, "postFixOrder")); j++) { - if (conflicts[j] == '1') { - *conflicters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig"); - } - } - - VBranch *tree = (VASSIGN, - VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig"), - (VAND, - (HAS_ATTR(transition, "event") - ? (VNOT, VLINE("spontaneous_active")) - : (VNOP, VLINE("spontaneous_en"))), - VLINE("state_active_" + ATTR(transition, "source") + "_sig"), - nameMatchers, - (VNOT, conflicters))); - - tree->print(stream); - stream << ";" << std::endl; - - *optimalTransitions += VLINE("in_optimal_transition_set_" - + ATTR(transition, "postFixOrder") + "_sig"); - if (HAS_ATTR(transition, "event") == false) { - *spontaneoursActive += VLINE("in_optimal_transition_set_" - + ATTR(transition, "postFixOrder") + "_sig"); - } - } - - VBranch *tree = (VASSIGN, - VLINE("optimal_transition_set_combined_sig"), - optimalTransitions); - tree->print(stream); - stream << ";" << std::endl; - - VBranch *tree2 = (VASSIGN, - VLINE("spontaneous_active"), - spontaneoursActive); - tree2->print(stream); - stream << ";" << std::endl; - } - - void ChartToVHDL::writeExitSet(std::ostream &stream) { - stream << "-- exit set selection" << std::endl; - - for (auto state : _states) { - - std::string completion = ATTR(state, "completionBools"); - std::string ancestors = ATTR(state, "ancBools"); - std::string children = ATTR(state, "childBools"); - std::string parent = ATTR(state, "parent"); - - VContainer exitsetters = VOR; - for (auto transition : _transitions) { - std::string exitSet = ATTR(transition, "exitSetBools"); - if (exitSet.at(strTo<size_t>(ATTR(state, "documentOrder"))) == '1') { - *exitsetters += VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig "); - } - } - - VBranch *tree = (VASSIGN, - VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig"), - (VAND, - VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig"), - exitsetters)); - - tree->print(stream); - stream << ";" << std::endl; - } - } - - void ChartToVHDL::writeEntrySet(std::ostream &stream) { - stream << "-- entry set selection" << std::endl; - - for (auto state : _states) { - - VBranch *tree = (VASSIGN, - VLINE("in_entry_set_" + ATTR(state, "documentOrder") + "_sig"), - (VAND, - VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), - (VOR, VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig"), - (VNOT, VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig"))))); - - tree->print(stream); - stream << ";" << std::endl; - } - } - - void ChartToVHDL::writeCompleteEntrySet(std::ostream &stream) { - stream << "-- complete entry set selection" << std::endl; - - for (auto state : _states) { - std::string completion = ATTR(state, "completionBools"); - std::string ancestors = ATTR(state, "ancBools"); - std::string children = ATTR(state, "childBools"); - std::string parent = ATTR(state, "parent"); - - if (parent.size() == 0) { - continue; // skips <scxml> node - } - - - // EntrySet for every state types - VContainer optimalEntrysetters = VOR; - for (auto transition : _transitions) { - // Is this state in TargetSet of the transition? - std::string targetSet = ATTR(transition, "targetBools"); - if (targetSet[strTo<size_t>(ATTR(state, "documentOrder"))] == '1') { - //yes? then add the transition to optimal entry set of the state - *optimalEntrysetters += - VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig"); - } - } - - // if composite state (or root) we have to add ancestor completion - VContainer completeEntrysetters = VOR; - if (isCompound(state) || isParallel(state)) { - for (auto tmp_state : _states) { - // is tmp_state is child of state continue? - if (children[strTo<size_t>(ATTR(state, "documentOrder"))] == '1') { - // yes? then add its complete_entry_set_up as ancestor completion - *completeEntrysetters += - VLINE("in_complete_entry_set_up_" + ATTR(tmp_state, "documentOrder") + "_sig"); - } - } - } - - VBranch *tree = (VASSIGN, - VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), - (VOR, optimalEntrysetters, completeEntrysetters) - ); - tree->print(stream); - stream << ";" << std::endl; - } - - - // descendant completion - for (auto state : _states) { - std::string completion = ATTR(state, "completionBools"); - std::string ancestors = ATTR(state, "ancBools"); - std::string parent = ATTR(state, "parent"); //is it a int ? - - if (parent.size() == 0) { - continue; // skips <scxml> node - } - - VContainer descendantCompletion = VAND; - // if parent is compound - if (getParentState(state) != NULL && - isCompound(getParentState(state))) { - std::string children = ATTR_CAST(_states[strTo<size_t>(parent)], - "childBools"); - - std::string parentInit = ATTR(getParentState(state), "initial"); - if (// if parent has init field an this state is inside --> add it as default completion - (!parentInit.empty() - && ATTR(state, "id").compare(parentInit) == 0) || - // or add this state as default completion when parent has no init field and it is the first in document order - (parentInit.empty() && - (strTo<size_t>(ATTR(getParentState(state), "documentOrder")) + 1) == - strTo<size_t>(ATTR(state, "documentOrder")))) { - *descendantCompletion += - VLINE("in_entry_set_" + ATTR(getParentState(state), "documentOrder") + "_sig"); - - // but only if compound parent is not already completed - for (auto tmp_state : _states) { - if (tmp_state == state) { - // skip state itselve - continue; - } - if (children[strTo<size_t>(ATTR(tmp_state, "documentOrder"))] == '1') { - *descendantCompletion += (VNOT, - (VAND, - VLINE("state_active_" + ATTR(tmp_state, "documentOrder") + "_sig"), - (VNOT, - VLINE("in_exit_set_" + ATTR(tmp_state, "documentOrder") + - "_sig")))); - } - } - } else { - // disable this branche - *descendantCompletion += VLINE("'0'"); - } - } else - // if parent is parallel - if (getParentState(state) != NULL && - isParallel(getParentState(state))) { - *descendantCompletion += - VLINE("in_complete_entry_set_" + ATTR(getParentState(state), "documentOrder") + "_sig"); - } - - VBranch *tree = (VASSIGN, - VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), - (VOR, - VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), - descendantCompletion)); - - tree->print(stream); - stream << ";" << std::endl; - } - } - - void ChartToVHDL::writeStateHandler(std::ostream &stream) { - // updater for current state - stream << "-- State Handler" << std::endl; - stream << "-- updates current state" << std::endl; - stream << "state_proc: process(clk, rst, stall)" << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") << "_sig <= " << "'0';" << std::endl; - } - - stream << " in_complete_entry_set_0_sig <= '1';" << std::endl; - stream << " elsif (rising_edge(clk) and stall = '0') then" << std::endl; - stream << " in_complete_entry_set_0_sig <= '0';" << std::endl; - - for (auto state : _states) { - stream << " state_active_" << ATTR(state, "documentOrder") << "_sig <= " << "state_next_" << - ATTR(state, "documentOrder") << "_sig;" << std::endl; - } - - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeSystemSignalMapping(std::ostream &stream) { - stream << "-- system signals" << std::endl; - std::list<DOMElement *> topLevelFinal = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "final", - _scxml); - - VContainer tlf = VOR; - for (auto final : topLevelFinal) { - *tlf += VLINE("state_active_" + ATTR(final, "documentOrder") + "_sig"); - - } - - VBranch *tree = (VASSIGN, - VLINE("completed_sig"), - tlf); - - tree->print(stream); - stream << ";" << std::endl; - - // tmp mapping for events - stream << "stall <= not en or completed_sig or ( int_event_empty and not spontaneous_en ) ; " << std::endl; - stream << std::endl; - - // interface signals - stream << "-- interface signals" << std::endl; - for (auto state : _states) { - stream << "state_active_" << ATTR(state, "documentOrder") - << "_o <= state_active_" << ATTR(state, "documentOrder") - << "_sig;" << std::endl; - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { - stream << "exit_set_" << ATTR(state, "documentOrder") - << "_o <= in_exit_set_" << ATTR(state, "documentOrder") - << "_sig;" << std::endl; - } - - if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { - stream << "entry_set_" << ATTR(state, "documentOrder") - << "_o <= in_entry_set_" << ATTR(state, "documentOrder") - << "_sig;" << std::endl; - } - } - - for (auto transition : _transitions) { - if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { - stream << "transition_set_" << ATTR(transition, "postFixOrder") - << "_o <= in_optimal_transition_set_" << ATTR(transition, "postFixOrder") - << "_sig;" << std::endl; - } - } - - stream << "completed_o <= completed_sig; " << std::endl; - stream << "error_o <= reg_error_out; " << std::endl; - stream << std::endl; - } + stream << ";" << std::endl; + + } + + stream << "seq_0_sig <= '1';" << std::endl; + + if (_execContent.size() > 1) { + i = 0; + for (auto ecIter = _execContent.begin(); ecIter != _execContent.end(); ecIter++, i++) { + // prevent writing seq_0_sig since this should be hardcoded to '1' + if (i != 0) { + // seq lines (input if process i is in seqence now) + stream << "seq_" << toStr(i) << "_sig <= " + << "done_" << toStr(i - 1) << "_sig or " + << "( not " + << getLineForExecContent(*ecIter); + stream << " and seq_" << toStr(i - 1) << "_sig"; + stream << " );" << std::endl; + } + } + } + stream << std::endl; + + stream << "end behavioral; " << std::endl; + stream << "-- END Event Controller Logic" << std::endl; + stream << std::endl; +} + +std::string ChartToVHDL::getLineForExecContent(const DOMNode *elem) { + const DOMNode *ecBlock = elem; + while (ecBlock) { + if (ecBlock->getNodeType() == DOMNode::ELEMENT_NODE) { + std::string localName = LOCALNAME_CAST(ecBlock); + if (localName == XML_PREFIX(_scxml).str() + "transition") { + return "transition_set_" + ATTR_CAST(ecBlock, "postFixOrder") + "_i"; + } + + if (localName == XML_PREFIX(_scxml).str() + "onentry") { + return "entry_set_" + ATTR_CAST(ecBlock->getParentNode(), "documentOrder") + "_i"; + } + + if (localName == XML_PREFIX(_scxml).str() + "onexit") { + return "exit_set_" + ATTR_CAST(ecBlock->getParentNode(), "documentOrder") + "_i"; + } + + } + ecBlock = ecBlock->getParentNode(); + } + + return ""; +} + +void ChartToVHDL::writeMicroStepper(std::ostream &stream) { + // create MicroStepper top level + stream << "-- FSM Logic" << std::endl; + writeIncludes(stream); + stream << "entity micro_stepper is" << std::endl; + stream << "port(" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk :in std_logic;" << std::endl; + stream << " rst_i :in std_logic;" << std::endl; + stream << " en :in std_logic;" << std::endl; + stream << " next_event_i :in event_type;" << std::endl; + stream << " next_event_we_i :in std_logic;" << std::endl; + stream << " --outputs" << std::endl; + stream << " error_o :out std_logic;" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << " entry_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << " exit_set_" << ATTR(state, "documentOrder") << "_o :out std_logic;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << " transition_set_" << ATTR(transition, "postFixOrder") << "_o :out std_logic;" + << std::endl; + } + } + + stream << " completed_o :out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end micro_stepper; " << std::endl; + + stream << std::endl; + stream << "architecture behavioral of micro_stepper is " << std::endl; + stream << std::endl; + + // Add signals and components + writeSignalsAndComponents(stream); + + stream << std::endl; + stream << "begin" << std::endl; + stream << std::endl; + + // signal mapping + writeModuleInstantiation(stream); + + // signal handler + writeSpontaneousHandler(stream); + writeErrorHandler(stream); + writeInternalEventHandler(stream); + writeStateHandler(stream); + writeResetHandler(stream); + + // combinatorial logic for Sn+1 + writeOptimalTransitionSetSelection(stream); + writeExitSet(stream); + writeCompleteEntrySet(stream); + writeEntrySet(stream); + //writeDefaultCompletions(stream); + writeActiveStateNplusOne(stream); + + // connect output signals + writeSystemSignalMapping(stream); + + + stream << std::endl; + stream << "end behavioral; " << std::endl; + stream << "-- END FSM Logic" << std::endl; +} + +void ChartToVHDL::writeFiFo(std::ostream &stream) { + // taken from: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ + // alternativly take fifo logic for a ram device: http://www.eng.auburn.edu/~strouce/class/elec4200/vhdlmods.pdf + stream << "-- standard FIFO buffer" << std::endl; + writeIncludes(stream); + stream << "" << std::endl; + stream << "entity std_fifo is" << std::endl; + stream << "generic (" << std::endl; + stream << " constant FIFO_DEPTH : positive := 256" << std::endl; + stream << ");" << std::endl; + stream << "port ( " << std::endl; + stream << " clk : in std_logic;" << std::endl; + stream << " rst : in std_logic;" << std::endl; + stream << " write_en : in std_logic;" << std::endl; + stream << " read_en : in std_logic;" << std::endl; + stream << " data_in : in event_type;" << std::endl; + stream << " data_out : out event_type;" << std::endl; + stream << " empty : out std_logic;" << std::endl; + stream << " full : out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end std_fifo;" << std::endl; + stream << "" << std::endl; + stream << "architecture behavioral of std_fifo is" << std::endl; + stream << "begin" << std::endl; + stream << "-- Memory Pointer Process" << std::endl; + stream << "fifo_proc : process (clk)" << std::endl; + stream << " type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of event_type;" << std::endl; + stream << " variable Memory : FIFO_Memory;" << std::endl; + stream << "" << std::endl; + stream << " variable Head : natural range 0 to FIFO_DEPTH - 1;" << std::endl; + stream << " variable Tail : natural range 0 to FIFO_DEPTH - 1;" << std::endl; + stream << "" << std::endl; + stream << " variable Looped : boolean;" << std::endl; + stream << "begin" << std::endl; + stream << " if rising_edge(clk) then" << std::endl; + stream << " if rst = '1' then" << std::endl; + stream << " Head := 0;" << std::endl; + stream << " Tail := 0;" << std::endl; + stream << "" << std::endl; + stream << " Looped := false;" << std::endl; + stream << "" << std::endl; + stream << " full <= '0';" << std::endl; + stream << " empty <= '1';" << std::endl; + stream << " else" << std::endl; + stream << " if (read_en = '1') then" << std::endl; + stream << " if ((Looped = true) or (Head /= Tail)) then" << std::endl; + stream << " -- Update data output" << std::endl; + stream << " data_out <= Memory(Tail);" << std::endl; + stream << " " << std::endl; + stream << " -- Update Tail pointer as needed" << std::endl; + stream << " if (Tail = FIFO_DEPTH - 1) then" << std::endl; + stream << " Tail := 0;" << std::endl; + stream << " " << std::endl; + stream << " Looped := false;" << std::endl; + stream << " else" << std::endl; + stream << " Tail := Tail + 1;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " if (write_en = '1') then" << std::endl; + stream << " if ((Looped = false) or (Head /= Tail)) then" << std::endl; + stream << " -- Write Data to Memory" << std::endl; + stream << " Memory(Head) := data_in;" << std::endl; + stream << " " << std::endl; + stream << " -- Increment Head pointer as needed" << std::endl; + stream << " if (Head = FIFO_DEPTH - 1) then" << std::endl; + stream << " Head := 0;" << std::endl; + stream << " " << std::endl; + stream << " Looped := true;" << std::endl; + stream << " else" << std::endl; + stream << " Head := Head + 1;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " -- Update empty and full flags" << std::endl; + stream << " if (Head = Tail) then" << std::endl; + stream << " if Looped then" << std::endl; + stream << " full <= '1';" << std::endl; + stream << " else" << std::endl; + stream << " empty <= '1';" << std::endl; + stream << " end if;" << std::endl; + stream << " else" << std::endl; + stream << " empty <= '0';" << std::endl; + stream << " full <= '0';" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << "" << std::endl; + stream << "end behavioral;" << std::endl; + stream << "-- END standard FIFO buffer" << std::endl; +} + +void ChartToVHDL::writeSignalsAndComponents(std::ostream &stream) { + // create internal signals + stream << "-- system signals" << std::endl; + stream << "signal stall : std_logic;" << std::endl; + stream << "signal completed_sig : std_logic;" << std::endl; + stream << "signal rst : std_logic;" << std::endl; + stream << std::endl; + + stream << "-- state signals" << std::endl; + + std::list<std::string> signalDecls; + + for (auto state : _states) { + std::string parent = ATTR(state, "parent"); + + signalDecls.push_back("signal state_active_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal state_next_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal in_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal in_exit_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + + // not needed for <scxml> state + if (parent.size() != 0) { + signalDecls.push_back( + "signal in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + } + } + + signalDecls.sort(); + for (std::list<std::string>::iterator iter = signalDecls.begin(); iter != signalDecls.end(); iter++) { + stream << *iter << std::endl; + } + stream << std::endl; + + + stream << "-- transition signals" << std::endl; + stream << "signal spontaneous_en : std_logic;" << std::endl; + stream << "signal spontaneous_active : std_logic;" << std::endl; + stream << "signal optimal_transition_set_combined_sig : std_logic;" << std::endl; + + for (auto transition : _transitions) { + stream << "signal in_optimal_transition_set_" << ATTR(transition, "postFixOrder") << "_sig : std_logic;" + << std::endl; + } + stream << std::endl; + + stream << "-- event signals" << std::endl; + stream << "signal int_event_write_en : std_logic;" << std::endl; + stream << "signal int_event_read_en : std_logic;" << std::endl; + stream << "signal int_event_empty : std_logic;" << std::endl; + stream << "signal int_event_input : event_type;" << std::endl; + stream << "signal int_event_output : event_type;" << std::endl; + stream << "signal next_event_re : std_logic;" << std::endl; + stream << "signal next_event_dequeued : std_logic;" << std::endl; + stream << "signal next_event : event_type;" << std::endl; + stream << "signal event_consumed : std_logic;" << std::endl; + stream << std::endl; + + std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << "signal event_" << escapeMacro((*eventIter)->value) << "_sig : std_logic;" << std::endl; + } + stream << std::endl; + + stream << "-- error signals" << std::endl; + stream << "signal reg_error_out : std_logic;" << std::endl; + stream << "signal error_full_int_event_fifo : std_logic;" << std::endl; + stream << std::endl; + + // add components + stream << "-- event FIFO" << std::endl; + stream << "component std_fifo is" << std::endl; + stream << "port ( " << std::endl; + stream << " clk : in std_logic;" << std::endl; + stream << " rst : in std_logic;" << std::endl; + stream << " write_en : in std_logic;" << std::endl; + stream << " read_en : in std_logic;" << std::endl; + stream << " data_in : in event_type;" << std::endl; + stream << " data_out : out event_type;" << std::endl; + stream << " empty : out std_logic;" << std::endl; + stream << " full : out std_logic" << std::endl; // we calculate how much we need + stream << ");" << std::endl; + stream << "end component;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeModuleInstantiation(std::ostream &stream) { + // instantiate event fifo + stream << "int_event_fifo : component std_fifo " << std::endl; + stream << "port map ( " << std::endl; + stream << " clk => clk," << std::endl; + stream << " rst => rst_i," << std::endl; + stream << " write_en => int_event_write_en," << std::endl; + stream << " read_en => int_event_read_en," << std::endl; + stream << " data_in => int_event_input," << std::endl; + stream << " data_out => int_event_output," << std::endl; + stream << " empty => int_event_empty," << std::endl; + stream << " full => error_full_int_event_fifo" << std::endl; // we calculate how much we need + stream << ");" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeErrorHandler(std::ostream &stream) { + // sets error output signal if an error occures somewhere + stream << "-- error handler" << std::endl; + stream << "-- sets error output signal if an error occures somewhere" << std::endl; + stream << "error_handler : process (clk, rst) " << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + stream << " reg_error_out <= '0';" << std::endl; + stream << " elsif rising_edge(clk) then" << std::endl; + stream << " reg_error_out <= error_full_int_event_fifo;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeResetHandler(std::ostream &stream) { + stream << "-- reset handler" << std::endl; + stream << "rst <= rst_i;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeSpontaneousHandler(std::ostream &stream) { + // sets spontaneous signal + stream << "-- spontaneous handler" << std::endl; + stream << "spontaneous_handler : process (clk, rst) " << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + stream << " spontaneous_en <= '1';" << std::endl; + stream << " elsif rising_edge(clk) and stall = '0' then" << std::endl; + stream << " if spontaneous_en = '1' then" << std::endl; + stream << " spontaneous_en <= optimal_transition_set_combined_sig;" << std::endl; + stream << " else" << std::endl; + //if new event is dequeued then 1 else stay 0 + stream << " spontaneous_en <= next_event_dequeued;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeInternalEventHandler(std::ostream &stream) { + // Add controler specific stuff here + stream << "-- event handler" << std::endl; + stream << "-- pops events and set event signals" << std::endl; + stream << "event_handler : process (clk, rst) " << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + + std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix(""); + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; + } + + stream << " next_event_dequeued <= '0';" << std::endl; + stream << " event_consumed <= '0';" << std::endl; + + stream << " elsif falling_edge(clk) and stall = '0' then" << std::endl; + + VContainer eventConsumed = VOR; + for (auto transition : _transitions) { + + if (HAS_ATTR(transition, "event") == true) { + *eventConsumed += VLINE("in_optimal_transition_set_" + + ATTR(transition, "postFixOrder") + "_sig"); + } + } + + VBranch *tree = (VASSIGN, + VLINE("event_consumed"), + eventConsumed); + tree->print(stream); + stream << ";" << std::endl; + + stream << " if int_event_empty = '0' then " << std::endl; + stream << " case next_event is " << std::endl; + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << " when hwe_" + << escapeMacro((*eventIter)->value) << " =>" << std::endl; + for (std::list<TrieNode *>::iterator eventIter2 = eventNames.begin(); + eventIter2 != eventNames.end(); eventIter2++) { + stream << " event_" << escapeMacro((*eventIter2)->value); + if (escapeMacro((*eventIter)->value) == escapeMacro((*eventIter2)->value)) { + stream << "_sig <= '1';" << std::endl; + } else { + stream << "_sig <= '0';" << std::endl; + } + } + stream << " next_event_dequeued <= '1';" << std::endl; + } + stream << " when others =>" << std::endl; + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; + } + stream << " next_event_dequeued <= '0';" << std::endl; + stream << " end case;" << std::endl; + stream << " elsif int_event_empty = '1' and event_consumed = '1' then" << std::endl; + + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + stream << " event_" << escapeMacro((*eventIter)->value) << "_sig <= '0';" << std::endl; + } + stream << " next_event_dequeued <= '0';" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; + + stream << "next_event_re <= not int_event_empty and not stall; " << std::endl; + stream << "next_event <= int_event_output; " << std::endl; + stream << "int_event_write_en <= next_event_we_i; " << std::endl; + stream << "int_event_input <= next_event_i; " << std::endl; + stream << "int_event_read_en <= not stall; --not spontaneous_en and " << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeActiveStateNplusOne(std::ostream &stream) { + stream << "-- active configuration" << std::endl; + + for (auto state : _states) { + std::string parent = ATTR(state, "parent"); + + // special case for <scxml> to start the state machine + if (parent.size() == 0) { + stream << " state_next_" << ATTR(state, "documentOrder") << "_sig <= " << + "not completed_sig;" << std::endl; + continue; + } + + VBranch *tree = (VASSIGN, + VLINE("state_next_" + ATTR(state, "documentOrder") + "_sig"), + (VOR, + VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), + (VAND, (VNOT, VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig")), + VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig")) + )); + + tree->print(stream); + stream << ";" << std::endl; + + } +} + +void ChartToVHDL::writeOptimalTransitionSetSelection(std::ostream &stream) { + stream << "-- optimal transition set selection" << std::endl; + VContainer optimalTransitions = VOR; + VContainer spontaneoursActive = VOR; + + for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++) { + DOMElement *transition = *transIter; + std::string conflicts = ATTR(transition, "conflictBools"); + + + VContainer nameMatchers = VOR; + if (HAS_ATTR(transition, "event")) { + std::list<std::string> eventDescs = tokenize(ATTR(transition, "event")); + for (std::list<std::string>::iterator descIter = eventDescs.begin(); + descIter != eventDescs.end(); descIter++) { + std::list<TrieNode *> eventNames = _eventTrie.getWordsWithPrefix( + (*descIter) == "*" ? "" : *descIter); + for (std::list<TrieNode *>::iterator eventIter = eventNames.begin(); + eventIter != eventNames.end(); eventIter++) { + *nameMatchers += VLINE("event_" + escapeMacro((*eventIter)->value) + "_sig"); + } + } + } else { + *nameMatchers += VLINE("'1'"); + } + + VContainer conflicters = VOR; + for (size_t j = 0; j < strTo<size_t>(ATTR(transition, "postFixOrder")); j++) { + if (conflicts[j] == '1') { + *conflicters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig"); + } + } + + VBranch *tree = (VASSIGN, + VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig"), + (VAND, + (HAS_ATTR(transition, "event") + ? (VNOT, VLINE("spontaneous_active")) + : (VNOP, VLINE("spontaneous_en"))), + VLINE("state_active_" + ATTR(transition, "source") + "_sig"), + nameMatchers, + (VNOT, conflicters))); + + tree->print(stream); + stream << ";" << std::endl; + + *optimalTransitions += VLINE("in_optimal_transition_set_" + + ATTR(transition, "postFixOrder") + "_sig"); + if (HAS_ATTR(transition, "event") == false) { + *spontaneoursActive += VLINE("in_optimal_transition_set_" + + ATTR(transition, "postFixOrder") + "_sig"); + } + } + + VBranch *tree = (VASSIGN, + VLINE("optimal_transition_set_combined_sig"), + optimalTransitions); + tree->print(stream); + stream << ";" << std::endl; + + VBranch *tree2 = (VASSIGN, + VLINE("spontaneous_active"), + spontaneoursActive); + tree2->print(stream); + stream << ";" << std::endl; +} + +void ChartToVHDL::writeExitSet(std::ostream &stream) { + stream << "-- exit set selection" << std::endl; + + for (auto state : _states) { + + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string children = ATTR(state, "childBools"); + std::string parent = ATTR(state, "parent"); + + VContainer exitsetters = VOR; + for (auto transition : _transitions) { + std::string exitSet = ATTR(transition, "exitSetBools"); + if (exitSet.at(strTo<size_t>(ATTR(state, "documentOrder"))) == '1') { + *exitsetters += VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig "); + } + } + + VBranch *tree = (VASSIGN, + VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig"), + (VAND, + VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig"), + exitsetters)); + + tree->print(stream); + stream << ";" << std::endl; + } +} + +void ChartToVHDL::writeEntrySet(std::ostream &stream) { + stream << "-- entry set selection" << std::endl; + + for (auto state : _states) { + + VBranch *tree = (VASSIGN, + VLINE("in_entry_set_" + ATTR(state, "documentOrder") + "_sig"), + (VAND, + VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), + (VOR, VLINE("in_exit_set_" + ATTR(state, "documentOrder") + "_sig"), + (VNOT, VLINE("state_active_" + ATTR(state, "documentOrder") + "_sig"))))); + + tree->print(stream); + stream << ";" << std::endl; + } +} + +void ChartToVHDL::writeCompleteEntrySet(std::ostream &stream) { + stream << "-- complete entry set selection" << std::endl; + + for (auto state : _states) { + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string children = ATTR(state, "childBools"); + std::string parent = ATTR(state, "parent"); + + if (parent.size() == 0) { + continue; // skips <scxml> node + } + + + // EntrySet for every state types + VContainer optimalEntrysetters = VOR; + for (auto transition : _transitions) { + // Is this state in TargetSet of the transition? + std::string targetSet = ATTR(transition, "targetBools"); + if (targetSet[strTo<size_t>(ATTR(state, "documentOrder"))] == '1') { + //yes? then add the transition to optimal entry set of the state + *optimalEntrysetters += + VLINE("in_optimal_transition_set_" + ATTR(transition, "postFixOrder") + "_sig"); + } + } + + // if composite state (or root) we have to add ancestor completion + VContainer completeEntrysetters = VOR; + if (isCompound(state) || isParallel(state)) { + for (auto tmp_state : _states) { + // is tmp_state is child of state continue? + if (children[strTo<size_t>(ATTR(state, "documentOrder"))] == '1') { + // yes? then add its complete_entry_set_up as ancestor completion + *completeEntrysetters += + VLINE("in_complete_entry_set_up_" + ATTR(tmp_state, "documentOrder") + "_sig"); + } + } + } + + VBranch *tree = (VASSIGN, + VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), + (VOR, optimalEntrysetters, completeEntrysetters) + ); + tree->print(stream); + stream << ";" << std::endl; + } + + + // descendant completion + for (auto state : _states) { + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string parent = ATTR(state, "parent"); //is it a int ? + + if (parent.size() == 0) { + continue; // skips <scxml> node + } + + VContainer descendantCompletion = VAND; + // if parent is compound + if (getParentState(state) != NULL && + isCompound(getParentState(state))) { + std::string children = ATTR_CAST(_states[strTo<size_t>(parent)], + "childBools"); + + std::string parentInit = ATTR(getParentState(state), "initial"); + if (// if parent has init field an this state is inside --> add it as default completion + (!parentInit.empty() + && ATTR(state, "id").compare(parentInit) == 0) || + // or add this state as default completion when parent has no init field and it is the first in document order + (parentInit.empty() && + (strTo<size_t>(ATTR(getParentState(state), "documentOrder")) + 1) == + strTo<size_t>(ATTR(state, "documentOrder")))) { + *descendantCompletion += + VLINE("in_entry_set_" + ATTR(getParentState(state), "documentOrder") + "_sig"); + + // but only if compound parent is not already completed + for (auto tmp_state : _states) { + if (tmp_state == state) { + // skip state itselve + continue; + } + if (children[strTo<size_t>(ATTR(tmp_state, "documentOrder"))] == '1') { + *descendantCompletion += (VNOT, + (VAND, + VLINE("state_active_" + ATTR(tmp_state, "documentOrder") + "_sig"), + (VNOT, + VLINE("in_exit_set_" + ATTR(tmp_state, "documentOrder") + + "_sig")))); + } + } + } else { + // disable this branche + *descendantCompletion += VLINE("'0'"); + } + } else + // if parent is parallel + if (getParentState(state) != NULL && + isParallel(getParentState(state))) { + *descendantCompletion += + VLINE("in_complete_entry_set_" + ATTR(getParentState(state), "documentOrder") + "_sig"); + } + + VBranch *tree = (VASSIGN, + VLINE("in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig"), + (VOR, + VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), + descendantCompletion)); + + tree->print(stream); + stream << ";" << std::endl; + } +} + +void ChartToVHDL::writeStateHandler(std::ostream &stream) { + // updater for current state + stream << "-- State Handler" << std::endl; + stream << "-- updates current state" << std::endl; + stream << "state_proc: process(clk, rst, stall)" << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") << "_sig <= " << "'0';" << std::endl; + } + + stream << " in_complete_entry_set_0_sig <= '1';" << std::endl; + stream << " elsif (rising_edge(clk) and stall = '0') then" << std::endl; + stream << " in_complete_entry_set_0_sig <= '0';" << std::endl; + + for (auto state : _states) { + stream << " state_active_" << ATTR(state, "documentOrder") << "_sig <= " << "state_next_" << + ATTR(state, "documentOrder") << "_sig;" << std::endl; + } + + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeSystemSignalMapping(std::ostream &stream) { + stream << "-- system signals" << std::endl; + std::list<DOMElement *> topLevelFinal = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "final", + _scxml); + + VContainer tlf = VOR; + for (auto final : topLevelFinal) { + *tlf += VLINE("state_active_" + ATTR(final, "documentOrder") + "_sig"); + + } + + VBranch *tree = (VASSIGN, + VLINE("completed_sig"), + tlf); + + tree->print(stream); + stream << ";" << std::endl; + + // tmp mapping for events + stream << "stall <= not en or completed_sig or ( int_event_empty and not spontaneous_en ) ; " << std::endl; + stream << std::endl; + + // interface signals + stream << "-- interface signals" << std::endl; + for (auto state : _states) { + stream << "state_active_" << ATTR(state, "documentOrder") + << "_o <= state_active_" << ATTR(state, "documentOrder") + << "_sig;" << std::endl; + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onexit", state).size() > 0) { + stream << "exit_set_" << ATTR(state, "documentOrder") + << "_o <= in_exit_set_" << ATTR(state, "documentOrder") + << "_sig;" << std::endl; + } + + if (DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "onentry", state).size() > 0) { + stream << "entry_set_" << ATTR(state, "documentOrder") + << "_o <= in_entry_set_" << ATTR(state, "documentOrder") + << "_sig;" << std::endl; + } + } + + for (auto transition : _transitions) { + if (DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, transition).size() > 0) { + stream << "transition_set_" << ATTR(transition, "postFixOrder") + << "_o <= in_optimal_transition_set_" << ATTR(transition, "postFixOrder") + << "_sig;" << std::endl; + } + } + + stream << "completed_o <= completed_sig; " << std::endl; + stream << "error_o <= reg_error_out; " << std::endl; + stream << std::endl; +} }
\ No newline at end of file diff --git a/src/uscxml/transform/ChartToVHDL.h b/src/uscxml/transform/ChartToVHDL.h index 2506584..4b047da 100644 --- a/src/uscxml/transform/ChartToVHDL.h +++ b/src/uscxml/transform/ChartToVHDL.h @@ -31,129 +31,129 @@ namespace uscxml { - class USCXML_API ChartToVHDL : public ChartToC { - public: - - virtual ~ChartToVHDL(); - - static Transformer transform(const Interpreter &other); - - void writeTo(std::ostream &stream); - - - struct VNode { - virtual void print(std::ostream &stream, const std::string padding = "") = 0; - - virtual ~VNode() { }; - }; - - struct VBranch : VNode { - std::vector<VNode *> v; - - virtual ~VBranch() { - for (unsigned i = 0; i < v.size(); i++) - delete v[i]; - } - - VBranch &operator+=(VNode *p) { - v.push_back(p); - return *this; - } - }; - - struct VPointer { - VNode *ptr; - - operator VNode *() { - return ptr; - } - - operator VBranch *() { - return static_cast<VBranch *> (ptr); - } - - VPointer &operator/(VNode *p) { - ptr = p; - return *this; - } - }; - - struct VContainer { - VBranch *ptr; - - operator VBranch *() { - return ptr; - } - - VContainer &operator/(VBranch *p) { - ptr = p; - return *this; - } - - VContainer &operator,(VPointer p) { - if (ptr) ptr->v.push_back(p.ptr); - return *this; - } - - VContainer &operator,(VContainer c) { - if (ptr) ptr->v.push_back(c.ptr); - return *this; - } - }; - - struct VLine : VNode { - VLine(const std::string &name) : name(name) { } - - virtual void print(std::ostream &stream, const std::string padding = "") { - stream << " " << name; - } - - std::string name; - }; - - struct VAssign : VBranch { - virtual void print(std::ostream &stream, const std::string padding = "") { - v[0]->print(stream, padding); - stream << padding << " <="; - v[1]->print(stream, padding + " "); - } - }; - - struct VAnd : VBranch { - virtual void print(std::ostream &stream, const std::string padding = "") { - stream << std::endl << padding << "( '1' "; - for (unsigned i = 0; i < v.size(); i++) { - stream << std::endl << padding << " and"; - v[i]->print(stream, padding + " "); - } - stream << padding << ")" << std::endl; - } - }; - - struct VOr : VBranch { - virtual void print(std::ostream &stream, const std::string padding = "") { - stream << std::endl << padding << "( '0' "; - for (unsigned i = 0; i < v.size(); i++) { - stream << std::endl << padding << " or"; - v[i]->print(stream, padding + " "); - } - stream << std::endl << padding << ")" << std::endl; - } - }; - - struct VNot : VBranch { - virtual void print(std::ostream &stream, const std::string padding = "") { - stream << " ( not"; - v[0]->print(stream, padding + " "); - stream << " )"; - } - }; - - struct VNop : VBranch { - virtual void print(std::ostream &stream, const std::string padding = "") { - v[0]->print(stream, padding); - } - }; +class USCXML_API ChartToVHDL : public ChartToC { +public: + + virtual ~ChartToVHDL(); + + static Transformer transform(const Interpreter &other); + + void writeTo(std::ostream &stream); + + + struct VNode { + virtual void print(std::ostream &stream, const std::string padding = "") = 0; + + virtual ~VNode() { }; + }; + + struct VBranch : VNode { + std::vector<VNode *> v; + + virtual ~VBranch() { + for (unsigned i = 0; i < v.size(); i++) + delete v[i]; + } + + VBranch &operator+=(VNode *p) { + v.push_back(p); + return *this; + } + }; + + struct VPointer { + VNode *ptr; + + operator VNode *() { + return ptr; + } + + operator VBranch *() { + return static_cast<VBranch *> (ptr); + } + + VPointer &operator/(VNode *p) { + ptr = p; + return *this; + } + }; + + struct VContainer { + VBranch *ptr; + + operator VBranch *() { + return ptr; + } + + VContainer &operator/(VBranch *p) { + ptr = p; + return *this; + } + + VContainer &operator,(VPointer p) { + if (ptr) ptr->v.push_back(p.ptr); + return *this; + } + + VContainer &operator,(VContainer c) { + if (ptr) ptr->v.push_back(c.ptr); + return *this; + } + }; + + struct VLine : VNode { + VLine(const std::string &name) : name(name) { } + + virtual void print(std::ostream &stream, const std::string padding = "") { + stream << " " << name; + } + + std::string name; + }; + + struct VAssign : VBranch { + virtual void print(std::ostream &stream, const std::string padding = "") { + v[0]->print(stream, padding); + stream << padding << " <="; + v[1]->print(stream, padding + " "); + } + }; + + struct VAnd : VBranch { + virtual void print(std::ostream &stream, const std::string padding = "") { + stream << std::endl << padding << "( '1' "; + for (unsigned i = 0; i < v.size(); i++) { + stream << std::endl << padding << " and"; + v[i]->print(stream, padding + " "); + } + stream << padding << ")" << std::endl; + } + }; + + struct VOr : VBranch { + virtual void print(std::ostream &stream, const std::string padding = "") { + stream << std::endl << padding << "( '0' "; + for (unsigned i = 0; i < v.size(); i++) { + stream << std::endl << padding << " or"; + v[i]->print(stream, padding + " "); + } + stream << std::endl << padding << ")" << std::endl; + } + }; + + struct VNot : VBranch { + virtual void print(std::ostream &stream, const std::string padding = "") { + stream << " ( not"; + v[0]->print(stream, padding + " "); + stream << " )"; + } + }; + + struct VNop : VBranch { + virtual void print(std::ostream &stream, const std::string padding = "") { + v[0]->print(stream, padding); + } + }; //TODO can we create the macros without IDE errors ?! #define VLINE VPointer()/new VLine @@ -164,71 +164,71 @@ namespace uscxml { #define VNOP VContainer()/new VNop - protected: - ChartToVHDL(const Interpreter &other); +protected: + ChartToVHDL(const Interpreter &other); - void checkDocument(); + void checkDocument(); - void findEvents(); + void findEvents(); - void writeTypes(std::ostream &stream); + void writeTypes(std::ostream &stream); - void writeIncludes(std::ostream &stream); + void writeIncludes(std::ostream &stream); - // top layer components - void writeFiFo(std::ostream &stream); + // top layer components + void writeFiFo(std::ostream &stream); - void writeEventController(std::ostream &stream); + void writeEventController(std::ostream &stream); - void writeMicroStepper(std::ostream &stream); + void writeMicroStepper(std::ostream &stream); - void writeTestbench(std::ostream &stream); + void writeTestbench(std::ostream &stream); - // system - void writeSignalsAndComponents(std::ostream &stream); + // system + void writeSignalsAndComponents(std::ostream &stream); - void writeSystemSignalMapping(std::ostream &stream); + void writeSystemSignalMapping(std::ostream &stream); - void writeModuleInstantiation(std::ostream &stream); + void writeModuleInstantiation(std::ostream &stream); - // combinatorial logic - void writeOptimalTransitionSetSelection(std::ostream &stream); + // combinatorial logic + void writeOptimalTransitionSetSelection(std::ostream &stream); - void writeExitSet(std::ostream &stream); + void writeExitSet(std::ostream &stream); - void writeEntrySet(std::ostream &stream); + void writeEntrySet(std::ostream &stream); - void writeTransitionSet(std::ostream &stream); + void writeTransitionSet(std::ostream &stream); - void writeDefaultCompletions(std::ostream &stream); + void writeDefaultCompletions(std::ostream &stream); - void writeCompleteEntrySet(std::ostream &stream); + void writeCompleteEntrySet(std::ostream &stream); - void writeActiveStateNplusOne(std::ostream &stream); + void writeActiveStateNplusOne(std::ostream &stream); - // handler - void writeStateHandler(std::ostream &stream); + // handler + void writeStateHandler(std::ostream &stream); - void writeResetHandler(std::ostream &stream); + void writeResetHandler(std::ostream &stream); - void writeSpontaneousHandler(std::ostream &stream); + void writeSpontaneousHandler(std::ostream &stream); - void writeInternalEventHandler(std::ostream &stream); + void writeInternalEventHandler(std::ostream &stream); - void writeErrorHandler(std::ostream &stream); + void writeErrorHandler(std::ostream &stream); - // event generation - void writeExContentBlock(std::ostream &stream, std::string index, - std::list<XERCESC_NS::DOMElement *> commandSequence); + // event generation + void writeExContentBlock(std::ostream &stream, std::string index, + std::list<XERCESC_NS::DOMElement *> commandSequence); - Trie _eventTrie; - std::list<XERCESC_NS::DOMElement *> _execContent; + Trie _eventTrie; + std::list<XERCESC_NS::DOMElement *> _execContent; - private: - std::string getLineForExecContent(const XERCESC_NS::DOMNode *elem); +private: + std::string getLineForExecContent(const XERCESC_NS::DOMNode *elem); - bool filterSupportedExecContent(XERCESC_NS::DOMElement *execContentElement); - }; + bool filterSupportedExecContent(XERCESC_NS::DOMElement *execContentElement); +}; } diff --git a/src/uscxml/transform/Transformer.h b/src/uscxml/transform/Transformer.h index 5b2fbdb..6a9f2f3 100644 --- a/src/uscxml/transform/Transformer.h +++ b/src/uscxml/transform/Transformer.h @@ -39,16 +39,16 @@ public: _binding = other.getImpl()->_binding; } - - + + virtual void writeTo(std::ostream& stream) = 0; virtual operator Interpreter() { throw std::runtime_error("Transformer cannot be interpreted as an Interpreter again"); } - virtual XERCESC_NS::DOMDocument* getDocument() const { - return _document; - } + virtual XERCESC_NS::DOMDocument* getDocument() const { + return _document; + } protected: std::multimap<std::string, std::string> _extensions; diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp index 7cb69d7..044e660 100644 --- a/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp @@ -33,20 +33,20 @@ using namespace XERCESC_NS; void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { - /** - Create macro names for state identifiers - Do not add as literals as they are not unique with nested state-charts - */ - { - for (size_t i = 0; i < interpreter->_states.size(); i++) { - DOMElement* state = interpreter->_states[i]; - if (HAS_ATTR(state, "id")) { - createMacroName(ATTR(state, "id")); - } - } - } + /** + Create macro names for state identifiers + Do not add as literals as they are not unique with nested state-charts + */ + { + for (size_t i = 0; i < interpreter->_states.size(); i++) { + DOMElement* state = interpreter->_states[i]; + if (HAS_ATTR(state, "id")) { + createMacroName(ATTR(state, "id")); + } + } + } // _lastStrIndex = interpreter->_states.size(); - + /** Find all event names that might occur */ { std::list<XERCESC_NS::DOMElement*> internalEventNames = DOMUtils::inDocumentOrder({ @@ -77,24 +77,24 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { addEvent("done.state." + ATTR(state, "id")); } } - - std::list<XERCESC_NS::DOMElement*> invokers = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml, false); - for (auto invoker : invokers) { - addCode("_event.invokeid", interpreter); - - if (HAS_ATTR(invoker, "id")) { - addEvent("done.state." + ATTR(invoker, "id")); - } - } + + std::list<XERCESC_NS::DOMElement*> invokers = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml, false); + for (auto invoker : invokers) { + addCode("_event.invokeid", interpreter); + + if (HAS_ATTR(invoker, "id")) { + addEvent("done.state." + ATTR(invoker, "id")); + } + } + } + + // add event names from trie to string literals + std::list<TrieNode*> events = _eventTrie.getWordsWithPrefix(""); + for (auto event : events) { + addLiteral(event->value); } - // add event names from trie to string literals - std::list<TrieNode*> events = _eventTrie.getWordsWithPrefix(""); - for (auto event : events) { - addLiteral(event->value); - } - - + /** Find all string literals */ { // string literals for raise / send content @@ -103,8 +103,8 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { }, interpreter->_scxml); for (auto content : contents) { - if (!content->hasChildNodes()) - continue; + if (!content->hasChildNodes()) + continue; std::string contentStr = spaceNormalize(X(content->getFirstChild()->getNodeValue())); if (!isNumeric(contentStr.c_str(), 10)) { addLiteral(contentStr); @@ -129,7 +129,7 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { if (HAS_ATTR(cond, "cond")) { std::string code = ATTR_CAST(cond, "cond"); code = sanitizeCode(code); - addCode(code, interpreter); + addCode(code, interpreter); cond->setAttribute(X("cond"), X(code)); } } @@ -159,7 +159,7 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { if (HAS_ATTR(location, "location")) { std::string code = ATTR_CAST(location, "location"); code = sanitizeCode(code); - addCode(code, interpreter); + addCode(code, interpreter); location->setAttribute(X("location"), X(code)); } } @@ -175,7 +175,7 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { std::string code = X(textText->getNodeValue()).str(); if (code.size() > 0) { code = sanitizeCode(code); - addCode(code, interpreter); + addCode(code, interpreter); textText->setNodeValue(X(code)); } } @@ -186,73 +186,73 @@ void PromelaCodeAnalyzer::analyze(ChartToPromela* interpreter) { }, interpreter->_scxml); for (auto foreach : foreachs) { - if (HAS_ATTR(foreach, "index")) { - addCode(ATTR(foreach, "index"), interpreter); - } else { - _hasIndexLessLoops = true; - } - if (HAS_ATTR(foreach, "item")) { - addCode(ATTR(foreach, "item"), interpreter); - } - } - - // do we need sendid / invokeid? - { - std::list<DOMElement*> invokes = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml); - std::list<DOMElement*> sends = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "send"}, interpreter->_scxml); - std::list<DOMElement*> cancels = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "cancel"}, interpreter->_scxml); - - if (cancels.size() > 0) { - addCode("_event.origin", interpreter); - _usesCancel = true; - } - - for (auto send : sends) { - if (HAS_ATTR(send, "idlocation")) { - addCode("_event.sendid", interpreter); - } - if (HAS_ATTR(send, "id")) { - addLiteral(ATTR(send, "id")); - addCode("_event.sendid", interpreter); - } - - // do we need delays? - if (HAS_ATTR(send, "delay") || HAS_ATTR(send, "delayexpr")) { - size_t delay = strTo<size_t>(ATTR(send, "delay")); - if (delay > largestDelay) - largestDelay = delay; - addCode("_event.delay", interpreter); + if (HAS_ATTR(foreach, "index")) { + addCode(ATTR(foreach, "index"), interpreter); + } else { + _hasIndexLessLoops = true; + } + if (HAS_ATTR(foreach, "item")) { + addCode(ATTR(foreach, "item"), interpreter); + } + } + + // do we need sendid / invokeid? + { + std::list<DOMElement*> invokes = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml); + std::list<DOMElement*> sends = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "send"}, interpreter->_scxml); + std::list<DOMElement*> cancels = DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "cancel"}, interpreter->_scxml); + + if (cancels.size() > 0) { + addCode("_event.origin", interpreter); + _usesCancel = true; + } + + for (auto send : sends) { + if (HAS_ATTR(send, "idlocation")) { + addCode("_event.sendid", interpreter); + } + if (HAS_ATTR(send, "id")) { + addLiteral(ATTR(send, "id")); + addCode("_event.sendid", interpreter); + } + + // do we need delays? + if (HAS_ATTR(send, "delay") || HAS_ATTR(send, "delayexpr")) { + size_t delay = strTo<size_t>(ATTR(send, "delay")); + if (delay > largestDelay) + largestDelay = delay; + addCode("_event.delay", interpreter); #if NEW_DELAY_RESHUFFLE #else - addCode("_event.seqNr", interpreter); + addCode("_event.seqNr", interpreter); #endif - } - } - } - - // add all namelist entries to the _event structure - { - std::list<DOMElement*> withNamelists; - withNamelists.splice(withNamelists.end(), DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "send"}, interpreter->_scxml)); - withNamelists.splice(withNamelists.end(), DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml)); - for (auto withNamelist : withNamelists) { - if (HAS_ATTR(withNamelist, "namelist")) { - std::string namelist = ATTR(withNamelist, "namelist"); - std::list<std::string> names = tokenize(namelist); - for (std::list<std::string>::iterator nameIter = names.begin(); nameIter != names.end(); nameIter++) { - addCode("_event.data." + *nameIter + " = 0;", interpreter); // introduce for _event_t typedef - } - } - } - } + } + } + } + + // add all namelist entries to the _event structure + { + std::list<DOMElement*> withNamelists; + withNamelists.splice(withNamelists.end(), DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "send"}, interpreter->_scxml)); + withNamelists.splice(withNamelists.end(), DOMUtils::inDocumentOrder({XML_PREFIX(interpreter->_scxml).str() + "invoke"}, interpreter->_scxml)); + for (auto withNamelist : withNamelists) { + if (HAS_ATTR(withNamelist, "namelist")) { + std::string namelist = ATTR(withNamelist, "namelist"); + std::list<std::string> names = tokenize(namelist); + for (std::list<std::string>::iterator nameIter = names.begin(); nameIter != names.end(); nameIter++) { + addCode("_event.data." + *nameIter + " = 0;", interpreter); // introduce for _event_t typedef + } + } + } + } } } void PromelaCodeAnalyzer::addEvent(const std::string& eventName) { - addLiteral(eventName); - _eventTrie.addWord(eventName); + addLiteral(eventName); + _eventTrie.addWord(eventName); } std::string PromelaCodeAnalyzer::sanitizeCode(const std::string& code) { @@ -401,14 +401,14 @@ void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* inter } } - + void PromelaCodeAnalyzer::addLiteral(const std::string& literal, int forceIndex) { if (boost::starts_with(literal, "'")) throw std::runtime_error("Literal " + literal + " passed with quotes"); - if (_literals.find(literal) != _literals.end()) - return; - _literals.insert(literal); + if (_literals.find(literal) != _literals.end()) + return; + _literals.insert(literal); createMacroName(literal); enumerateLiteral(literal, forceIndex); } @@ -519,16 +519,16 @@ std::string PromelaCodeAnalyzer::adaptCode(const std::string& code, const std::s lastPos = 0; while (posIter != posList.end()) { - std::string token = code.substr(posIter->first, posIter->second - posIter->first); - if (std::all_of(token.begin(), token.end(), ::isupper) && false) { - // assume it is a state-name macro - processedStr << code.substr(lastPos, posIter->first - lastPos) << token; - } else if (boost::starts_with(prefix, token)) { - processedStr << code.substr(lastPos, posIter->first - lastPos) << token; - } else { - processedStr << code.substr(lastPos, posIter->first - lastPos) << prefix << token; - } - lastPos = posIter->second; + std::string token = code.substr(posIter->first, posIter->second - posIter->first); + if (std::all_of(token.begin(), token.end(), ::isupper) && false) { + // assume it is a state-name macro + processedStr << code.substr(lastPos, posIter->first - lastPos) << token; + } else if (boost::starts_with(prefix, token)) { + processedStr << code.substr(lastPos, posIter->first - lastPos) << token; + } else { + processedStr << code.substr(lastPos, posIter->first - lastPos) << prefix << token; + } + lastPos = posIter->second; posIter++; } processedStr << processed.substr(lastPos, processed.size() - lastPos); @@ -595,9 +595,9 @@ std::list<std::pair<size_t, size_t> > PromelaCodeAnalyzer::getTokenPositions(con std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const PromelaTypedef& type, size_t indent) { std::stringstream assignment; - std::string padding; - for (size_t i = 0; i < indent; i++) - padding += " "; + std::string padding; + for (size_t i = 0; i < indent; i++) + padding += " "; std::map<std::string, PromelaTypedef>::const_iterator typeIter = type.types.begin(); while(typeIter != type.types.end()) { @@ -618,26 +618,26 @@ std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const Prom } std::string PromelaCodeAnalyzer::getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, size_t indent) { - std::stringstream assignment; - std::string padding; - for (size_t i = 0; i < indent; i++) - padding += " "; - - std::map<std::string, PromelaTypedef>::const_iterator typeIter = type.types.begin(); - while(typeIter != type.types.end()) { - const PromelaTypedef& innerType = typeIter->second; - if (innerType.arraySize > 0) { - for (size_t i = 0; i < innerType.arraySize; i++) { - assignment << padding << varTo << "." << typeIter->first << "[" << i << "] = " << varFrom << "." << typeIter->first << "[" << i << "];" << std::endl; - } - } else if (innerType.types.size() > 0) { - assignment << getTypeAssignment(varTo + "." + typeIter->first, varFrom + "." + typeIter->first, typeIter->second, indent); - } else { - assignment << padding << varTo << "." << typeIter->first << " = " << varFrom << "." << typeIter->first << ";" << std::endl; - } - typeIter++; - } - return assignment.str(); + std::stringstream assignment; + std::string padding; + for (size_t i = 0; i < indent; i++) + padding += " "; + + std::map<std::string, PromelaTypedef>::const_iterator typeIter = type.types.begin(); + while(typeIter != type.types.end()) { + const PromelaTypedef& innerType = typeIter->second; + if (innerType.arraySize > 0) { + for (size_t i = 0; i < innerType.arraySize; i++) { + assignment << padding << varTo << "." << typeIter->first << "[" << i << "] = " << varFrom << "." << typeIter->first << "[" << i << "];" << std::endl; + } + } else if (innerType.types.size() > 0) { + assignment << getTypeAssignment(varTo + "." + typeIter->first, varFrom + "." + typeIter->first, typeIter->second, indent); + } else { + assignment << padding << varTo << "." << typeIter->first << " = " << varFrom << "." << typeIter->first << ";" << std::endl; + } + typeIter++; + } + return assignment.str(); } } diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.h b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h index 83ee684..7f69ac9 100644 --- a/src/uscxml/transform/promela/PromelaCodeAnalyzer.h +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h @@ -64,10 +64,10 @@ public: return true; return false; } - bool usesCancel(const std::string& elementName) { - return _usesCancel; - } - + bool usesCancel(const std::string& elementName) { + return _usesCancel; + } + bool usesEventDataField(const std::string& fieldName) { if (usesComplexEventStruct() && _typeDefs.types["_event"].types.find("data") != _typeDefs.types["_event"].types.end() && @@ -76,8 +76,8 @@ public: return false; } - size_t largestDelay = 0; - + size_t largestDelay = 0; + std::string getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, size_t indent = 0); std::string getTypeReset(const std::string& var, const PromelaTypedef& type, size_t indent = 0); @@ -91,9 +91,9 @@ public: return _usesPlatformVars; } - bool hasIndexLessLoops() { - return _hasIndexLessLoops; - } + bool hasIndexLessLoops() { + return _hasIndexLessLoops; + } std::string macroForLiteral(const std::string& literal); int indexForLiteral(const std::string& literal); @@ -121,17 +121,17 @@ public: } std::string sanitizeCode(const std::string& code); - void addEvent(const std::string& eventName); - std::string createMacroName(const std::string& literal); + void addEvent(const std::string& eventName); + std::string createMacroName(const std::string& literal); protected: - void addState(const std::string& stateName, size_t index); + void addState(const std::string& stateName, size_t index); int enumerateLiteral(const std::string& literal, int forceIndex = -1); std::map<std::string, std::string> _strMacros; // macronames for string literals std::map<std::string, int> _strIndex; // integer enumeration for string - std::set<std::string> _literals; + std::set<std::string> _literals; PromelaTypedef _typeDefs; Trie _eventTrie; @@ -139,8 +139,8 @@ protected: private: std::set<std::string> _macroNameSet; // helper set for uniqueness of macros int _lastStrIndex = 1; - bool _usesCancel = false; - bool _usesInPredicate = false; + bool _usesCancel = false; + bool _usesInPredicate = false; bool _usesPlatformVars = false; bool _hasIndexLessLoops = false; }; diff --git a/src/uscxml/util/String.cpp b/src/uscxml/util/String.cpp index ae1aa68..6a80756 100644 --- a/src/uscxml/util/String.cpp +++ b/src/uscxml/util/String.cpp @@ -26,26 +26,25 @@ namespace uscxml { #define ISWHITESPACE(char) (isspace(char)) std::string escapeMacro(std::string const &s) { - // inspired by http://stackoverflow.com/questions/2417588/escaping-a-c-string - std::string returnValue=""; + // inspired by http://stackoverflow.com/questions/2417588/escaping-a-c-string + std::string returnValue=""; std::string specialChars=""; - for (std::string::const_iterator iter = s.begin(), end = s.end(); iter != end; ++iter) { - char c = *iter; - if (('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '_') { - returnValue += c; - } - else { - specialChars += c; - } - } - if (!specialChars.empty()){ + for (std::string::const_iterator iter = s.begin(), end = s.end(); iter != end; ++iter) { + char c = *iter; + if (('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || c == '_') { + returnValue += c; + } else { + specialChars += c; + } + } + if (!specialChars.empty()) { // http://www.cplusplus.com/reference/functional/hash/ // returns the same result for a given string within one execution std::hash<std::string> strHash; returnValue += "_"; returnValue += strHash(specialChars); } - return returnValue; + return returnValue; } std::list<std::string> tokenize(const std::string& line, const char sep, bool trimWhiteSpace) { |