diff options
Diffstat (limited to 'src/uscxml/transform')
-rw-r--r-- | src/uscxml/transform/ChartToC.cpp | 6 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToC.h | 2 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.cpp | 2625 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToPromela.h | 130 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.cpp | 2558 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.h | 26 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp | 596 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaCodeAnalyzer.h | 150 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaInlines.cpp | 165 | ||||
-rw-r--r-- | src/uscxml/transform/promela/PromelaInlines.h | 113 |
10 files changed, 5075 insertions, 1296 deletions
diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index 04f0378..10eee0c 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -50,7 +50,7 @@ ChartToC::ChartToC(const Interpreter& other) : TransformerImpl(other), _topMostM ss << _document; _md5 = md5(ss.str()); - _prefix = "_uscxml_" + _md5.substr(0, 8); + _prefix = "_uscxml_" + _md5.substr(0, 8) + "_"; _allMachines.push_back(this); prepare(); @@ -1189,7 +1189,7 @@ void ChartToC::writeExecContent(std::ostream& stream) { } -void ChartToC::writeExecContent(std::ostream& stream, const DOMNode* node, int indent) { +void ChartToC::writeExecContent(std::ostream& stream, const DOMNode* node, size_t indent) { if (!node) return; @@ -2560,4 +2560,4 @@ void ChartToC::writeFSM(std::ostream& stream) { ChartToC::~ChartToC() { } -}
\ No newline at end of file +} diff --git a/src/uscxml/transform/ChartToC.h b/src/uscxml/transform/ChartToC.h index 43ffc45..9fe6a9f 100644 --- a/src/uscxml/transform/ChartToC.h +++ b/src/uscxml/transform/ChartToC.h @@ -58,7 +58,7 @@ protected: void writeFSM(std::ostream& stream); void writeCharArrayInitList(std::ostream& stream, const std::string& boolString); - void writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, int indent = 0); + void writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent = 0); void resortStates(XERCESC_NS::DOMNode* node); void setHistoryCompletion(); diff --git a/src/uscxml/transform/ChartToPromela.cpp b/src/uscxml/transform/ChartToPromela.cpp new file mode 100644 index 0000000..a697d99 --- /dev/null +++ b/src/uscxml/transform/ChartToPromela.cpp @@ -0,0 +1,2625 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "uscxml/transform/ChartToPromela.h" +#include "uscxml/util/Predicates.h" +#include "uscxml/util/String.h" +#include "uscxml/plugins/datamodel/promela/PromelaParser.h" +#include "uscxml/plugins/datamodel/promela/parser/promela.tab.hpp" + +#include <boost/algorithm/string.hpp> +#include <easylogging++.h> + +#include <algorithm> + +#define ADAPT_SRC(code) _analyzer.adaptCode(code, _prefix) +#define BIT_WIDTH(number) (number > 1 ? (int)ceil(log((double)number) / log((double)2.0)) : 1) +#define EVENT_NAME (_analyzer.usesComplexEventStruct() ? "_event.name" : "_event") + +namespace uscxml { + +using namespace XERCESC_NS; + + +Transformer ChartToPromela::transform(const Interpreter& other) { + return std::shared_ptr<TransformerImpl>(new ChartToPromela(other)); +} + +ChartToPromela::~ChartToPromela() { +} + +/** + The following tests FAILED: + 1740 - w3c/spin/promela/test150.scxml (Failed) + 1741 - w3c/spin/promela/test151.scxml (Failed) + 1742 - w3c/spin/promela/test152.scxml (Failed) + 1743 - w3c/spin/promela/test153.scxml (Failed) + 1744 - w3c/spin/promela/test155.scxml (Failed) + 1745 - w3c/spin/promela/test156.scxml (Failed) + 1749 - w3c/spin/promela/test173.scxml (Failed) + 1750 - w3c/spin/promela/test174.scxml (Failed) + 1752 - w3c/spin/promela/test176.scxml (Failed) + 1753 - w3c/spin/promela/test178.scxml (Failed) + 1754 - w3c/spin/promela/test179.scxml (Failed) + 1757 - w3c/spin/promela/test186.scxml (Failed) + 1762 - w3c/spin/promela/test192.scxml (Failed) + 1763 - w3c/spin/promela/test193.scxml (Failed) + 1765 - w3c/spin/promela/test198.scxml (Failed) + 1769 - w3c/spin/promela/test205.scxml (Failed) + 1770 - w3c/spin/promela/test207.scxml (Failed) + 1771 - w3c/spin/promela/test208.scxml (Failed) + 1772 - w3c/spin/promela/test210.scxml (Failed) + 1773 - w3c/spin/promela/test215.scxml (Failed) + 1774 - w3c/spin/promela/test216.scxml (Failed) + 1776 - w3c/spin/promela/test223.scxml (Failed) + 1777 - w3c/spin/promela/test224.scxml (Failed) + 1778 - w3c/spin/promela/test225.scxml (Failed) + 1780 - w3c/spin/promela/test228.scxml (Failed) + 1782 - w3c/spin/promela/test230.scxml (Failed) + 1783 - w3c/spin/promela/test232.scxml (Failed) + 1785 - w3c/spin/promela/test234.scxml (Failed) + 1787 - w3c/spin/promela/test236.scxml (Failed) + 1788 - w3c/spin/promela/test237.scxml (Failed) + 1789 - w3c/spin/promela/test239.scxml (Failed) + 1790 - w3c/spin/promela/test240.scxml (Failed) + 1791 - w3c/spin/promela/test241.scxml (Failed) + 1792 - w3c/spin/promela/test242.scxml (Failed) + 1797 - w3c/spin/promela/test250.scxml (Failed) + 1798 - w3c/spin/promela/test252.scxml (Failed) + 1799 - w3c/spin/promela/test253.scxml (Failed) + 1802 - w3c/spin/promela/test278.scxml (Failed) + 1803 - w3c/spin/promela/test279.scxml (Failed) + 1805 - w3c/spin/promela/test286.scxml (Failed) + 1808 - w3c/spin/promela/test294.scxml (Failed) + 1809 - w3c/spin/promela/test298.scxml (Failed) + 1811 - w3c/spin/promela/test302.scxml (Failed) + 1813 - w3c/spin/promela/test304.scxml (Failed) + 1814 - w3c/spin/promela/test309.scxml (Failed) + 1815 - w3c/spin/promela/test310.scxml (Failed) + 1816 - w3c/spin/promela/test311.scxml (Failed) + 1817 - w3c/spin/promela/test312.scxml (Failed) + 1818 - w3c/spin/promela/test313.scxml (Failed) + 1819 - w3c/spin/promela/test314.scxml (Failed) + 1820 - w3c/spin/promela/test318.scxml (Failed) + 1823 - w3c/spin/promela/test322.scxml (Failed) + 1825 - w3c/spin/promela/test324.scxml (Failed) + 1827 - w3c/spin/promela/test326.scxml (Failed) + 1828 - w3c/spin/promela/test329.scxml (Failed) + 1829 - w3c/spin/promela/test330.scxml (Failed) + 1830 - w3c/spin/promela/test331.scxml (Failed) + 1831 - w3c/spin/promela/test332.scxml (Failed) + 1832 - w3c/spin/promela/test333.scxml (Failed) + 1833 - w3c/spin/promela/test335.scxml (Failed) + 1835 - w3c/spin/promela/test337.scxml (Failed) + 1837 - w3c/spin/promela/test339.scxml (Failed) + 1838 - w3c/spin/promela/test342.scxml (Failed) + 1839 - w3c/spin/promela/test343.scxml (Failed) + 1840 - w3c/spin/promela/test344.scxml (Failed) + 1841 - w3c/spin/promela/test346.scxml (Failed) + 1842 - w3c/spin/promela/test347.scxml (Failed) + 1846 - w3c/spin/promela/test351.scxml (Failed) + 1847 - w3c/spin/promela/test352.scxml (Failed) + 1848 - w3c/spin/promela/test354.scxml (Failed) + 1849 - w3c/spin/promela/test355.scxml (Failed) + 1850 - w3c/spin/promela/test364.scxml (Failed) + 1851 - w3c/spin/promela/test372.scxml (Failed) + 1854 - w3c/spin/promela/test377.scxml (Failed) + 1855 - w3c/spin/promela/test378.scxml (Failed) + 1856 - w3c/spin/promela/test387.scxml (Failed) + 1857 - w3c/spin/promela/test388.scxml (Failed) + 1858 - w3c/spin/promela/test396.scxml (Failed) + 1859 - w3c/spin/promela/test399.scxml (Failed) + 1860 - w3c/spin/promela/test401.scxml (Failed) + 1861 - w3c/spin/promela/test402.scxml (Failed) + 1862 - w3c/spin/promela/test403a.scxml (Failed) + 1863 - w3c/spin/promela/test403b.scxml (Failed) + 1864 - w3c/spin/promela/test403c.scxml (Failed) + 1865 - w3c/spin/promela/test404.scxml (Failed) + 1866 - w3c/spin/promela/test405.scxml (Failed) + 1867 - w3c/spin/promela/test406.scxml (Failed) + 1868 - w3c/spin/promela/test407.scxml (Failed) + 1869 - w3c/spin/promela/test409.scxml (Failed) + 1870 - w3c/spin/promela/test411.scxml (Failed) + 1871 - w3c/spin/promela/test412.scxml (Failed) + 1872 - w3c/spin/promela/test413.scxml (Failed) + 1873 - w3c/spin/promela/test415.scxml (Failed) + 1874 - w3c/spin/promela/test416.scxml (Failed) + 1875 - w3c/spin/promela/test417.scxml (Failed) + 1877 - w3c/spin/promela/test421.scxml (Failed) + 1878 - w3c/spin/promela/test422.scxml (Failed) + 1880 - w3c/spin/promela/test487.scxml (Failed) + 1881 - w3c/spin/promela/test488.scxml (Failed) + 1882 - w3c/spin/promela/test495.scxml (Failed) + 1886 - w3c/spin/promela/test503.scxml (Failed) + 1887 - w3c/spin/promela/test504.scxml (Failed) + 1888 - w3c/spin/promela/test505.scxml (Failed) + 1890 - w3c/spin/promela/test509.scxml (Failed) + 1892 - w3c/spin/promela/test518.scxml (Failed) + 1893 - w3c/spin/promela/test519.scxml (Failed) + 1894 - w3c/spin/promela/test520.scxml (Failed) + 1897 - w3c/spin/promela/test525.scxml (Failed) + 1898 - w3c/spin/promela/test527.scxml (Failed) + 1899 - w3c/spin/promela/test528.scxml (Failed) + 1900 - w3c/spin/promela/test529.scxml (Failed) + 1901 - w3c/spin/promela/test530.scxml (Failed) + 1902 - w3c/spin/promela/test531.scxml (Failed) + 1903 - w3c/spin/promela/test532.scxml (Failed) + 1904 - w3c/spin/promela/test533.scxml (Failed) + 1905 - w3c/spin/promela/test534.scxml (Failed) + 1906 - w3c/spin/promela/test550.scxml (Failed) + 1907 - w3c/spin/promela/test551.scxml (Failed) + 1911 - w3c/spin/promela/test567.scxml (Failed) + 1912 - w3c/spin/promela/test570.scxml (Failed) + 1913 - w3c/spin/promela/test576.scxml (Failed) + 1915 - w3c/spin/promela/test579.scxml (Failed) + 1916 - w3c/spin/promela/test580.scxml (Failed) +*/ + +void ChartToPromela::prepare() { + if (_machinesAll == NULL) { + _machinesAll = new std::map<DOMNode*, ChartToPromela*>(); + (*_machinesAll)[_scxml] = this; + } + + if (_machinesAllPerId == NULL) + _machinesAllPerId = new std::map<std::string, XERCESC_NS::DOMNode* >(); + + if (_parentTopMost == NULL) + _parentTopMost = 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 replae 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) { + + _analyzer.analyze(this); + // same preparations as the C transformation + prepare(); + + stream << "/** generated from " << std::endl; + stream << " " << std::string(_baseURL) << std::endl; + stream << " Use as:" << std::endl; + stream << " $ spin -a this.pml" << std::endl; + stream << " $ gcc pan.c -o pan" << std::endl; + stream << " $ ./pan -a -n -N w3c" << std::endl; + stream << " */" << std::endl; + stream << std::endl; + + + writeMacros(stream); + stream << std::endl; + writeTypeDefs(stream); + stream << std::endl; + writeTypes(stream); + stream << std::endl; + writeStrings(stream); + stream << std::endl; + writeCancelEvents(stream); + stream << std::endl; + writeFSM(stream); + stream << std::endl; + + + stream << "init {" << std::endl; + + stream << "/* initialize state and transition information */" << std::endl; + writeTransitions(stream); + stream << std::endl; + writeStates(stream); + stream << std::endl; + + stream << "/* initialize data model variables */" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_PRISTINE] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + + for (auto initializer : _varInitializers) { + stream << ADAPT_SRC(beautifyIndentation(initializer, 1)) << std::endl; + } + + stream << std::endl; + + stream << " run " << _prefix << "step() priority 10;" << std::endl; + stream << "}" << std::endl; + stream << std::endl; + stream << "ltl w3c { eventually (" << _prefix << "config[" << _prefix << "PASS]) }" << std::endl; + +} + +void ChartToPromela::bit_clear_all(std::ostream& stream, + const std::string& identifier, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << std::endl; + stream << padding << "/** clearing all bits of " << identifier << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << identifier << "[" << i << "] = false;" << std::endl; + } +} + +void ChartToPromela::bit_copy(std::ostream& stream, + const std::string& from, + const std::string& to, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << std::endl; + stream << padding << "/** copy bits from " << from << " to " << to << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << to << "[" << i << "] = "<< from << "[" << i << "];" << std::endl; + } +} + +void ChartToPromela::bit_or(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << std::endl; + stream << padding << "/** or'ing bits in " << to << " with mask " << mask << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] | " << mask << "[" << i << "];" << std::endl; + } +} + +void ChartToPromela::bit_and(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << std::endl; + stream << padding << "/** and'ing bits in " << to << " with mask " << mask << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] & " << mask << "[" << i << "];" << std::endl; + } +} + +void ChartToPromela::bit_and_not(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << std::endl; + stream << padding << "/** not and'ing bits in " << to << " with mask " << mask << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << to << "[" << i << "] = "<< to << "[" << i << "] & !" << mask << "[" << i << "];" << std::endl; + } +} + +void ChartToPromela::bit_has_and(std::ostream& stream, + const std::string& a, + const std::string& b, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + stream << "(false /** is there a common bit in " << a << " and " << b << " */" << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << " || " << a << "[" << i << "] & "<< b << "[" << i << "]" << std::endl; + } + stream << padding << ")"; + +} + +void ChartToPromela::printBitArray(std::ostream& stream, + const std::string& array, + size_t length, + size_t indent) { + std::string padding; + while (indent--) + padding += " "; + + stream << padding << "printf(\""; + for (size_t i = 0; i < length; i++) { + stream << "%d"; + } + stream << "\", " << std::endl; + for (size_t i = 0; i < length; i++) { + stream << padding << " " << array << "[" << toStr(i) << "]"; + if (i + 1 < length) { + stream << ", " << std::endl; + } + } + stream << ");" << std::endl; +} + +void ChartToPromela::writeMacros(std::ostream& stream) { + stream << "/* machine state flags */" << std::endl; + stream << "#define USCXML_CTX_PRISTINE 0" << std::endl; + stream << "#define USCXML_CTX_SPONTANEOUS 1" << std::endl; + stream << "#define USCXML_CTX_INITIALIZED 2" << std::endl; + stream << "#define USCXML_CTX_TOP_LEVEL_FINAL 3" << std::endl; + stream << "#define USCXML_CTX_TRANSITION_FOUND 4" << std::endl; + stream << "#define USCXML_CTX_FINISHED 5" << std::endl; + stream << std::endl; + + stream << "#define USCXML_TRANS_SPONTANEOUS 0" << std::endl; + stream << "#define USCXML_TRANS_TARGETLESS 1" << std::endl; + stream << "#define USCXML_TRANS_INTERNAL 2" << std::endl; + stream << "#define USCXML_TRANS_HISTORY 3" << std::endl; + stream << "#define USCXML_TRANS_INITIAL 4" << std::endl; + stream << std::endl; + + stream << "#define USCXML_STATE_ATOMIC 0" << std::endl; + stream << "#define USCXML_STATE_PARALLEL 1" << std::endl; + stream << "#define USCXML_STATE_COMPOUND 2" << std::endl; + stream << "#define USCXML_STATE_FINAL 3" << std::endl; + stream << "#define USCXML_STATE_HISTORY_DEEP 4" << std::endl; + stream << "#define USCXML_STATE_HISTORY_SHALLOW 5" << std::endl; + stream << "#define USCXML_STATE_INITIAL 6" << std::endl; + stream << "#define USCXML_STATE_HAS_HISTORY 7" << std::endl; + stream << std::endl; + + stream << "#define USCXML_ERR_OK 0" << std::endl; + stream << "#define USCXML_ERR_DONE 1" << std::endl; + stream << std::endl; + + stream << "#define USCXML_EVENT_SPONTANEOUS 0" << std::endl; + stream << std::endl; + stream << "#define TRACE_EXECUTION 1" << std::endl; + stream << std::endl; + + +} + +void ChartToPromela::writeTypeDefs(std::ostream& stream) { + stream << "/* 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 << " int delay;" << std::endl; +#if NEW_DELAY_RESHUFFLE +#else + stream << " int seqNr;" << std::endl; +#endif + } + stream << " int name;" << std::endl; + if (_analyzer.usesEventField("invokeid")) { + stream << " int invokeid;" << 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("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::writeTypes(std::ostream& stream) { + stream << "/* type definitions and global variables */" << std::endl; + stream << "bool " << _prefix << "flags[6];" << std::endl; + stream << "bool " << _prefix << "config[" << _states.size() << "];" << std::endl; + 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 << "_event_t " << _prefix << "_event; /* current event */" << 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 << "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; + } + + stream << std::endl; + stream << "typedef transition {" << 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; + if (_transitions.size() > 0) { + stream << "hidden transition " << _prefix << "transitions[" << toStr(_transitions.size()) << "];" << std::endl; + } + stream << std::endl; + + stream << "typedef state {" << 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 << "hidden state " << _prefix << "states[" << toStr(_states.size()) << "];" << 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 " << _prefix << "_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 int _lastSeqId = 0; /* sequential counter for delayed events */" << std::endl; + + stream << std::endl; + + std::set<std::string> processedIdentifiers; + + // automatic types + std::list<DOMElement*> datas = DOMUtils::inDocumentOrder({ XML_PREFIX(_scxml).str() + "data" }, _scxml, false); + PromelaCodeAnalyzer::PromelaTypedef allTypes = _analyzer.getTypes(); + + for (auto data : datas) { + std::string identifier = (HAS_ATTR_CAST(data, "id") ? ATTR_CAST(data, "id") : ""); + std::string type = boost::trim_copy(HAS_ATTR_CAST(data, "type") ? ATTR_CAST(data, "type") : ""); + + _dataModelVars.insert(identifier); + if (processedIdentifiers.find(identifier) != processedIdentifiers.end()) + continue; + + processedIdentifiers.insert(identifier); + + if (boost::starts_with(type, "string")) { + type = "int" + type.substr(6, type.length() - 6); + } + + if (type.length() == 0 || type == "auto") { + if (allTypes.types.find(identifier) != allTypes.types.end()) { + type = allTypes.types[identifier].name; + } else { + LOG(ERROR) << "Automatic or no type for '" << identifier << "' but no type resolved"; + continue; + } + } + + std::string arrSize; + size_t bracketPos = type.find("["); + if (bracketPos != std::string::npos) { + arrSize = type.substr(bracketPos, type.length() - bracketPos); + type = type.substr(0, bracketPos); + } + std::string decl = type + " " + _prefix + identifier + arrSize; + stream << decl << ";" << std::endl; + + } + + // implicit and dynamic types + std::map<std::string, PromelaCodeAnalyzer::PromelaTypedef>::iterator typeIter = allTypes.types.begin(); + while(typeIter != allTypes.types.end()) { + if (typeIter->second.occurrences.find(this) == typeIter->second.occurrences.end()) { + typeIter++; + continue; + } + + if (processedIdentifiers.find(typeIter->first) != processedIdentifiers.end()) { + typeIter++; + continue; + } + + 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++; + continue; + } + + processedIdentifiers.insert(typeIter->first); + + if (typeIter->second.types.size() == 0) { + stream << "hidden " << declForRange(_prefix + typeIter->first, typeIter->second.minValue, typeIter->second.maxValue) << ";" << std::endl; + } else { + stream << "hidden " << _prefix << typeIter->second.name << " " << typeIter->first << ";" << std::endl; + } + typeIter++; + } + +} + +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; + } + } + } + + + for (auto literal : literals) { + stream << "#define " << _analyzer.macroForLiteral(literal) << " " << _analyzer.indexForLiteral(literal) << " /* " << literal << " */" << std::endl; + } +} + +void ChartToPromela::writeTransitions(std::ostream& stream) { + for (size_t i = 0; i < _transitions.size(); i++) { + DOMElement* transition(_transitions[i]); + + /** source */ + stream << " " << _prefix << "transitions[" << toStr(i) << "].source = "; + stream << ATTR_CAST(transition->getParentNode(), "documentOrder") ; + stream << ";" << std::endl; + + /** target */ + if (HAS_ATTR(transition, "targetBools")) { + std::string targetBools = ATTR(transition, "targetBools"); + for (size_t j = 0; j < _states.size(); j++) { + if (targetBools[j] == '1') + stream << " " << _prefix << "transitions[" << toStr(i) << "].target[" << toStr(j) << "] = 1;" << std::endl; + } + } + +#if 0 + /** events */ + if (HAS_ATTR(transition, "event")) { + std::list<std::string> events = tokenize(ATTR(transition, "event"), ' ', true); + for(auto& event : events) { + auto trieNodes = _analyzer.getTrie().getWordsWithPrefix(event); + for(auto trieNode : trieNodes) { + stream << " " << _prefix << "transitions[" << toStr(i) << "].event[" << _analyzer.macroForLiteral(trieNode->value) << "] = 1;" << std::endl; + } + } + } +#endif + + if (!HAS_ATTR(transition, "event")) + stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_SPONTANEOUS] = 1;" << std::endl; + + if (!HAS_ATTR(transition, "target")) + stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_TARGETLESS] = 1;" << std::endl; + + if (HAS_ATTR(transition, "type") && ATTR(transition, "type") == "internal") + stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_INTERNAL] = 1;" << std::endl; + + if (TAGNAME_CAST(transition->getParentNode()) == XML_PREFIX(transition).str() + "history") + stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_HISTORY] = 1;" << std::endl; + + if (TAGNAME_CAST(transition->getParentNode()) == XML_PREFIX(transition).str() + "initial") + stream << " " << _prefix << "transitions[" << toStr(i) << "].type[USCXML_TRANS_INITIAL] = 1;" << std::endl; + + if (HAS_ATTR(transition, "conflictBools")) { + std::string conflicts = ATTR(transition, "conflictBools"); + for (auto j = 0; j < conflicts.size(); j++) { + if (conflicts[j] == '1') + stream << " " << _prefix << "transitions[" << toStr(i) << "].conflicts[" << toStr(j) << "] = 1;" << std::endl; + } + } + + if (HAS_ATTR(transition, "exitSetBools")) { + std::string exitSet = ATTR(transition, "exitSetBools"); + for (auto j = 0; j < exitSet.size(); j++) { + if (exitSet[j] == '1') + stream << " " << _prefix << "transitions[" << toStr(i) << "].exit_set[" << toStr(j) << "] = 1;" << std::endl; + } + } + + stream << std::endl; + + } +} + + + +void ChartToPromela::writeStates(std::ostream& stream) { + for (size_t i = 0; i < _states.size(); i++) { + DOMElement* state(_states[i]); + + stream << " " << _prefix << "states[" << toStr(i) << "].parent = "; + stream << (i == 0 ? "0" : ATTR_CAST(state->getParentNode(), "documentOrder")); + stream << ";" << std::endl; + + + if (HAS_ATTR(state, "childBools")) { + std::string childs = ATTR(state, "childBools"); + for (auto j = 0; j < childs.size(); j++) { + if (childs[j] == '1') + stream << " " << _prefix << "states[" << toStr(i) << "].children[" << toStr(j) << "] = 1;" << std::endl; + } + } + + if (HAS_ATTR(state, "completionBools")) { + std::string completions = ATTR(state, "completionBools"); + for (auto j = 0; j < completions.size(); j++) { + if (completions[j] == '1') + stream << " " << _prefix << "states[" << toStr(i) << "].completion[" << toStr(j) << "] = 1;" << std::endl; + } + } + + if (HAS_ATTR(state, "ancBools")) { + std::string ancestors = ATTR(state, "ancBools"); + for (auto j = 0; j < ancestors.size(); j++) { + if (ancestors[j] == '1') + stream << " " << _prefix << "states[" << toStr(i) << "].ancestors[" << toStr(j) << "] = 1;" << std::endl; + } + } + if (false) { + } else if (iequals(TAGNAME(state), "initial")) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_INITIAL] = 1;" << std::endl; + } else if (isFinal(state)) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_FINAL] = 1;" << std::endl; + } else if (isHistory(state)) { + if (HAS_ATTR(state, "type") && iequals(ATTR(state, "type"), "deep")) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_HISTORY_DEEP] = 1;" << std::endl; + } else { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_HISTORY_SHALLOW] = 1;" << std::endl; + } + } else if (isAtomic(state)) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_ATOMIC] = 1;" << std::endl; + } else if (isParallel(state)) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_PARALLEL] = 1;" << std::endl; + } else if (isCompound(state)) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_COMPOUND] = 1;" << std::endl; + } else { // <scxml> + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_COMPOUND] = 1;" << std::endl; + } + if (HAS_ATTR(state, "hasHistoryChild")) { + stream << " " << _prefix << "states[" << toStr(i) << "].type[USCXML_STATE_HAS_HISTORY] = 1;" << std::endl; + } + + stream << std::endl; + + } +} + + +void ChartToPromela::writeHelpers(std::ostream& stream) { + + +} + +void ChartToPromela::writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent) { + if (!node) + return; + + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + if (node->getNodeType() == DOMNode::TEXT_NODE) { + if (boost::trim_copy(X(node->getNodeValue()).str()).length() > 0) + stream << beautifyIndentation(ADAPT_SRC(X(node->getNodeValue()).str()), indent) << std::endl; + } + + if (node->getNodeType() != DOMNode::ELEMENT_NODE) + return; // skip anything not an element + + const XERCESC_NS::DOMElement* element = static_cast<const XERCESC_NS::DOMElement*>(node); + + if (false) { + } else if(TAGNAME(element) == "onentry" || + TAGNAME(element) == "onexit" || + TAGNAME(element) == "transition" || + TAGNAME(element) == "finalize") { + // descent into childs and write their contents + const XERCESC_NS::DOMNode* child = node->getFirstChild(); + while(child) { + writeExecContent(stream, child, indent); + child = child->getNextSibling(); + } + } else if(TAGNAME(element) == "script") { + std::list<DOMNode*> scriptTexts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, node, true); + for (auto scriptText : scriptTexts) { + stream << ADAPT_SRC(beautifyIndentation(X(scriptText->getNodeValue()).str(), indent)) << std::endl; + } + + } else if(TAGNAME(element) == "log") { + std::string label = (HAS_ATTR(element, "label") ? ATTR(element, "label") : ""); + std::string expr = (HAS_ATTR(element, "expr") ? ADAPT_SRC(ATTR(element, "expr")) : ""); + std::string trimmedExpr = boost::trim_copy(expr); + bool isStringLiteral = (boost::starts_with(trimmedExpr, "\"") || boost::starts_with(trimmedExpr, "'")); + + std::string formatString; + std::string varString; + std::string seperator; + + if (label.size() > 0) { + if (expr.size() > 0) { + formatString += label + ": "; + } else { + formatString += label; + } + } + + if (isStringLiteral) { + formatString += expr; + } else if (expr.size() > 0) { + formatString += "%d"; + varString += seperator + expr; + } + + if (varString.length() > 0) { + stream << padding << "printf(\"" + formatString + "\", " + varString + ");" << std::endl; + } else { + stream << padding << "printf(\"" + formatString + "\");" << std::endl; + } + + } else if(TAGNAME(element) == "foreach") { + stream << padding << "for (" << _prefix << (HAS_ATTR(element, "index") ? ATTR(element, "index") : "_index") << " in " << _prefix << ATTR(element, "array") << ") {" << std::endl; + if (HAS_ATTR(element, "item")) { + stream << padding << " " << _prefix << ATTR(element, "item") << " = " << _prefix << ATTR(element, "array") << "[" << _prefix << (HAS_ATTR(element, "index") ? ATTR(element, "index") : "_index") << "];" << std::endl; + } + const XERCESC_NS::DOMNode* child = element->getFirstChild(); + while(child) { + writeExecContent(stream, child, indent + 1); + child = child->getNextSibling(); + } + // if (HAS_ATTR(nodeElem, "index")) + // stream << padding << " " << _prefix << ATTR(nodeElem, "index") << "++;" << std::endl; + stream << padding << "}" << std::endl; + + } else if(TAGNAME(element) == "if") { + std::list<DOMElement*> condChain; + condChain.push_back(const_cast<DOMElement*>(element)); + + condChain.splice(condChain.end(), DOMUtils::filterChildElements(XML_PREFIX(element).str() + "elseif", element)); + condChain.splice(condChain.end(), DOMUtils::filterChildElements(XML_PREFIX(element).str() + "else", element)); + + 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) << std::endl; + + } else if(TAGNAME(element) == "send" || TAGNAME(element) == "raise") { + std::string targetQueue; + std::string insertOp = "!"; + if (TAGNAME(element) == "raise") { + targetQueue = _prefix + "iQ"; + } else if (!HAS_ATTR(element, "target")) { +// if (_allowEventInterleaving) { +// targetQueue = _prefix + "tmpQ"; +// } else { + targetQueue = _prefix + "eQ"; +// } + } else if (ATTR(element, "target").compare("#_internal") == 0) { + targetQueue = _prefix + "iQ"; + } else if (ATTR(element, "target").compare("#_parent") == 0) { + targetQueue = _parent->_prefix + "eQ"; + } else if (boost::starts_with(ATTR(element, "target"), "#_") && _machinesPerId.find(ATTR(element, "target").substr(2)) != _machinesPerId.end()) { + targetQueue = _machines[_machinesPerId[ATTR(element, "target").substr(2)]]->_prefix + "eQ"; + } + if (targetQueue.length() > 0) { + // this is for our external queue + std::string event; + + if (HAS_ATTR(element, "event")) { + event = _analyzer.macroForLiteral(ATTR(element, "event")); + } else if (HAS_ATTR(element, "eventexpr")) { + event = ADAPT_SRC(ATTR(element, "eventexpr")); + } + if (_analyzer.usesComplexEventStruct()) { + stream << padding << "{" << std::endl; + std::string typeReset = _analyzer.getTypeReset(_prefix + "_event", _analyzer.getType("_event"), padding + " "); + std::stringstream typeAssignSS; + typeAssignSS << padding << " " << _prefix << EVENT_NAME << " = " << event << ";" << std::endl; + + if (HAS_ATTR(element, "idlocation")) { + typeAssignSS << padding << " /* idlocation */" << std::endl; + typeAssignSS << padding << " _lastSendId = _lastSendId + 1;" << std::endl; + typeAssignSS << padding << " " << _prefix << ATTR(element, "idlocation") << " = _lastSendId;" << std::endl; + typeAssignSS << padding << " " << _prefix << "_event.sendid = _lastSendId;" << std::endl; + typeAssignSS << padding << " if" << std::endl; + typeAssignSS << padding << " :: _lastSendId == 2147483647 -> _lastSendId = 0;" << std::endl; + typeAssignSS << padding << " :: else -> skip;" << std::endl; + typeAssignSS << padding << " fi;" << std::endl; + } else if (HAS_ATTR(element, "id")) { + typeAssignSS << padding << " " << _prefix << "_event.sendid = " << _analyzer.macroForLiteral(ATTR(element, "id")) << ";" << std::endl; + } + + if (_invokerid.length() > 0) { // do not send invokeid if we send / raise to ourself + typeAssignSS << padding << " " << _prefix << "_event.invokeid = " << _analyzer.macroForLiteral(_invokerid) << ";" << std::endl; + } + + if (_analyzer.usesEventField("origintype") && !boost::ends_with(targetQueue, "iQ")) { + typeAssignSS << padding << " " << _prefix << "_event.origintype = " << _analyzer.macroForLiteral("http://www.w3.org/TR/scxml/#SCXMLEventProcessor") << ";" << std::endl; + } + + if (_analyzer.usesEventField("delay")) { +#if NEW_DELAY_RESHUFFLE +#else + insertOp += "!"; + typeAssignSS << padding << " _lastSeqId = _lastSeqId + 1;" << std::endl; +#endif + if (HAS_ATTR_CAST(element, "delay")) { + typeAssignSS << padding << " " << _prefix << "_event.delay = " << ATTR_CAST(element, "delay") << ";" << std::endl; + } else if (HAS_ATTR_CAST(element, "delayexpr")) { + typeAssignSS << padding << " " << _prefix << "_event.delay = " << ADAPT_SRC(ATTR_CAST(element, "delayexpr")) << ";" << std::endl; + } else { + typeAssignSS << padding << " " << _prefix << "_event.delay = 0;" << std::endl; + } +#if NEW_DELAY_RESHUFFLE +#else + typeAssignSS << padding << " " << _prefix << "_event.seqNr = _lastSeqId;" << std::endl; +#endif + } + + if (_analyzer.usesEventField("type")) { + std::string eventType = (targetQueue.compare("iQ!") == 0 ? _analyzer.macroForLiteral("internal") : _analyzer.macroForLiteral("external")); + typeAssignSS << padding << " " << _prefix << "_event.type = " << eventType << ";" << std::endl; + } + + std::list<DOMElement*> sendParams = DOMUtils::filterChildElements(XML_PREFIX(element).str() + "param", element); + std::list<DOMElement*> sendContents = DOMUtils::filterChildElements(XML_PREFIX(element).str() + "content", element); + std::string sendNameList = ATTR(element, "namelist"); + if (sendParams.size() > 0) { + for (auto sendParam : sendParams) { + typeAssignSS << padding << " " << _prefix << "_event.data." << ATTR(sendParam, "name") << " = " << ADAPT_SRC(ATTR(sendParam, "expr")) << ";" << std::endl; + } + } + if (sendNameList.size() > 0) { + std::list<std::string> nameListIds = tokenize(sendNameList); + std::list<std::string>::iterator nameIter = nameListIds.begin(); + while(nameIter != nameListIds.end()) { + typeAssignSS << padding << " " << _prefix << "_event.data." << *nameIter << " = " << ADAPT_SRC(*nameIter) << ";" << std::endl; + nameIter++; + } + } + + if (sendParams.size() == 0 && sendNameList.size() == 0 && sendContents.size() > 0) { + DOMElement* contentElem = sendContents.front(); + if (contentElem->hasChildNodes() && contentElem->getFirstChild()->getNodeType() == DOMNode::TEXT_NODE) { + std::string content = spaceNormalize(X(contentElem->getFirstChild()->getNodeValue()).str()); + if (!isNumeric(content.c_str(), 10)) { + typeAssignSS << padding << " " << _prefix << "_event.data = " << _analyzer.macroForLiteral(content) << ";" << std::endl; + } else { + typeAssignSS << padding << " " << _prefix << "_event.data = " << content << ";" << std::endl; + } + } else if (HAS_ATTR(contentElem, "expr")) { + typeAssignSS << padding << " " << _prefix << "_event.data = " << ADAPT_SRC(ATTR(contentElem, "expr")) << ";" << std::endl; + } + } + + // remove all fields from typeReset that are indeed set by typeAssign + // for (std::string assigned; std::getline(typeAssignSS, assigned); ) { + // assigned = assigned.substr(0, assigned.find('=')); + // assigned = assigned.substr(assigned.find('.')); + // std::istringstream typeResetSS (typeReset); + // for (std::string reset; std::getline(typeResetSS, reset); ) { + // if (!boost::find_first(reset, assigned)) { + // stream << reset << std::endl; + // } + // } + // } + // stream << typeAssignSS.str(); + + std::istringstream typeResetSS (typeReset); + for (std::string reset; std::getline(typeResetSS, reset); ) { + std::string resetField = reset.substr(0, reset.find('=')); + resetField = resetField.substr(resetField.find('.')); + for (std::string assigned; std::getline(typeAssignSS, assigned); ) { + if (boost::find_first(resetField, assigned)) { + break; + } + } + stream << reset << std::endl; + } + stream << typeAssignSS.str(); + + + stream << padding << " " << targetQueue << insertOp << _prefix <<"_event;" << std::endl; + +#if NEW_DELAY_RESHUFFLE + if (_analyzer->usesEventField("delay") && !boost::ends_with(targetQueue, "iQ")) { + stream << padding << " insertWithDelay(" << targetQueue << ");" << std::endl; + } +#endif + + stream << padding << "}" << std::endl; + } else { + stream << padding << targetQueue << insertOp << event << ";" << std::endl; + } + } + } else if(TAGNAME(element) == "cancel") { + if (HAS_ATTR(element, "sendid")) { + stream << padding << "cancelSendId(" << _analyzer.macroForLiteral(ATTR(element, "sendid")) << ", " << (_invokerid.size() > 0 ? _analyzer.macroForLiteral(_invokerid) : "0") << ");" << std::endl; + } else if (HAS_ATTR(element, "sendidexpr")) { + stream << padding << "cancelSendId(" << ADAPT_SRC(ATTR(element, "sendidexpr")) << ", " << (_invokerid.size() > 0 ? _analyzer.macroForLiteral(_invokerid) : "0") << ");" << std::endl; + } + } else { + std::cerr << "'" << TAGNAME(element) << "' not supported" << std::endl << element << std::endl; + assert(false); + } + + +} + + + +void ChartToPromela::writeFSM(std::ostream& stream) { + stream << "/* machine microstep function */" << std::endl; + stream << "#define USCXML_NUMBER_STATES " << _states.size() << std::endl; + stream << "#define USCXML_NUMBER_TRANS " << _transitions.size() << std::endl; + + stream << "proctype " << _prefix << "step() { atomic {" << std::endl; + stream << std::endl; + stream << "/* ---------------------------- */" << std::endl; + stream << "MICROSTEP:" << std::endl; + + stream << "do" << std::endl; + stream << ":: !" << _prefix << "flags[USCXML_CTX_FINISHED] -> {" << std::endl; + stream << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Taking a step\\n\");" << std::endl; + stream << "#endif" << 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 << " int err = USCXML_ERR_OK;" << std::endl; + + 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; + +#if 0 + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_FINISHED]" << std::endl; + stream << " ACCEPT: {" << std::endl; + stream << " false;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Machine not finished\\n\");" << std::endl; + stream << "#endif" << std::endl; +#endif + +#if 0 + stream << " if (ctx->flags & USCXML_CTX_TOP_LEVEL_FINAL) -> {" << std::endl; + stream << " /* exit all remaining states */" << std::endl; + stream << " i = USCXML_NUMBER_STATES;" << std::endl; + stream << " while(i-- > 0) {" << std::endl; + stream << " if (BIT_HAS(i, ctx->config)) {" << std::endl; + stream << " /* call all on exit handlers */" << std::endl; + stream << " if (USCXML_GET_STATE(i).on_exit != NULL) {" << std::endl; + stream << " if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; + stream << " return err;" << std::endl; + stream << " }" << std::endl; + // stream << " BIT_CLEAR(i, ctx->config);" << std::endl; + stream << " }" << std::endl; + stream << " if (BIT_HAS(i, ctx->invocations)) {" << std::endl; + stream << " if (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; + stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1);" << std::endl; + stream << " BIT_CLEAR(i, ctx->invocations);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " ctx->flags |= USCXML_CTX_FINISHED;" << std::endl; + stream << " return USCXML_ERR_DONE;" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + +#endif + + stream << " if" << std::endl; + stream << " ::" << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] -> {" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Top level final state reached\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " /* exit all remaining states */" << std::endl; + stream << " i = 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] -> {" << std::endl; + stream << " /* TODO: call all on exit handlers */" << 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 << " /* TODO: cancel invocations */" << 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 << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Ending machine!\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_FINISHED] = true;" << std::endl; + stream << " goto MICROSTEP;" << std::endl; + + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + +#if 0 + stream << " bit_clear_all(target_set, nr_states_bytes);" << std::endl; + stream << " bit_clear_all(trans_set, nr_trans_bytes);" << std::endl; + stream << " if unlikely(ctx->flags == USCXML_CTX_PRISTINE) {" << std::endl; + stream << " if (ctx->machine->script != NULL)" << std::endl; + stream << " ctx->machine->script(ctx, &ctx->machine->states[0], NULL);" << std::endl; + stream << " bit_or(target_set, ctx->machine->states[0].completion, nr_states_bytes);" << std::endl; + stream << " ctx->flags |= USCXML_CTX_SPONTANEOUS | USCXML_CTX_INITIALIZED;" << std::endl; + stream << " goto ESTABLISH_ENTRY_SET;" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << " if" << std::endl; + stream << " ::" << _prefix << "flags[USCXML_CTX_PRISTINE] -> {" << std::endl; + stream << " /* run global scripts */" << std::endl; + + std::list<DOMElement*> globalScripts = DOMUtils::filterChildElements(XML_PREFIX(_scxml).str() + "script", _scxml, false); + for (auto globalScript : globalScripts) { + writeExecContent(stream, globalScript); + } + stream << std::endl; + + stream << " /* Enter initial configuration */" << std::endl; + bit_copy(stream, _prefix + "states[0].completion", "target_set", _states.size(), 2); + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_PRISTINE] = false;" << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Entering initial default completion\\n\");" << std::endl; + stream << "#endif" << std::endl; + + stream << " goto ESTABLISH_ENTRY_SET;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + +#if 0 + stream << "DEQUEUE_EVENT:" << std::endl; + stream << " if (ctx->flags & USCXML_CTX_SPONTANEOUS) {" << std::endl; + stream << " ctx->event = NULL;" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; + stream << " if (ctx->dequeue_internal != NULL && (ctx->event = ctx->dequeue_internal(ctx)) != NULL) {" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + + stream << "/* ---------------------------- */" << std::endl; + stream << "DEQUEUE_EVENT:" << std::endl; + stream << " if" << std::endl; + stream << " ::" << _prefix << "flags[USCXML_CTX_SPONTANEOUS] -> {" << std::endl; + stream << " " << _prefix << EVENT_NAME << " = USCXML_EVENT_SPONTANEOUS;" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Trying with a spontaneuous event\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "iQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "iQ ? " << _prefix << "_event;" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Deqeued an internal event\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> skip;" << std::endl; + stream << " fi;" << std::endl; + + +#if 0 + stream << " /* manage invocations */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " /* uninvoke */" << std::endl; + stream << " if (!BIT_HAS(i, ctx->config) && BIT_HAS(i, ctx->invocations)) {" << std::endl; + stream << " if (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; + stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 1);" << std::endl; + stream << " BIT_CLEAR(i, ctx->invocations)" << std::endl; + stream << " }" << std::endl; + stream << " /* invoke */" << std::endl; + stream << " if (BIT_HAS(i, ctx->config) && !BIT_HAS(i, ctx->invocations)) {" << std::endl; + stream << " if (USCXML_GET_STATE(i).invoke != NULL)" << std::endl; + stream << " USCXML_GET_STATE(i).invoke(ctx, &USCXML_GET_STATE(i), NULL, 0);" << std::endl; + stream << " BIT_SET_AT(i, ctx->invocations)" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << " /* manage invocations */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " /* uninvoke */" << std::endl; + stream << " if" << std::endl; + stream << " :: !" << _prefix << "config[i] && " << _prefix << "invocations[i] -> {" << 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 << " 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; + +#if 0 + stream << " if (ctx->dequeue_external != NULL && (ctx->event = ctx->dequeue_external(ctx)) != NULL) {" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + stream << " if (ctx->dequeue_external == NULL) {" << std::endl; + stream << " return USCXML_ERR_DONE;" << std::endl; + stream << " }" << std::endl; + stream << " return USCXML_ERR_IDLE;" << std::endl; + stream << std::endl; +#endif + + stream << " if" << std::endl; + stream << " :: len(" << _prefix << "eQ) != 0 -> {" << std::endl; + stream << " " << _prefix << "eQ ? " << _prefix << "_event;" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Deqeued an external event\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " goto SELECT_TRANSITIONS;" << std::endl; + stream << " }" << std::endl; +// stream << " :: else -> quit;" << std::endl; + stream << " fi;" << std::endl; + stream << std::endl; + +#if 0 + stream << "SELECT_TRANSITIONS:" << std::endl; + stream << " bit_clear_all(conflicts, nr_trans_bytes);" << std::endl; + stream << " bit_clear_all(exit_set, nr_states_bytes);" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_TRANS; i++) {" << std::endl; + stream << " /* never select history or initial transitions automatically */" << std::endl; + stream << " if unlikely(USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL))" << std::endl; + stream << " continue;" << std::endl; + stream << std::endl; + stream << " /* is the transition active? */" << std::endl; + stream << " if (BIT_HAS(USCXML_GET_TRANS(i).source, ctx->config)) {" << std::endl; + stream << " /* is it non-conflicting? */" << std::endl; + stream << " if (!BIT_HAS(i, conflicts)) {" << std::endl; + stream << " /* is it spontaneous with an event or vice versa? */" << std::endl; + stream << " if ((USCXML_GET_TRANS(i).event == NULL && ctx->event == NULL) || " << std::endl; + stream << " (USCXML_GET_TRANS(i).event != NULL && ctx->event != NULL)) {" << std::endl; + stream << " /* is it enabled? */" << std::endl; + stream << " if ((ctx->event == NULL || ctx->is_matched(ctx, &USCXML_GET_TRANS(i), ctx->event) > 0) &&" << std::endl; + stream << " (USCXML_GET_TRANS(i).condition == NULL || " << std::endl; + stream << " USCXML_GET_TRANS(i).is_enabled(ctx, &USCXML_GET_TRANS(i)) > 0)) {" << std::endl; + stream << " /* remember that we found a transition */" << std::endl; + stream << " ctx->flags |= USCXML_CTX_TRANSITION_FOUND;" << std::endl; + stream << std::endl; + + stream << " /* transitions that are pre-empted */" << std::endl; + stream << " bit_or(conflicts, USCXML_GET_TRANS(i).conflicts, nr_trans_bytes);" << std::endl; + stream << std::endl; + stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; + stream << " bit_or(target_set, USCXML_GET_TRANS(i).target, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* states that will be left */" << std::endl; + stream << " bit_or(exit_set, USCXML_GET_TRANS(i).exit_set, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " BIT_SET_AT(i, trans_set);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " bit_and(exit_set, ctx->config, nr_states_bytes);" << std::endl; + stream << std::endl; +#endif + + stream << "/* ---------------------------- */" << std::endl; + stream << "SELECT_TRANSITIONS:" << std::endl; + bit_clear_all(stream, "conflicts", _transitions.size(), 1); + bit_clear_all(stream, "trans_set", _transitions.size(), 1); + bit_clear_all(stream, "target_set", _states.size(), 1); + bit_clear_all(stream, "exit_set", _states.size(), 1); + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Establishing optimal transition set for event %d\\n\", " << _prefix << EVENT_NAME << ");" << std::endl; + stream << "#endif" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < 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 << " !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<TrieNode*> events =_analyzer.getTrie().getWordsWithPrefix(ATTR(_transitions[i], "event")); + 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; + bit_or(stream, "conflicts", _prefix + "transitions[i].conflicts", _transitions.size(), 4); + stream << std::endl; + + stream << " /* states that are directly targeted (resolve as entry-set later) */" << std::endl; + bit_or(stream, "target_set", _prefix + "transitions[i].target", _states.size(), 4); + stream << std::endl; + + stream << " /* states that will be left */" << std::endl; + bit_or(stream, "exit_set", _prefix + "transitions[i].exit_set", _states.size(), 4); + stream << std::endl; + + stream << " 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 -> break;" << 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 << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Selected Transitions: \");" << std::endl; + printBitArray(stream, "trans_set", _transitions.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Target Set: \");" << std::endl; + printBitArray(stream, "target_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + +#if 0 + stream << " if (ctx->flags & USCXML_CTX_TRANSITION_FOUND) {" << std::endl; + stream << " ctx->flags |= USCXML_CTX_SPONTANEOUS;" << std::endl; + stream << " ctx->flags &= ~USCXML_CTX_TRANSITION_FOUND;" << std::endl; + stream << " } else {" << std::endl; + stream << " ctx->flags &= ~USCXML_CTX_SPONTANEOUS;" << std::endl; + stream << " goto DEQUEUE_EVENT;" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << " if" << std::endl; + stream << " :: " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] -> {" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Found transitions\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = true;" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TRANSITION_FOUND] = false;" << std::endl; + stream << " }" << std::endl; + stream << " :: else {" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_SPONTANEOUS] = false;" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Found NO transitions\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " goto DEQUEUE_EVENT;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + +#if 0 + stream << "/* REMEMBER_HISTORY: */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||" << std::endl; + stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP) {" << std::endl; + stream << " /* a history state whose parent is about to be exited */" << std::endl; + stream << " if unlikely(BIT_HAS(USCXML_GET_STATE(i).parent, exit_set)) {" << std::endl; + stream << " bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* set those states who were enabled */" << std::endl; + stream << " bit_and(tmp_states, ctx->config, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* clear current history with completion mask */" << std::endl; + stream << " bit_and_not(ctx->history, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* set history */" << std::endl; + stream << " bit_or(ctx->history, tmp_states, nr_states_bytes);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << "/* ---------------------------- */" << std::endl; + stream << "/* REMEMBER_HISTORY: */" << std::endl; + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Save history configurations\\n\");" << std::endl; + stream << "#endif" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < 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 << " :: exit_set[" << _prefix << "states[i].parent] -> {" << std::endl; + stream << " /* a history state whose parent is about to be exited */" << std::endl; + + bit_copy(stream, _prefix + "states[i].completion", "tmp_states", _states.size(), 3); + bit_and(stream, "tmp_states", _prefix + "config", _states.size(), 3); + bit_and_not(stream, "tmp_states", _prefix + "states[i].completion", _states.size(), 3); + bit_or(stream, _prefix + "history", "tmp_states", _states.size(), 3); + 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; + +#if 0 + stream << "ESTABLISH_ENTRY_SET:" << std::endl; + stream << " /* calculate new entry set */" << std::endl; + stream << " bit_copy(entry_set, target_set, nr_states_bytes);" << std::endl; + stream << std::endl; + stream << " /* iterate for ancestors */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; + stream << " bit_or(entry_set, USCXML_GET_STATE(i).ancestors, nr_states_bytes);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << "/* ---------------------------- */" << std::endl; + stream << "ESTABLISH_ENTRY_SET:" << std::endl; + stream << " /* calculate new entry set */" << std::endl; + bit_copy(stream, "target_set", "entry_set", _states.size(), 1); + stream << std::endl; + + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + + stream << " if" << std::endl; + stream << " :: entry_set[i] -> {" << std::endl; + stream << " /* ancestor completion */" << std::endl; + bit_or(stream, "entry_set", _prefix + "states[i].ancestors", _states.size(), 3); + + 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 << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Entry Set (after ancestor completion)\");" << std::endl; + printBitArray(stream, "entry_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + +#if 0 + stream << " /* iterate for descendants */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " if (BIT_HAS(i, entry_set)) {" << std::endl; + stream << " switch (USCXML_STATE_MASK(USCXML_GET_STATE(i).type)) {" << std::endl; +#endif + + stream << " /* iterate for descendants */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: entry_set[i] -> {" << std::endl; + stream << " if" << std::endl; + +#if 0 + stream << " case USCXML_STATE_PARALLEL: {" << std::endl; + stream << " bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; +#endif + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_PARALLEL] -> {" << std::endl; + bit_or(stream, "entry_set", _prefix + "states[i].completion", _states.size(), 4); + stream << " }" << std::endl; + + +#if 0 + stream << " case USCXML_STATE_HISTORY_SHALLOW:" << std::endl; + stream << " case USCXML_STATE_HISTORY_DEEP: {" << std::endl; + stream << " if (!bit_has_and(USCXML_GET_STATE(i).completion, ctx->history, nr_states_bytes) &&" << std::endl; + stream << " !BIT_HAS(USCXML_GET_STATE(i).parent, ctx->config)) {" << std::endl; + stream << " /* nothing set for history, look for a default transition */" << std::endl; + stream << " for (j = 0; j < USCXML_NUMBER_TRANS; j++) {" << std::endl; + stream << " if unlikely(ctx->machine->transitions[j].source == i) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl; + stream << " if(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP &&" << std::endl; + stream << " !bit_has_and(ctx->machine->transitions[j].target, USCXML_GET_STATE(i).children, nr_states_bytes)) {" << std::endl; + stream << " for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {" << std::endl; + stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " BIT_SET_AT(j, trans_set);" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + stream << " /* Note: SCXML mandates every history to have a transition! */" << std::endl; + stream << " }" << std::endl; + stream << " } else {" << std::endl; + stream << " bit_copy(tmp_states, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; + stream << " bit_and(tmp_states, ctx->history, nr_states_bytes);" << std::endl; + stream << " bit_or(entry_set, tmp_states, nr_states_bytes);" << std::endl; + stream << " if (USCXML_GET_STATE(i).type == (USCXML_STATE_HAS_HISTORY | USCXML_STATE_HISTORY_DEEP)) {" << std::endl; + stream << " /* a deep history state with nested histories -> more completion */" << std::endl; + stream << " for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {" << std::endl; + stream << " if (BIT_HAS(j, USCXML_GET_STATE(i).completion) &&" << std::endl; + stream << " BIT_HAS(j, entry_set) &&" << std::endl; + stream << " (ctx->machine->states[j].type & USCXML_STATE_HAS_HISTORY)) {" << std::endl; + stream << " for (k = j + 1; k < USCXML_NUMBER_STATES; k++) {" << std::endl; + stream << " /* add nested history to entry_set */" << std::endl; + stream << " if ((USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_DEEP ||" << std::endl; + stream << " USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_HISTORY_SHALLOW) &&" << std::endl; + stream << " BIT_HAS(k, ctx->machine->states[j].children)) {" << std::endl; + stream << " /* a nested history state */" << std::endl; + stream << " BIT_SET_AT(k, entry_set);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; +#endif + + + 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 << " :: !"; + 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; + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + + bit_or(stream, "entry_set", _prefix + "transitions[j].target", _states.size(), 8); + stream << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[i].type[USCXML_STATE_HISTORY_DEEP] &&" << std::endl; + stream << " !"; + 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 < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + bit_or(stream, "entry_set", _prefix + "states[k].ancestors", _states.size(), 11); + stream << " break;" << 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 << " trans_set[j] = true;" << std::endl; + stream << " break;" << 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 << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + bit_copy(stream, "tmp_states", _prefix + "states[i].completion", _states.size(), 5); + bit_and(stream, "tmp_states", _prefix + "history", _states.size(), 5); + bit_or(stream, "entry_set", "tmp_states", _states.size(), 5); + 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; + stream << " j = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << _prefix << "states[i].completion[j] &&" << std::endl; + stream << " 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 < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " /* add nested history to entry_set */" << std::endl; + stream << " k = k + 1;" << 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 << " entry_set[k] = true;" << 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 -> 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 0 + stream << " case USCXML_STATE_INITIAL: {" << std::endl; + stream << " for (j = 0; j < USCXML_NUMBER_TRANS; j++) {" << std::endl; + stream << " if (ctx->machine->transitions[j].source == i) {" << std::endl; + stream << " BIT_SET_AT(j, trans_set);" << std::endl; + stream << " BIT_CLEAR(i, entry_set);" << std::endl; + stream << " bit_or(entry_set, ctx->machine->transitions[j].target, nr_states_bytes);" << std::endl; + stream << " for (k = i + 1; k < USCXML_NUMBER_STATES; k++) {" << std::endl; + stream << " if (BIT_HAS(k, ctx->machine->transitions[j].target)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; +#endif + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_INITIAL] -> {" << std::endl; + stream << " j = 0" << std::endl; + stream << " do" << std::endl; + stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].source == i -> {" << std::endl; + stream << " trans_set[j] = true;" << std::endl; + stream << " entry_set[i] = false;" << std::endl; + + bit_or(stream, "entry_set", _prefix + "transitions[j].target", _states.size(), 6); + stream << std::endl; + + stream << " k = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: k < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "transitions[j].target[k] -> {" << std::endl; + + bit_or(stream, "entry_set", _prefix + "states[k].ancestors", _states.size(), 8); + 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 -> break;" << 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; + + +#if 0 + stream << " case USCXML_STATE_COMPOUND: { /* we need to check whether one child is already in entry_set */" << std::endl; + stream << " if (!bit_has_and(entry_set, USCXML_GET_STATE(i).children, nr_states_bytes) &&" << std::endl; + stream << " (!bit_has_and(ctx->config, USCXML_GET_STATE(i).children, nr_states_bytes) ||" << std::endl; + stream << " bit_has_and(exit_set, USCXML_GET_STATE(i).children, nr_states_bytes)))" << std::endl; + stream << " {" << std::endl; + stream << " bit_or(entry_set, USCXML_GET_STATE(i).completion, nr_states_bytes);" << std::endl; + stream << " if (!bit_has_and(USCXML_GET_STATE(i).completion, USCXML_GET_STATE(i).children, nr_states_bytes)) {" << std::endl; + stream << " /* deep completion */" << std::endl; + stream << " for (j = i + 1; j < USCXML_NUMBER_STATES; j++) {" << std::endl; + stream << " if (BIT_HAS(j, USCXML_GET_STATE(i).completion)) {" << std::endl; + stream << " bit_or(entry_set, ctx->machine->states[j].ancestors, nr_states_bytes);" << std::endl; + stream << " break; /* completion of compound is single state */" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " break;" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_COMPOUND] -> {" << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Descendant completion for compound state %d\\n\", i);" << std::endl; + stream << "#endif" << std::endl; + + stream << " /* we need to check whether one child is already in entry_set */" << std::endl; + stream << " if" << std::endl; + stream << " :: (" << std::endl; + stream << " !"; + bit_has_and(stream, "entry_set", _prefix + "states[i].children", _states.size(), 5); + stream << " && " << std::endl; + stream << " (!"; + bit_has_and(stream, _prefix + "config", _prefix + "states[i].children", _states.size(), 5); + stream << " || " << std::endl; + bit_has_and(stream, "exit_set", _prefix + "states[i].children", _states.size(), 5); + stream << ")) "<< std::endl; + stream << " -> {" << std::endl; + + bit_or(stream, "entry_set", _prefix + "states[i].completion", _states.size(), 5); + + stream << " if" << std::endl; + stream << " :: ("; + bit_has_and(stream, _prefix + "states[i].completion", _prefix + "states[i].children", _states.size(), 5); + stream << std::endl; + stream << " ) -> {" << std::endl; + stream << " /* deep completion */" << std::endl; + stream << " j = i + 1;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < USCXML_NUMBER_STATES - 1 -> {" << std::endl; + stream << " j = j + 1;" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].completion[j] -> {" << std::endl; + + bit_or(stream, "entry_set", _prefix + "states[j].ancestors", _states.size(), 9); + 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; + +#if 0 + stream << "/* EXIT_STATES: */" << std::endl; + stream << " i = USCXML_NUMBER_STATES;" << std::endl; + stream << " while(i-- > 0) {" << std::endl; + stream << " if (BIT_HAS(i, exit_set) && BIT_HAS(i, ctx->config)) {" << std::endl; + stream << " /* call all on exit handlers */" << std::endl; + stream << " if (USCXML_GET_STATE(i).on_exit != NULL) {" << std::endl; + stream << " if unlikely((err = USCXML_GET_STATE(i).on_exit(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; + stream << " return err;" << std::endl; + stream << " }" << std::endl; + stream << " BIT_CLEAR(i, ctx->config);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Entry Set (after descendant completion)\");" << std::endl; + printBitArray(stream, "entry_set", _states.size()); + stream << "printf(\"\\n\");" << std::endl; + stream << "#endif" << std::endl; + + stream << "/* ---------------------------- */" << std::endl; + stream << "/* EXIT_STATES: */" << std::endl; + stream << " i = 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 << " :: exit_set[i] && " << _prefix << "config[i] -> {" << 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; + for (auto onentry : onentries) + writeExecContent(stream, onentry, 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 << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Exited States\\n\");" << std::endl; + stream << "#endif" << std::endl; + +#if 0 + stream << "/* TAKE_TRANSITIONS: */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_TRANS; i++) {" << std::endl; + stream << " if (BIT_HAS(i, trans_set) && (USCXML_GET_TRANS(i).type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) == 0) {" << std::endl; + stream << " /* call executable content in transition */" << std::endl; + stream << " if (USCXML_GET_TRANS(i).on_transition != NULL) {" << std::endl; + stream << " if unlikely((err = USCXML_GET_TRANS(i).on_transition(ctx," << std::endl; + stream << " &ctx->machine->states[USCXML_GET_TRANS(i).source]," << std::endl; + stream << " ctx->event)) != USCXML_ERR_OK)" << std::endl; + stream << " return err;" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; +#endif + + stream << "/* ---------------------------- */" << std::endl; + stream << "/* TAKE_TRANSITIONS: */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: 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; + stream << " if" << std::endl; + for (auto i = 0; i < _transitions.size(); i++) { + stream << " :: i == " << toStr(i) << " -> {" << std::endl; + 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 << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Took Transitions\\n\");" << std::endl; + stream << "#endif" << std::endl; + +#if 0 + stream << "/* ENTER_STATES: */" << std::endl; + stream << " for (i = 0; i < USCXML_NUMBER_STATES; i++) {" << std::endl; + stream << " if (BIT_HAS(i, entry_set) && !BIT_HAS(i, ctx->config)) {" << std::endl; + stream << " /* these are no proper states */" << std::endl; + stream << " if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_DEEP ||" << std::endl; + stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_HISTORY_SHALLOW ||" << std::endl; + stream << " USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_INITIAL)" << std::endl; + stream << " continue;" << std::endl; + stream << std::endl; +#endif + + stream << "/* ---------------------------- */" << std::endl; + stream << "/* ENTER_STATES: */" << std::endl; + stream << " i = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: i < USCXML_NUMBER_STATES -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (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; + +#if 0 + stream << " BIT_SET_AT(i, ctx->config);" << std::endl; + stream << std::endl; +#endif + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Entering State %d\\n\", i);" << std::endl; + stream << "#endif" << std::endl; + + stream << " " << _prefix << "config[i] = true;" << std::endl; + stream << std::endl; + + +#if 0 + stream << " /* initialize data */" << std::endl; + stream << " if (!BIT_HAS(i, ctx->initialized_data)) {" << std::endl; + stream << " if unlikely(USCXML_GET_STATE(i).data != NULL && ctx->exec_content_init != NULL) {" << std::endl; + stream << " ctx->exec_content_init(ctx, USCXML_GET_STATE(i).data);" << std::endl; + stream << " }" << std::endl; + stream << " BIT_SET_AT(i, ctx->initialized_data);" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + +#endif + + 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; + +#if 0 + stream << " if (USCXML_GET_STATE(i).on_entry != NULL) {" << std::endl; + stream << " if unlikely((err = USCXML_GET_STATE(i).on_entry(ctx, &USCXML_GET_STATE(i), ctx->event)) != USCXML_ERR_OK)" << std::endl; + stream << " return err;" << std::endl; + stream << " }" << 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; + for (auto onentry : onentries) + writeExecContent(stream, onentry, 5); + stream << " }" << std::endl; + } + } + stream << " :: else ->skip;" << std::endl; + stream << " fi" << std::endl; + stream << std::endl; + +#if 0 + stream << " /* take history and initial transitions */" << std::endl; + stream << " for (j = 0; j < USCXML_NUMBER_TRANS; j++) {" << std::endl; + stream << " if unlikely(BIT_HAS(j, trans_set) &&" << std::endl; + stream << " (ctx->machine->transitions[j].type & (USCXML_TRANS_HISTORY | USCXML_TRANS_INITIAL)) &&" << std::endl; + stream << " ctx->machine->states[ctx->machine->transitions[j].source].parent == i) {" << std::endl; + stream << " /* call executable content in transition */" << std::endl; + stream << " if (ctx->machine->transitions[j].on_transition != NULL) {" << std::endl; + stream << " if unlikely((err = ctx->machine->transitions[j].on_transition(ctx," << std::endl; + stream << " &USCXML_GET_STATE(i)," << std::endl; + stream << " ctx->event)) != USCXML_ERR_OK)" << std::endl; + stream << " return err;" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + +#endif + + stream << " /* take history and initial transitions */" << std::endl; + stream << " j = 0;" << std::endl; + stream << " do" << std::endl; + stream << " :: j < USCXML_NUMBER_TRANS -> {" << std::endl; + stream << " if" << std::endl; + stream << " :: (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; + 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; + + +#if 0 + stream << " /* handle final states */" << std::endl; + stream << " if unlikely(USCXML_STATE_MASK(USCXML_GET_STATE(i).type) == USCXML_STATE_FINAL) {" << std::endl; +#endif + + stream << " /* handle final states */" << std::endl; + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[i].type[USCXML_STATE_FINAL] -> {" << std::endl; + + +#if 0 + stream << " if unlikely(USCXML_GET_STATE(i).ancestors[0] == 0x01) {" << std::endl; + stream << " ctx->flags |= USCXML_CTX_TOP_LEVEL_FINAL;" << std::endl; + stream << " } else {" << std::endl; + stream << " /* raise done event */" << std::endl; + stream << " const uscxml_elem_donedata* donedata = &ctx->machine->donedata[0];" << std::endl; + stream << " while(USCXML_ELEM_DONEDATA_IS_SET(donedata)) {" << std::endl; + stream << " if unlikely(donedata->source == i)" << std::endl; + stream << " break;" << std::endl; + stream << " donedata++;" << std::endl; + stream << " }" << std::endl; + stream << " ctx->raise_done_event(ctx, &ctx->machine->states[USCXML_GET_STATE(i).parent], (USCXML_ELEM_DONEDATA_IS_SET(donedata) ? donedata : NULL));" << std::endl; + stream << " }" << std::endl; +#endif + + stream << " if" << std::endl; + stream << " :: " << _prefix << "states[" << _prefix << "states[i].parent].children[1] -> {" << std::endl; + stream << " " << _prefix << "flags[USCXML_CTX_TOP_LEVEL_FINAL] = true;" << std::endl; + stream << " }" << std::endl; + stream << " :: else -> {" << std::endl; + stream << " /* TODO: raise done event */" << std::endl; + stream << " skip;" << std::endl; + stream << " }" << std::endl; + stream << " fi" << std::endl; + + +#if 0 + stream << 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 << " for (j = 0; j < USCXML_NUMBER_STATES; j++) {" << std::endl; + stream << " if unlikely(USCXML_STATE_MASK(ctx->machine->states[j].type) == USCXML_STATE_PARALLEL &&" << std::endl; + stream << " BIT_HAS(j, USCXML_GET_STATE(i).ancestors)) {" << std::endl; + stream << " bit_clear_all(tmp_states, nr_states_bytes);" << std::endl; + stream << " for (k = 0; k < USCXML_NUMBER_STATES; k++) {" << std::endl; + stream << " if unlikely(BIT_HAS(j, ctx->machine->states[k].ancestors) && BIT_HAS(k, ctx->config)) {" << std::endl; + stream << " if (USCXML_STATE_MASK(ctx->machine->states[k].type) == USCXML_STATE_FINAL) {" << std::endl; + stream << " bit_and_not(tmp_states, ctx->machine->states[k].ancestors, nr_states_bytes);" << std::endl; + stream << " } else {" << std::endl; + stream << " BIT_SET_AT(k, tmp_states);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " if unlikely(!bit_has_any(tmp_states, nr_states_bytes)) {" << std::endl; + stream << " ctx->raise_done_event(ctx, &ctx->machine->states[j], NULL);" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << " }" << std::endl; + stream << std::endl; + + stream << " return USCXML_ERR_OK;" << std::endl; + stream << "}" << std::endl; + stream << std::endl; + stream << std::endl; +#endif + + stream << " /** TODO:" << 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 << " }" << 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 << std::endl; + + stream << "#if TRACE_EXECUTION" << std::endl; + stream << "printf(\"Done\\n\");" << std::endl; + stream << "#endif" << std::endl; + + stream << "}" << std::endl; + stream << ":: else -> break;" << std::endl; + stream << "od" << std::endl; + + + stream << "} }" << std::endl; + stream << std::endl; + +} + +#if 0 + +void ChartToPromela::writeProgram(std::ostream& stream) { + + _traceTransitions = envVarIsTrue("USCXML_PROMELA_TRANSITION_TRACE"); + _writeTransitionPrintfs = envVarIsTrue("USCXML_PROMELA_TRANSITION_DEBUG"); + + if (!HAS_ATTR(_scxml, "datamodel") || ATTR(_scxml, "datamodel") != "promela") { + LOG(ERROR) << "Can only convert SCXML documents with \"promela\" datamodel"; + return; + } + + if (HAS_ATTR(_scxml, "binding") && ATTR(_scxml, "binding") != "early") { + LOG(ERROR) << "Can only convert for early data bindings"; + return; + } + + // std::cerr << _scxml << std::endl; + + stream << "/* " << (std::string)_baseURL << " */" << std::endl; + stream << std::endl; + + initNodes(); + + for (std::map<Arabica::DOM::Node<std::string>, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { + if (nestedIter->second->_start == NULL) { + nestedIter->second->interpret(); + } + nestedIter->second->initNodes(); + } + + writeEvents(stream); + stream << std::endl; + writeStates(stream); + stream << std::endl; + writeStrings(stream); + stream << std::endl; + if (_analyzer->usesInPredicate()) { + writeStateMap(stream); + stream << std::endl; + } + if (_historyMembers.size() > 0) { + writeHistoryArrays(stream); + stream << std::endl; + } + writeTypeDefs(stream); + stream << std::endl; + writeDeclarations(stream); + stream << std::endl; + + for (std::map<Arabica::DOM::Node<std::string>, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { + nestedIter->second->writeDeclarations(stream); + stream << std::endl; + } + + stream << std::endl << "/* global inline functions */" << std::endl; + + if (_analyzer->usesComplexEventStruct()) { + stream << "hidden _event_t tmpE;" << std::endl; + } else { + stream << "hidden int tmpE;" << std::endl; + } + stream << "hidden int tmpIndex;" << std::endl; + + +#if NEW_DELAY_RESHUFFLE + if (_analyzer->usesEventField("delay")) { + writeInsertWithDelay(stream); + stream << std::endl; + } +#endif + + if (_analyzer->usesEventField("delay") && _machines.size() > 0) { + writeDetermineShortestDelay(stream); + stream << std::endl; + writeAdvanceTime(stream); + stream << std::endl; + writeRescheduleProcess(stream); + stream << std::endl; + writeScheduleMachines(stream); + stream << std::endl; + } + + { + NodeSet<std::string> cancels = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "cancel", _scxml, true); + if (cancels.size() > 0) { + writeCancelEvents(stream); + stream << std::endl; + } + } + { + NodeSet<std::string> invokes = DOMUtils::filterChildElements(_nsInfo.xmlNSPrefix + "invoke", _scxml, true); + if (invokes.size() > 0 && _analyzer->usesEventField("delay")) { + writeRemovePendingEventsFromInvoker(stream); + stream << std::endl; + } + + } + stream << std::endl; + writeEventSources(stream); + stream << std::endl; + writeFSM(stream); + stream << std::endl; + writeMain(stream); + stream << std::endl; + + for (std::map<Arabica::DOM::Node<std::string>, ChartToPromela*>::iterator nestedIter = _machines.begin(); nestedIter != _machines.end(); nestedIter++) { + nestedIter->second->writeFSM(stream); + stream << std::endl; + } + + // write ltl expression for success + std::stringstream acceptingStates; + std::string seperator; + + for (std::map<std::string, GlobalState*>::iterator stateIter = _activeConf.begin(); stateIter != _activeConf.end(); stateIter++) { + FlatStateIdentifier flatId(stateIter->first); + if (std::find(flatId.getActive().begin(), flatId.getActive().end(), "pass") != flatId.getActive().end()) { + acceptingStates << seperator << _prefix << "s == s" << stateIter->second->activeIndex; + seperator = " || "; + } + } + if (acceptingStates.str().size() > 0) { + stream << "ltl { eventually (" << acceptingStates.str() << ") }" << std::endl; + } +} +#endif + +void ChartToPromela::writeIfBlock(std::ostream& stream, std::list<DOMElement*>& condChain, size_t indent) { + if (condChain.size() == 0) + return; + + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + bool noNext = condChain.size() == 1; + bool nextIsElse = false; + + DOMElement* ifNode = condChain.front(); + condChain.pop_front(); + + if (condChain.size() > 0) { + if (TAGNAME_CAST(condChain.front()) == "else") { + nextIsElse = true; + } + } + + stream << padding << "if" << std::endl; + // we need to nest the elseifs to resolve promela if semantics + stream << padding << ":: (" << ADAPT_SRC(ATTR(ifNode, "cond")) << ") -> {" << std::endl; + + DOMNode* child; + if (TAGNAME(ifNode) == "if") { + child = ifNode->getFirstChild(); + } else { + child = ifNode->getNextSibling(); + } + while(child) { + if (child->getNodeType() == DOMNode::ELEMENT_NODE) { + DOMElement* childElem = static_cast<DOMElement*>(child); + if (TAGNAME(childElem) == "elseif" || TAGNAME_CAST(childElem) == "else") + break; + writeExecContent(stream, childElem, indent + 1); + } + child = child->getNextSibling(); + } + stream << padding << "}" << std::endl; + stream << padding << ":: else -> "; + + if (nextIsElse) { + child = condChain.front()->getNextSibling(); + stream << "{" << std::endl; + while(child) { + if (child->getNodeType() == DOMNode::ELEMENT_NODE) { + writeExecContent(stream, child, indent + 1); + } + child = child->getNextSibling(); + } + stream << padding << "}" << std::endl; + + } else if (noNext) { + stream << "skip;" << std::endl; + } else { + stream << "{" << std::endl; + writeIfBlock(stream, condChain, indent + 1); + stream << padding << "}" << std::endl; + } + + stream << padding << "fi;" << std::endl; + +} + +std::string ChartToPromela::beautifyIndentation(const std::string& code, size_t indent) { + + std::string padding; + for (size_t i = 0; i < indent; i++) { + padding += " "; + } + + // remove topmost indentation from every line and reindent + std::stringstream beautifiedSS; + + std::string initialIndent; + bool gotIndent = false; + bool isFirstLine = true; + std::stringstream ssLine(code); + std::string line; + + while(std::getline(ssLine, line)) { + size_t firstChar = line.find_first_not_of(" \t\r\n"); + if (firstChar != std::string::npos) { + if (!gotIndent) { + initialIndent = line.substr(0, firstChar); + gotIndent = true; + } + beautifiedSS << (isFirstLine ? "" : "\n") << padding << boost::replace_first_copy(line, initialIndent, ""); + isFirstLine = false; + } + } + + return beautifiedSS.str(); +} + +std::string ChartToPromela::dataToAssignments(const std::string& prefix, const Data& data) { + std::stringstream retVal; + if (data.atom.size() > 0) { + if (data.type == Data::VERBATIM) { + retVal << prefix << " = " << _analyzer.macroForLiteral(data.atom) << ";" << std::endl; + } else { + retVal << prefix << " = " << data.atom << ";" << std::endl; + } + } else if (data.compound.size() > 0) { + for (std::map<std::string, Data>::const_iterator cIter = data.compound.begin(); cIter != data.compound.end(); cIter++) { + retVal << dataToAssignments(prefix + "." + cIter->first, cIter->second); + } + } else if (data.array.size() > 0) { + size_t index = 0; + for(std::list<Data>::const_iterator aIter = data.array.begin(); aIter != data.array.end(); aIter++) { + retVal << dataToAssignments(prefix + "[" + toStr(index) + "]", *aIter); + index++; + } + } + return retVal.str(); +} + +std::string ChartToPromela::sanitizeCode(const std::string& code) { + std::string replaced = code; + boost::replace_all(replaced, "\"", "'"); + boost::replace_all(replaced, "_sessionid", "_SESSIONID"); + boost::replace_all(replaced, "_name", "_NAME"); + return replaced; +} + +std::string ChartToPromela::declForRange(const std::string& identifier, long minValue, long maxValue, bool nativeOnly) { + // return "int " + identifier; // just for testing + + // we know nothing about this type + if (minValue == 0 && maxValue == 0) + return "int " + identifier; + + if (minValue < 0) { + // only short or int for negatives + if (minValue < -32769 || maxValue > 32767) + return "int " + identifier; + return "short " + identifier; + } + + // type is definitely positive + if (nativeOnly) { + if (maxValue > 32767) + return "int " + identifier; + if (maxValue > 255) + return "short " + identifier; + if (maxValue > 1) + return "byte " + identifier; + return "bool " + identifier; + } else { + return "unsigned " + identifier + " : " + toStr(BIT_WIDTH(maxValue)); + } +} + +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, invokerIdentifier) {" << std::endl; + for (auto machine : *_machinesAll) { + for (auto queue : queues) { + stream << " cancelSendIdOnQueue(sendIdentifier, " << machine.second->_prefix << queue << ", invokerIdentifier);" << std::endl; + } + } + stream << "}" << std::endl; + stream << std::endl; + + + stream << "inline cancelSendIdOnQueue(sendIdentifier, queue, invokerIdentifier) {" << 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.invokeid != invokerIdentifier || tmpE.sendid != sendIdentifier || 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; +} + + +} diff --git a/src/uscxml/transform/ChartToPromela.h b/src/uscxml/transform/ChartToPromela.h new file mode 100644 index 0000000..cfba760 --- /dev/null +++ b/src/uscxml/transform/ChartToPromela.h @@ -0,0 +1,130 @@ +/** + * @file + * @author 2012-2014 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef CHARTTOPROMELA_H_RP48RFDJ +#define CHARTTOPROMELA_H_RP48RFDJ + +#include "Transformer.h" +#include "ChartToC.h" +#include "uscxml/util/DOM.h" + +#include "promela/PromelaInlines.h" +#include "promela/PromelaCodeAnalyzer.h" + +#include <ostream> + +namespace uscxml { + +class USCXML_API ChartToPromela : public ChartToC { +public: + virtual ~ChartToPromela(); + static Transformer transform(const Interpreter& other); + + void writeTo(std::ostream& stream); + +protected: + ChartToPromela(const Interpreter& other) : ChartToC(other) { + _prefix = "U" + _md5.substr(0, 8) + "_"; + } + + void writeTransitions(std::ostream& stream); + void writeStates(std::ostream& stream); + void writeTypeDefs(std::ostream& stream); + void writeTypes(std::ostream& stream); + void writeMacros(std::ostream& stream); + void writeHelpers(std::ostream& stream); + void writeFSM(std::ostream& stream); + void writeExecContent(std::ostream& stream, const XERCESC_NS::DOMNode* node, size_t indent = 0); + void writeStrings(std::ostream& stream); + + void writeCancelEvents(std::ostream& stream, int indent = 0); + + void prepare(); + + void bit_clear_all(std::ostream& stream, + const std::string& identifier, + size_t length, + size_t indent = 0); + + void bit_copy(std::ostream& stream, + const std::string& from, + const std::string& to, + size_t length, + size_t indent = 0); + + void bit_or(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent = 0); + + void bit_and(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent = 0); + + void bit_and_not(std::ostream& stream, + const std::string& to, + const std::string& mask, + size_t length, + size_t indent = 0); + + void bit_has_and(std::ostream& stream, + const std::string& a, + const std::string& b, + size_t length, + size_t indent = 0); + + void printBitArray(std::ostream& stream, + const std::string& array, + size_t length, + size_t indent = 0); + + PromelaCodeAnalyzer _analyzer; + + ChartToPromela* _parentTopMost; + ChartToPromela* _parent; + std::string _invokerid; + + size_t _internalQueueLength = 7; + size_t _externalQueueLength = 7; + bool _allowEventInterleaving = false; + + std::map<std::string, XERCESC_NS::DOMNode* > _machinesPerId; + std::map<std::string, XERCESC_NS::DOMNode* >* _machinesAllPerId = NULL; + std::map<XERCESC_NS::DOMNode*, ChartToPromela*> _machines; + std::map<XERCESC_NS::DOMNode*, ChartToPromela*>* _machinesAll = NULL; + + std::set<std::string> _dataModelVars; + 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); + + std::string dataToAssignments(const std::string& prefix, const Data& data); + std::string sanitizeCode(const std::string& code); + std::string declForRange(const std::string& identifier, long minValue, long maxValue, bool nativeOnly = false); + + friend class PromelaCodeAnalyzer; +}; + +} + +#endif /* end of include guard: CHARTTOPROMELA_H_RP48RFDJ */ diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp index 37fa03c..13e8120 100644 --- a/src/uscxml/transform/ChartToVHDL.cpp +++ b/src/uscxml/transform/ChartToVHDL.cpp @@ -40,9 +40,9 @@ namespace uscxml { using namespace XERCESC_NS; Transformer ChartToVHDL::transform(const Interpreter& other) { - ChartToVHDL* c2c = new ChartToVHDL(other); + ChartToVHDL* c2c = new ChartToVHDL(other); - return std::shared_ptr<TransformerImpl>(c2c); + return std::shared_ptr<TransformerImpl>(c2c); } ChartToVHDL::ChartToVHDL(const Interpreter& other) : ChartToC(other), _eventTrie(".") { @@ -52,1383 +52,1383 @@ 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!"); - } - } + // 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!"); + } + } } std::string ChartToVHDL::eventNameEscape(const std::string& eventName) { - std::string escaped = escape(eventName); - boost::replace_all(escaped, ".", "_"); - return escaped; + std::string escaped = escape(eventName); + boost::replace_all(escaped, ".", "_"); + return escaped; } 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")) { - // TODO: tokenize! - if (ATTR_CAST(withEvent, "event") != "*") - _eventTrie.addWord(ATTR_CAST(withEvent, "event")); - } - } - - _execContent = DOMUtils::inDocumentOrder({ - XML_PREFIX(_scxml).str() + "raise", - XML_PREFIX(_scxml).str() + "send" - }, _scxml); + // 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")) { + // TODO: tokenize! + if (ATTR_CAST(withEvent, "event") != "*") + _eventTrie.addWord(ATTR_CAST(withEvent, "event")); + } + } + + _execContent = DOMUtils::inDocumentOrder({ + XML_PREFIX(_scxml).str() + "raise", + XML_PREFIX(_scxml).str() + "send" + }, _scxml); } void ChartToVHDL::writeTo(std::ostream& stream) { - // same preparations as the C transformation - prepare(); + // same preparations as the C transformation + prepare(); - // checkDocument(); - findEvents(); + // 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=foo.vcd" << std::endl; - stream << std::endl; + 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=foo.vcd" << std::endl; + stream << std::endl; - writeTypes(stream); - writeFiFo(stream); - writeEventController(stream); - writeMicroStepper(stream); - writeTestbench(stream); + 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_" << eventNameEscape((*eventIter)->value); - seperator = ", "; - } - stream << " );" << std::endl; - - stream << "end machine" << _md5 << ";" << std::endl; - stream << std::endl; - stream << "-- END needed global types" << std::endl; + 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_" << eventNameEscape((*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; + // 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 bhv 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; - - stream << "end architecture;" << std::endl; - stream << "-- END TESTBENCH" << std::endl; + 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 bhv 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; + + 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> + std::string index, std::list< DOMElement* > commandSequence) { + // index should be [entry, transition, exit]_<index of state/transition>_<optional index for block> - // write clock blocks + // 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 << "ms_enable_manager : process (clk, rst) " << std::endl; - // stream << "begin" << std::endl; - // stream << " if rst = '1' then" << std::endl; - // stream << " micro_stepper_en <= '1';" << std::endl; - // stream << " elsif rising_edge(clk) then" << std::endl; - // stream << " " << 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 << " end if;" << std::endl; - // stream << "end process;" << std::endl; - stream << std::endl; - - // write enable management - // stream << "-- write enable for FIFO buffer" << std::endl; - // stream << "event_we <= not rst and ('0'"; - // for (int i = 0; i < _execContent.size(); i++) { - // stream << std::endl << " or start_" << toStr(i) << "_sig"; - // } - // 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; - - //TODO if raise - if (TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "raise" || - TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "send") { - stream << seperator << "if start_" << toStr(i) << "_sig = '1' then" - << std::endl; - //TODO use escape - stream << " event_bus <= hwe_" << 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; - for (auto exContentElem : _execContent) { - - //TODO if raise - if (TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "raise") { - 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 (i != 0) { // if not first element - 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++) { - // 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; + // 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 << "ms_enable_manager : process (clk, rst) " << std::endl; + // stream << "begin" << std::endl; + // stream << " if rst = '1' then" << std::endl; + // stream << " micro_stepper_en <= '1';" << std::endl; + // stream << " elsif rising_edge(clk) then" << std::endl; + // stream << " " << 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 << " end if;" << std::endl; + // stream << "end process;" << std::endl; + stream << std::endl; + + // write enable management + // stream << "-- write enable for FIFO buffer" << std::endl; + // stream << "event_we <= not rst and ('0'"; + // for (int i = 0; i < _execContent.size(); i++) { + // stream << std::endl << " or start_" << toStr(i) << "_sig"; + // } + // 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; + + //TODO if raise + if (TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "raise" || + TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "send") { + stream << seperator << "if start_" << toStr(i) << "_sig = '1' then" + << std::endl; + //TODO use escape + stream << " event_bus <= hwe_" << 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; + for (auto exContentElem : _execContent) { + + //TODO if raise + if (TAGNAME(exContentElem) == XML_PREFIX(_scxml).str() + "raise") { + 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 (i != 0) { // if not first element + 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++) { + // 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; } 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 ""; + 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; + // 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; + // 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_2 : std_logic;" << std::endl; - // stream << "signal rst_1 : 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) { - - 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_up_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); - signalDecls.push_back("signal default_completion_" + 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_" << eventNameEscape((*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; + // 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_2 : std_logic;" << std::endl; + // stream << "signal rst_1 : 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) { + + 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_up_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal in_complete_entry_set_" + ATTR(state, "documentOrder") + "_sig : std_logic;"); + signalDecls.push_back("signal default_completion_" + 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_" << eventNameEscape((*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; + // 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; + // 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 << "rst_proc: process(clk, rst_i)" << std::endl; - // stream << "begin" << std::endl; - // stream << " if rst_i = '1' then" << std::endl; - // stream << " rst_2 <= '1';" << std::endl; - // stream << " rst_1 <= '1';" << std::endl; - // stream << " rst <= '1';" << std::endl; - // stream << " elsif (rising_edge(clk)) then" << std::endl; - // stream << " rst_2 <= rst_i;" << std::endl; - // stream << " rst_1 <= rst_i;" << std::endl; - // stream << " rst <= rst_1;" << std::endl; - // stream << " end if;" << std::endl; - // stream << "end process;" << std::endl; - stream << std::endl; + stream << "-- reset handler" << std::endl; + stream << "rst <= rst_i;" << std::endl; + // stream << "rst_proc: process(clk, rst_i)" << std::endl; + // stream << "begin" << std::endl; + // stream << " if rst_i = '1' then" << std::endl; + // stream << " rst_2 <= '1';" << std::endl; + // stream << " rst_1 <= '1';" << std::endl; + // stream << " rst <= '1';" << std::endl; + // stream << " elsif (rising_edge(clk)) then" << std::endl; + // stream << " rst_2 <= rst_i;" << std::endl; + // stream << " rst_1 <= rst_i;" << std::endl; + // stream << " rst <= rst_1;" << std::endl; + // stream << " end if;" << std::endl; + // stream << "end process;" << 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; - //TODO 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; + // 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; + //TODO 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_" << eventNameEscape((*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_" - << eventNameEscape((*eventIter)->value) << " =>" << std::endl; - for (std::list<TrieNode*>::iterator eventIter2 = eventNames.begin(); eventIter2 != eventNames.end(); eventIter2++) { - stream << " event_" << eventNameEscape((*eventIter2)->value); - if (eventNameEscape((*eventIter)->value) == eventNameEscape((*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_" << eventNameEscape((*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_" << eventNameEscape((*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; + // 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_" << eventNameEscape((*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_" + << eventNameEscape((*eventIter)->value) << " =>" << std::endl; + for (std::list<TrieNode*>::iterator eventIter2 = eventNames.begin(); eventIter2 != eventNames.end(); eventIter2++) { + stream << " event_" << eventNameEscape((*eventIter2)->value); + if (eventNameEscape((*eventIter)->value) == eventNameEscape((*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_" << eventNameEscape((*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_" << eventNameEscape((*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; + stream << "-- active configuration" << std::endl; - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { // DOMElement* state = *stateIter; - // TÖDO: is there a case where complete entry set reflects not the next state ? - VBranch* tree = (VASSIGN, - VLINE("state_next_" + toStr(i) + "_sig"), - (VOR, - VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), - (VAND, (VNOT, VLINE("in_exit_set_" + toStr(i) + "_sig")), VLINE("state_active_" + toStr(i) + "_sig")) - ) ); - - tree->print(stream); - stream << ";" << std::endl; - - } + // TÖDO: is there a case where complete entry set reflects not the next state ? + VBranch* tree = (VASSIGN, + VLINE("state_next_" + toStr(i) + "_sig"), + (VOR, + VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), + (VAND, (VNOT, VLINE("in_exit_set_" + toStr(i) + "_sig")), VLINE("state_active_" + toStr(i) + "_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; - size_t i = 0; - for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, i++) { - 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_" + eventNameEscape((*eventIter)->value) + "_sig"); - } - } - } else { - *nameMatchers += VLINE("'1'"); - } - - VContainer conflicters = VOR; - for (size_t j = 0; j < i; 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; + stream << "-- optimal transition set selection" << std::endl; + VContainer optimalTransitions = VOR; + VContainer spontaneoursActive = VOR; + size_t i = 0; + for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, i++) { + 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_" + eventNameEscape((*eventIter)->value) + "_sig"); + } + } + } else { + *nameMatchers += VLINE("'1'"); + } + + VContainer conflicters = VOR; + for (size_t j = 0; j < i; 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; - - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { - DOMElement* state = *stateIter; - - 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; - size_t j = 0; - for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, j++) { - DOMElement* transition = *transIter; - std::string exitSet = ATTR(transition, "exitSetBools"); - if (exitSet[i] == '1') { - *exitsetters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig "); - } - } - - VBranch* tree = (VASSIGN, - VLINE("in_exit_set_" + toStr(i) + "_sig"), - (VAND, - VLINE("state_active_" + toStr(i) + "_sig"), - exitsetters)); - - tree->print(stream); - stream << ";" << std::endl; - } + stream << "-- exit set selection" << std::endl; + + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + DOMElement* state = *stateIter; + + 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; + size_t j = 0; + for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, j++) { + DOMElement* transition = *transIter; + std::string exitSet = ATTR(transition, "exitSetBools"); + if (exitSet[i] == '1') { + *exitsetters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig "); + } + } + + VBranch* tree = (VASSIGN, + VLINE("in_exit_set_" + toStr(i) + "_sig"), + (VAND, + VLINE("state_active_" + toStr(i) + "_sig"), + exitsetters)); + + tree->print(stream); + stream << ";" << std::endl; + } } void ChartToVHDL::writeEntrySet(std::ostream & stream) { - stream << "-- entry set selection" << std::endl; - - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { - DOMElement* state = *stateIter; - - VBranch* tree = (VASSIGN, - VLINE("in_entry_set_" + toStr(i) + "_sig"), - (VAND, - VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), - (VOR, VLINE("in_exit_set_" + toStr(i) + "_sig"), - (VNOT, VLINE("state_active_" + toStr(i) + "_sig"))))); - - tree->print(stream); - stream << ";" << std::endl; - } + stream << "-- entry set selection" << std::endl; + + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + DOMElement* state = *stateIter; + + VBranch* tree = (VASSIGN, + VLINE("in_entry_set_" + toStr(i) + "_sig"), + (VAND, + VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), + (VOR, VLINE("in_exit_set_" + toStr(i) + "_sig"), + (VNOT, VLINE("state_active_" + toStr(i) + "_sig"))))); + + tree->print(stream); + stream << ";" << std::endl; + } } void ChartToVHDL::writeDefaultCompletions(std::ostream & stream) { - // TODO direct connect the line in complete entry set (no extra line needed ...) - stream << "-- default completion assignments" << std::endl; - stream << "-- indikates if the state for which I am the def-completion is active" << std::endl; - std::map<DOMElement*, std::list<DOMNode*> > completions; - - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { - DOMElement* state = *stateIter; - - completions[state]; // initialize other completions to 0 - - // we just need this if parent is a compound state - std::string parent = ATTR(state, "parent"); - - if (getParentState(state) != NULL - && isCompound(getParentState(state))) { - - // Am I default completen ? - std::string completion = ATTR_CAST(_states[strTo<size_t>(parent)], "completionBools"); - if (completion[i] == '1') { - // Yes? then give me the parent line - completions[state].push_back(getParentState(state)); - - } - } - } - - auto complIter = completions.begin(); - while (complIter != completions.end()) { - const DOMElement* state(complIter->first); - const std::list<DOMNode*> refs(complIter->second); - - std::string index = ATTR(state, "documentOrder"); - VContainer defaultCompleters = VOR; - - for (auto ref : refs) { - // *defaultCompleters += VLINE("in_complete_entry_set_" + - // TODO: default completion just when state is entered the first time ? - // if yes then we use the following code. If not we have to revert - *defaultCompleters += VLINE("in_entry_set_" + - ATTR_CAST(ref, "documentOrder") + "_sig "); - } - - VBranch* tree = (VASSIGN, - VLINE("default_completion_" + index + "_sig"), defaultCompleters); - - tree->print(stream); - stream << ";" << std::endl; - - complIter++; - } + // TODO direct connect the line in complete entry set (no extra line needed ...) + stream << "-- default completion assignments" << std::endl; + stream << "-- indikates if the state for which I am the def-completion is active" << std::endl; + std::map<DOMElement*, std::list<DOMNode*> > completions; + + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + DOMElement* state = *stateIter; + + completions[state]; // initialize other completions to 0 + + // we just need this if parent is a compound state + std::string parent = ATTR(state, "parent"); + + if (getParentState(state) != NULL + && isCompound(getParentState(state))) { + + // Am I default completen ? + std::string completion = ATTR_CAST(_states[strTo<size_t>(parent)], "completionBools"); + if (completion[i] == '1') { + // Yes? then give me the parent line + completions[state].push_back(getParentState(state)); + + } + } + } + + auto complIter = completions.begin(); + while (complIter != completions.end()) { + const DOMElement* state(complIter->first); + const std::list<DOMNode*> refs(complIter->second); + + std::string index = ATTR(state, "documentOrder"); + VContainer defaultCompleters = VOR; + + for (auto ref : refs) { + // *defaultCompleters += VLINE("in_complete_entry_set_" + + // TODO: default completion just when state is entered the first time ? + // if yes then we use the following code. If not we have to revert + *defaultCompleters += VLINE("in_entry_set_" + + ATTR_CAST(ref, "documentOrder") + "_sig "); + } + + VBranch* tree = (VASSIGN, + VLINE("default_completion_" + index + "_sig"), defaultCompleters); + + tree->print(stream); + stream << ";" << std::endl; + + complIter++; + } } void ChartToVHDL::writeCompleteEntrySet(std::ostream & stream) { - stream << "-- complete entry set selection" << std::endl; - - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { - DOMElement* state = *stateIter; - - 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 optimalEntrysetters = VOR; - size_t j = 0; - for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, j++) { - DOMElement* transition = *transIter; - - std::string targetSet = ATTR(transition, "targetBools"); - if (targetSet[i] == '1') {// <- ? TODO Was ist hier der vergleich? - *optimalEntrysetters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig"); - } - } - - VContainer completeEntrysetters = VOR; - stream << "--" << state->getNodeName() << std::endl; // for debugging - if (isCompound(state) || isParallel(state)) { // <- true for scxml? TODO - for (size_t j = 0; j < _states.size(); j++) { - if (children[j] != '1') // if is child of state j - continue; - *completeEntrysetters += VLINE("in_complete_entry_set_up_" + toStr(j) + "_sig"); - } - } - - VBranch* tree = (VASSIGN, - VLINE("in_complete_entry_set_up_" + toStr(i) + "_sig"), - (VOR, optimalEntrysetters, completeEntrysetters) - ); - tree->print(stream); - stream << ";" << std::endl; + stream << "-- complete entry set selection" << std::endl; + + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + DOMElement* state = *stateIter; + + 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 optimalEntrysetters = VOR; + size_t j = 0; + for (auto transIter = _transitions.begin(); transIter != _transitions.end(); transIter++, j++) { + DOMElement* transition = *transIter; + + std::string targetSet = ATTR(transition, "targetBools"); + if (targetSet[i] == '1') {// <- ? TODO Was ist hier der vergleich? + *optimalEntrysetters += VLINE("in_optimal_transition_set_" + toStr(j) + "_sig"); + } + } + + VContainer completeEntrysetters = VOR; + stream << "--" << state->getNodeName() << std::endl; // for debugging + if (isCompound(state) || isParallel(state)) { // <- true for scxml? TODO + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') // if is child of state j + continue; + *completeEntrysetters += VLINE("in_complete_entry_set_up_" + toStr(j) + "_sig"); + } + } + + VBranch* tree = (VASSIGN, + VLINE("in_complete_entry_set_up_" + toStr(i) + "_sig"), + (VOR, optimalEntrysetters, completeEntrysetters) + ); + tree->print(stream); + stream << ";" << std::endl; #if 0 - stream << "in_complete_entry_set_up_" << toStr(i) << "_sig <= ('0'" << std::endl; - - for (size_t j = 0; j < _transitions.size(); j++) { - Element<std::string> transition(_transitions[j]); - // std::cout << transition; - std::string targetSet = ATTR(transition, "targetBools"); - if (targetSet[i] == '1') { - stream << " or in_optimal_transition_set_" << toStr(j) << std::endl; - } - } - if (isCompound(state)) { - for (size_t j = 0; j < _states.size(); j++) { - if (children[j] != '1') - continue; - - stream << " or in_complete_entry_set_up_" << toStr(j) << "_sig" << std::endl; - } - - } - stream << ");" << std::endl; + stream << "in_complete_entry_set_up_" << toStr(i) << "_sig <= ('0'" << std::endl; + + for (size_t j = 0; j < _transitions.size(); j++) { + Element<std::string> transition(_transitions[j]); + // std::cout << transition; + std::string targetSet = ATTR(transition, "targetBools"); + if (targetSet[i] == '1') { + stream << " or in_optimal_transition_set_" << toStr(j) << std::endl; + } + } + if (isCompound(state)) { + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') + continue; + + stream << " or in_complete_entry_set_up_" << toStr(j) << "_sig" << std::endl; + } + + } + stream << ");" << std::endl; #endif - } - - for (auto state : _states) { - std::string completion = ATTR(state, "completionBools"); - std::string ancestors = ATTR(state, "ancBools"); - std::string parent = ATTR(state, "parent"); - - if (parent.size() == 0) { - continue; // TODO: FixMe <scxml> <-- ? - } - - VContainer tmp1 = VAND; - // if parent is compound - if (getParentState(state) != NULL && - isCompound(getParentState(state))) { - std::string children = ATTR_CAST(_states[strTo<size_t>(parent)], - "childBools"); - // TODO: do not add default_completion line if not needed - // --> just if this state is the default completion of parent - // --> init attr. or if not present first in document order <-- = completion bool ? - *tmp1 += VLINE("default_completion_" + ATTR(state, "documentOrder") + "_sig"); - - //TODO check this - for (size_t j = 0; j < _states.size(); j++) { - if (children[j] != '1') - continue; - *tmp1 += (VAND, - (VNOT, - (VAND, - VLINE("state_active_" + toStr(j) + "_sig"), - (VNOT, - VLINE("in_exit_set_" + toStr(j) + "_sig"))))); - - } - - } - - // if parent is parallel - if (getParentState(state) != NULL && - isParallel(getParentState(state))) { - *tmp1 += VLINE("in_complete_entry_set_" + toStr(parent) + "_sig"); - } - - VBranch* tree = (VASSIGN, - VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), - (VOR, - VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), - tmp1)); - - tree->print(stream); - stream << ";" << std::endl; + } + + for (auto state : _states) { + std::string completion = ATTR(state, "completionBools"); + std::string ancestors = ATTR(state, "ancBools"); + std::string parent = ATTR(state, "parent"); + + if (parent.size() == 0) { + continue; // TODO: FixMe <scxml> <-- ? + } + + VContainer tmp1 = VAND; + // if parent is compound + if (getParentState(state) != NULL && + isCompound(getParentState(state))) { + std::string children = ATTR_CAST(_states[strTo<size_t>(parent)], + "childBools"); + // TODO: do not add default_completion line if not needed + // --> just if this state is the default completion of parent + // --> init attr. or if not present first in document order <-- = completion bool ? + *tmp1 += VLINE("default_completion_" + ATTR(state, "documentOrder") + "_sig"); + + //TODO check this + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') + continue; + *tmp1 += (VAND, + (VNOT, + (VAND, + VLINE("state_active_" + toStr(j) + "_sig"), + (VNOT, + VLINE("in_exit_set_" + toStr(j) + "_sig"))))); + + } + + } + + // if parent is parallel + if (getParentState(state) != NULL && + isParallel(getParentState(state))) { + *tmp1 += VLINE("in_complete_entry_set_" + toStr(parent) + "_sig"); + } + + VBranch* tree = (VASSIGN, + VLINE("in_complete_entry_set_" + toStr(i) + "_sig"), + (VOR, + VLINE("in_complete_entry_set_up_" + ATTR(state, "documentOrder") + "_sig"), + tmp1)); + + tree->print(stream); + stream << ";" << std::endl; #if 0 - stream << "in_complete_entry_set_" << toStr(i) << "_sig <= (in_complete_entry_set_up_" << toStr(i) << "_sig or (" << std::endl; + stream << "in_complete_entry_set_" << toStr(i) << "_sig <= (in_complete_entry_set_up_" << toStr(i) << "_sig or (" << std::endl; - if (isParallel(Element<std::string>(_states[strTo<size_t>(parent)]))) { - stream << " in_complete_entry_set_" << toStr(parent) << "_sig" << std::endl; - } else if (isCompound(Element<std::string>(_states[strTo<size_t>(parent)]))) { - stream << " default_completion_" << toStr(parent) << "_sig" << std::endl; + if (isParallel(Element<std::string>(_states[strTo<size_t>(parent)]))) { + stream << " in_complete_entry_set_" << toStr(parent) << "_sig" << std::endl; + } else if (isCompound(Element<std::string>(_states[strTo<size_t>(parent)]))) { + stream << " default_completion_" << toStr(parent) << "_sig" << std::endl; - for (size_t j = 0; j < _states.size(); j++) { - if (children[j] != '1') - continue; - stream << " and not (is_active" << toStr(j) << "_sig and not in_exit_set_" << toStr(j) << "_sig)" << std::endl; + for (size_t j = 0; j < _states.size(); j++) { + if (children[j] != '1') + continue; + stream << " and not (is_active" << toStr(j) << "_sig and not in_exit_set_" << toStr(j) << "_sig)" << std::endl; - } - } + } + } - stream << ");" << std::endl; + stream << ");" << std::endl; #endif - } + } } 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; - - size_t i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + // 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; + + size_t i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { // DOMElement* state = *stateIter; - stream << " state_active_" << toStr(i) << "_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; - - i = 0; - for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { - // DOMElement* state = *stateIter; - stream << " state_active_" << toStr(i) << "_sig <= " << "state_next_" << toStr(i) << "_sig;" << std::endl; - } - - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; + stream << " state_active_" << toStr(i) << "_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; + + i = 0; + for (auto stateIter = _states.begin(); stateIter != _states.end(); stateIter++, i++) { + // DOMElement* state = *stateIter; + stream << " state_active_" << toStr(i) << "_sig <= " << "state_next_" << toStr(i) << "_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 << "-- 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 85fd30d..0a58b4e 100644 --- a/src/uscxml/transform/ChartToVHDL.h +++ b/src/uscxml/transform/ChartToVHDL.h @@ -161,19 +161,19 @@ protected: void writeTypes(std::ostream& stream); void writeIncludes(std::ostream& stream); - - // top layer components + + // top layer components void writeFiFo(std::ostream& stream); void writeEventController(std::ostream & stream); void writeMicroStepper(std::ostream& stream); void writeTestbench(std::ostream & stream); - - // system + + // system void writeSignalsAndComponents(std::ostream& stream); void writeSystemSignalMapping(std::ostream& stream); void writeModuleInstantiation(std::ostream& stream); - // combinatorial logic + // combinatorial logic void writeOptimalTransitionSetSelection(std::ostream& stream); void writeExitSet(std::ostream & stream); void writeEntrySet(std::ostream & stream); @@ -182,24 +182,24 @@ protected: void writeCompleteEntrySet(std::ostream & stream); void writeActiveStateNplusOne(std::ostream & stream); - // handler + // handler void writeStateHandler(std::ostream& stream); void writeResetHandler(std::ostream & stream); void writeSpontaneousHandler(std::ostream & stream); void writeInternalEventHandler(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; + std::list< XERCESC_NS::DOMElement* > _execContent; private: std::string eventNameEscape(const std::string& eventName); - std::string getLineForExecContent(const XERCESC_NS::DOMNode* elem); + std::string getLineForExecContent(const XERCESC_NS::DOMNode* elem); }; diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp new file mode 100644 index 0000000..4d1d8d5 --- /dev/null +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.cpp @@ -0,0 +1,596 @@ +/** + * @file + * @author 2016 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#define MAX_MACRO_CHARS 64 + +#include "PromelaCodeAnalyzer.h" +#include "uscxml/transform/ChartToPromela.h" +#include "uscxml/util/Predicates.h" +#include "uscxml/util/DOM.h" +#include "uscxml/util/String.h" + +#include <boost/algorithm/string.hpp> + +namespace uscxml { + +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")); + } + } + } +// _lastStrIndex = interpreter->_states.size(); + + /** Find all event names that might occur */ + { + std::list<XERCESC_NS::DOMElement*> internalEventNames = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "transition", + XML_PREFIX(interpreter->_scxml).str() + "raise", + XML_PREFIX(interpreter->_scxml).str() + "send" + }, interpreter->_scxml); + + for (auto internalEventName : internalEventNames) { + if (HAS_ATTR_CAST(internalEventName, "event")) { + std::string eventNames = ATTR_CAST(internalEventName, "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); + } + } + } + + for (auto state : interpreter->_states) { + if (HAS_ATTR(state, "id") && (isCompound(state) || isParallel(state))) { + _eventTrie.addWord("done.state." + ATTR(state, "id")); + } + } + } + + // 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 + std::list<XERCESC_NS::DOMElement*> contents = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "content" + }, interpreter->_scxml); + + for (auto content : contents) { + std::string contentStr = spaceNormalize(X(((DOMElement*)content)->getFirstChild()->getNodeValue())); + if (!isNumeric(contentStr.c_str(), 10)) { + addLiteral(contentStr); + } + } + } + + /* add platform variables as string literals */ + addLiteral(interpreter->_prefix + "_sessionid"); + addLiteral(interpreter->_prefix + "_name"); + + + /** Extract and analyze source code */ + { + std::list<XERCESC_NS::DOMElement*> withCond = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "transition", + XML_PREFIX(interpreter->_scxml).str() + "if", + XML_PREFIX(interpreter->_scxml).str() + "elseif" + }, interpreter->_scxml); + + for (auto cond : withCond) { + if (HAS_ATTR(cond, "cond")) { + std::string code = ATTR_CAST(cond, "cond"); + code = sanitizeCode(code); + addCode(code, interpreter); + cond->setAttribute(X("cond"), X(code)); + } + } + + std::list<XERCESC_NS::DOMElement*> withExpr = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "log", + XML_PREFIX(interpreter->_scxml).str() + "data", + XML_PREFIX(interpreter->_scxml).str() + "assign", + XML_PREFIX(interpreter->_scxml).str() + "content", + XML_PREFIX(interpreter->_scxml).str() + "param" + }, interpreter->_scxml); + + for (auto expr : withExpr) { + if (HAS_ATTR(expr, "expr")) { + std::string code = ATTR_CAST(expr, "expr"); + code = sanitizeCode(code); + addCode(code, interpreter); + expr->setAttribute(X("expr"), X(code)); + } + } + + std::list<XERCESC_NS::DOMElement*> withLocation = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "assign" + }, interpreter->_scxml); + + for (auto location : withLocation) { + if (HAS_ATTR(location, "location")) { + std::string code = ATTR_CAST(location, "location"); + code = sanitizeCode(code); + addCode(code, interpreter); + location->setAttribute(X("location"), X(code)); + } + } + + std::list<XERCESC_NS::DOMElement*> withText = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "script" + }, interpreter->_scxml); + + for (auto text : withText) { + std::list<XERCESC_NS::DOMNode*> texts = DOMUtils::filterChildType(DOMNode::TEXT_NODE, text, true); + for (auto textBlock : texts) { + DOMText* textText = static_cast<DOMText*>(textBlock); + std::string code = X(textText->getNodeValue()).str(); + if (code.size() > 0) { + code = sanitizeCode(code); + addCode(code, interpreter); + textText->setNodeValue(X(code)); + } + } + } + + std::list<XERCESC_NS::DOMElement*> foreachs = DOMUtils::inDocumentOrder({ + XML_PREFIX(interpreter->_scxml).str() + "foreach" + }, 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.invokeid", 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")) { + addCode("_event.delay", interpreter); +#if NEW_DELAY_RESHUFFLE +#else + 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 + } + } + } + } + + } + +} + +std::string PromelaCodeAnalyzer::sanitizeCode(const std::string& code) { + std::string replaced = code; + boost::replace_all(replaced, "\"", "'"); + boost::replace_all(replaced, "_sessionid", "_SESSIONID"); + boost::replace_all(replaced, "_name", "_NAME"); + return replaced; +} + +void PromelaCodeAnalyzer::addCode(const std::string& code, ChartToPromela* interpreter) { + PromelaParser parser(code); + // parser.dump(); + + // find all strings + std::list<PromelaParserNode*> astNodes; + astNodes.push_back(parser.ast); + + while(astNodes.size() > 0) { + PromelaParserNode* node = astNodes.front(); + astNodes.pop_front(); + + // node->dump(); + + bool hasValue = false; + int assignedValue = 0; + + + switch (node->type) { + case PML_STRING: { + std::string unquoted = node->value; + if (boost::starts_with(unquoted, "'")) { + unquoted = unquoted.substr(1, unquoted.size() - 2); + } + addLiteral(unquoted); + break; + } + case PML_ASGN: + if (node->operands.back()->type == PML_CONST) { + hasValue = true; + if (isInteger(node->operands.back()->value.c_str(), 10)) { + assignedValue = strTo<int>(node->operands.back()->value); + } + } + if (node->operands.back()->type == PML_STRING) { + // remember strings for later + astNodes.push_back(node->operands.back()); + } + if (node->operands.front()->type == PML_CMPND) { + node = node->operands.front(); + } else { + break; + } + // if (node->operands.front()->type != PML_NAME) + // break; // this will skip array assignments + case PML_CMPND: { + std::string nameOfType; + std::list<PromelaParserNode*>::iterator opIter = node->operands.begin(); + if ((*opIter)->type != PML_NAME) { + node->dump(); + return; + assert(false); + } + + PromelaTypedef* td = &_typeDefs; + std::string seperator; + + while(opIter != node->operands.end()) { + switch ((*opIter)->type) { + case PML_NAME: + td = &td->types[(*opIter)->value]; + td->occurrences.insert(interpreter); + + nameOfType += seperator + (*opIter)->value; + if (nameOfType.compare("_x") == 0) + _usesPlatformVars = true; + seperator = "_"; + td->name = nameOfType + "_t"; + break; + case PML_VAR_ARRAY: { + PromelaParserNode* name = (*opIter)->operands.front(); + PromelaParserNode* subscript = *(++(*opIter)->operands.begin()); + td = &td->types[name->value]; + td->occurrences.insert(interpreter); + + nameOfType += seperator + name->value; + td->name = nameOfType + "_t"; + + if (isInteger(subscript->value.c_str(), 10)) { + td->arraySize = strTo<int>(subscript->value); + } + break; + } + default: + if ((*opIter)->type == PML_CONST) { + // break fall through from ASGN + break; + } + // node->dump(); + // assert(false); + break; + } + + if (nameOfType.compare("_x_states") == 0) { + _usesInPredicate = true; + } + if (nameOfType.compare("_event_type") == 0) { + addLiteral("internal"); + addLiteral("external"); + addLiteral("platform"); + } + if (nameOfType.compare("_event_origintype") == 0) { + addLiteral("http://www.w3.org/TR/scxml/#SCXMLEventProcessor"); + } + opIter++; + } + + if (hasValue) { + if (td->maxValue < assignedValue) + td->maxValue = assignedValue; + if (td->minValue > assignedValue) + td->minValue = assignedValue; + } + + continue; // skip processing nested AST nodes + } + case PML_NAME: { + _typeDefs.types[node->value].occurrences.insert(interpreter); + _typeDefs.types[node->value].minValue = 0; + _typeDefs.types[node->value].maxValue = 0; + // test325 + if (node->value.compare("_ioprocessors") == 0) { + addCode("_ioprocessors.scxml.location", interpreter); + } + + break; + } + + default: + // node->dump(); + break; + // assert(false); + } + + astNodes.insert(astNodes.end(), node->operands.begin(), node->operands.end()); + + } +} + +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); + createMacroName(literal); + enumerateLiteral(literal, forceIndex); +} + +int PromelaCodeAnalyzer::indexForLiteral(const std::string& literal) { + if (boost::starts_with(literal, "'")) + throw std::runtime_error("Literal " + literal + " passed with quotes"); + + if (_strIndex.find(literal) == _strIndex.end()) + throw std::runtime_error("No index for literal " + literal + " known"); + return _strIndex[literal]; +} + +std::string PromelaCodeAnalyzer::macroForLiteral(const std::string& literal) { + if (boost::starts_with(literal, "'")) + throw std::runtime_error("Literal " + literal + " passed with quotes"); + + if (_strMacros.find(literal) == _strMacros.end()) + throw std::runtime_error("No macro for literal '" + literal + "' known"); + return _strMacros[literal]; +} + + +std::string PromelaCodeAnalyzer::createMacroName(const std::string& literal) { + if (_strMacros.find(literal) != _strMacros.end()) + return _strMacros[literal]; + + // find a suitable macro name for the strings + std::string macroName = literal; //literal.substr(1, literal.size() - 2); + + // cannot start with digit + if (isInteger(macroName.substr(0,1).c_str(), 10)) + macroName = "_" + macroName; + + macroName = macroName.substr(0, MAX_MACRO_CHARS); + boost::to_upper(macroName); + + std::string illegalChars = "#\\/:?\"<>| \n\t()[]{}',.-"; + std::string tmp; + std::string::iterator it = macroName.begin(); + while (it < macroName.end()) { + bool found = illegalChars.find(*it) != std::string::npos; + if(found) { + tmp += '_'; + it++; + while(it < macroName.end() && illegalChars.find(*it) != std::string::npos) { + it++; + } + } else { + tmp += *it++; + } + } + macroName = tmp; + if(macroName.length() < 1) + macroName = "_EMPTY_STRING"; + if(macroName.length() < 2 && macroName[0] == '_') + macroName = "_WEIRD_CHARS"; + + unsigned int index = 2; + while (_macroNameSet.find(macroName) != _macroNameSet.end()) { + std::string suffix = toStr(index); + if (macroName.size() > suffix.size()) { + macroName = macroName.substr(0, macroName.size() - suffix.size()) + suffix; + } else { + macroName = suffix; + } + index++; + } + + _macroNameSet.insert(macroName); + _strMacros[literal] = macroName; + return macroName; +} + +int PromelaCodeAnalyzer::enumerateLiteral(const std::string& literal, int forceIndex) { + if (forceIndex >= 0) { + _strIndex[literal] = forceIndex; + return forceIndex; + } + + if (_strIndex.find(literal) != _strIndex.end()) + return _strIndex[literal]; + + _strIndex[literal] = _lastStrIndex++; + return _lastStrIndex + 1; +} + +std::string PromelaCodeAnalyzer::adaptCode(const std::string& code, const std::string& prefix) { + // for (std::map<std::string, std::string>::const_iterator litIter = _strMacros.begin(); litIter != _strMacros.end(); litIter++) { + // boost::replace_all(replaced, "'" + litIter->first + "'", litIter->second); + // } + // boost::replace_all(replaced, "_event", prefix + "_event"); + // replace all variables from analyzer + + std::string processed = code; + std::stringstream processedStr; + std::list<std::pair<size_t, size_t> > posList; + std::list<std::pair<size_t, size_t> >::iterator posIter; + size_t lastPos; + + // prepend all identifiers with our prefix + { + PromelaParser parsed(processed); + // parsed.dump(); + posList = getTokenPositions(code, PML_NAME, parsed.ast); + posList.sort(); + posIter = posList.begin(); + 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 { + processedStr << code.substr(lastPos, posIter->first - lastPos) << prefix << token; + } + lastPos = posIter->second; + posIter++; + } + processedStr << processed.substr(lastPos, processed.size() - lastPos); + + processed = processedStr.str(); + processedStr.clear(); + processedStr.str(""); + } + + // replace string literals + { + PromelaParser parsed(processed); + posList = getTokenPositions(code, PML_STRING, parsed.ast); + posList.sort(); + posIter = posList.begin(); + lastPos = 0; + + while (posIter != posList.end()) { + processedStr << processed.substr(lastPos, posIter->first - lastPos); + // std::cout << processed.substr(posIter->first + 1, posIter->second - posIter->first - 2) << std::endl; + assert(_strMacros.find(processed.substr(posIter->first + 1, posIter->second - posIter->first - 2)) != _strMacros.end()); + processedStr << _strMacros[processed.substr(posIter->first + 1, posIter->second - posIter->first - 2)]; + lastPos = posIter->second; + posIter++; + } + processedStr << processed.substr(lastPos, processed.size() - lastPos); + + processed = processedStr.str(); + processedStr.clear(); + processedStr.str(""); + } + + return processed; +} + +std::list<std::pair<size_t, size_t> > PromelaCodeAnalyzer::getTokenPositions(const std::string& expr, int type, PromelaParserNode* ast) { + std::list<std::pair<size_t, size_t> > posList; + if (ast->type == type && ast->loc != NULL) { + // ast->dump(); + if (type == PML_NAME && ast->parent && + ((ast->parent->type == PML_CMPND && ast->parent->operands.front() != ast) || + (ast->parent->parent && ast->parent->type == PML_VAR_ARRAY && ast->parent->parent->type == PML_CMPND))) { + // field in a compound + } else { + if (ast->loc->firstLine == 0) { + posList.push_back(std::make_pair(ast->loc->firstCol, ast->loc->lastCol)); + } else { + int line = ast->loc->firstLine; + size_t lastPos = 0; + while(line > 0) { + lastPos = expr.find_first_of('\n', lastPos + 1); + line--; + } + posList.push_back(std::make_pair(lastPos + ast->loc->firstCol, lastPos + ast->loc->lastCol)); + } + } + } + for (std::list<PromelaParserNode*>::iterator opIter = ast->operands.begin(); opIter != ast->operands.end(); opIter++) { + std::list<std::pair<size_t, size_t> > tmp = getTokenPositions(expr, type, *opIter); + posList.insert(posList.end(), tmp.begin(), tmp.end()); + } + return posList; +} + +std::string PromelaCodeAnalyzer::getTypeReset(const std::string& var, const PromelaTypedef& type, const std::string padding) { + std::stringstream assignment; + + 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 << var << "." << typeIter->first << "[" << i << "] = 0;" << std::endl; + } + } else if (innerType.types.size() > 0) { + assignment << getTypeReset(var + "." + typeIter->first, typeIter->second, padding); + } else { + assignment << padding << var << "." << typeIter->first << " = 0;" << std::endl; + } + typeIter++; + } + return assignment.str(); + +} + +} diff --git a/src/uscxml/transform/promela/PromelaCodeAnalyzer.h b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h new file mode 100644 index 0000000..656b24e --- /dev/null +++ b/src/uscxml/transform/promela/PromelaCodeAnalyzer.h @@ -0,0 +1,150 @@ +/** + * @file + * @author 2016 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef PROMELACODEANALYZER_H_E89FF519 +#define PROMELACODEANALYZER_H_E89FF519 + +#include "uscxml/transform/Trie.h" +#include "uscxml/plugins/datamodel/promela/PromelaParser.h" +#include "uscxml/plugins/datamodel/promela/parser/promela.tab.hpp" + +#include <set> + +namespace uscxml { + +class ChartToPromela; + +class USCXML_API PromelaCodeAnalyzer { +public: + class PromelaTypedef { + public: + PromelaTypedef() {} + std::string name; + std::string type; + size_t arraySize = 0; + size_t minValue = 0; + size_t maxValue = 0; + std::map<std::string, PromelaTypedef> types; + std::set<ChartToPromela*> occurrences; + + bool operator==(const PromelaTypedef& other) const { + return name == other.name; + } + + }; + + PromelaCodeAnalyzer() : _eventTrie(".") {} + + void analyze(ChartToPromela* interpreter); + + void addCode(const std::string& code, ChartToPromela* interpreter); + void addLiteral(const std::string& stateName, int forceIndex = -1); + + bool usesComplexEventStruct() { + return _typeDefs.types.find("_event") != _typeDefs.types.end() && _typeDefs.types["_event"].types.size() > 0; + } + bool usesEventField(const std::string& fieldName) { + if (usesComplexEventStruct() && _typeDefs.types["_event"].types.find(fieldName) != _typeDefs.types["_event"].types.end()) + return true; + return false; + } + 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() && + _typeDefs.types["_event"].types["data"].types.find(fieldName) != _typeDefs.types["_event"].types["data"].types.end()) + return true; + return false; + } + + std::string getTypeAssignment(const std::string& varTo, const std::string& varFrom, const PromelaTypedef& type, const std::string padding = ""); + std::string getTypeReset(const std::string& var, const PromelaTypedef& type, const std::string padding = ""); + + bool usesInPredicate() { + return _usesInPredicate; + } + void usesInPredicate(bool value) { + _usesInPredicate = value; + } + bool usesPlatformVars() { + return _usesPlatformVars; + } + + bool hasIndexLessLoops() { + return _hasIndexLessLoops; + } + + std::string macroForLiteral(const std::string& literal); + int indexForLiteral(const std::string& literal); + + std::set<std::string> getLiterals() { + return _literals; + } + std::set<std::string> getEventsWithPrefix(const std::string& prefix); + + Trie& getTrie() { + return _eventTrie; + } + + std::string adaptCode(const std::string& code, const std::string& prefix); + + static std::string prefixIdentifiers(const std::string& expr, const std::string& prefix); + static std::list<std::pair<size_t, size_t> > getTokenPositions(const std::string& expr, int type, PromelaParserNode* ast); + + PromelaTypedef& getTypes() { + return _typeDefs; + } + + PromelaTypedef& getType(const std::string& typeName) { + return _typeDefs.types.at(typeName); + } + + std::string sanitizeCode(const std::string& code); + +protected: + void addEvent(const std::string& eventName); + void addState(const std::string& stateName, size_t index); + + std::string createMacroName(const std::string& literal); + 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; + + PromelaTypedef _typeDefs; + Trie _eventTrie; + +private: + std::set<std::string> _macroNameSet; // helper set for uniqueness of macros + int _lastStrIndex = 1; + bool _usesCancel = false; + bool _usesInPredicate = false; + bool _usesPlatformVars = false; + bool _hasIndexLessLoops = false; +}; + + + +} + +#endif /* end of include guard: PROMELACODEANALYZER_H_E89FF519 */ diff --git a/src/uscxml/transform/promela/PromelaInlines.cpp b/src/uscxml/transform/promela/PromelaInlines.cpp new file mode 100644 index 0000000..7d62762 --- /dev/null +++ b/src/uscxml/transform/promela/PromelaInlines.cpp @@ -0,0 +1,165 @@ +/** + * @file + * @author 2016 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#include "PromelaInlines.h" +#include <boost/algorithm/string.hpp> + +namespace uscxml { + +using namespace XERCESC_NS; + +void PromelaInline::dump() { +} + +PromelaInline::PromelaInline(const XERCESC_NS::DOMNode* node) { + if (node->getNodeType() != DOMNode::COMMENT_NODE && node->getNodeType() != DOMNode::TEXT_NODE) + return; // nothing to do + + std::stringstream ssLine(X(node->getNodeValue()).str()); + std::string line; + + while(std::getline(ssLine, line)) { + // skip to first promela line + boost::trim(line); + if (boost::starts_with(line, "promela")) + break; + } + + if (!boost::starts_with(line, "promela")) + return; + + if (false) { + } else if (boost::starts_with(line, "promela-code")) { + type = PROMELA_CODE; + } else if (boost::starts_with(line, "promela-ltl")) { + type = PROMELA_LTL; + } else if (boost::starts_with(line, "promela-event-all")) { + type = PROMELA_EVENT_ALL_BUT; + } else if (boost::starts_with(line, "promela-event")) { + type = PROMELA_EVENT_ONLY; + } else if (boost::starts_with(line, "promela-progress")) { + type = PROMELA_PROGRESS_LABEL; + } else if (boost::starts_with(line, "promela-accept")) { + type = PROMELA_ACCEPT_LABEL; + } else if (boost::starts_with(line, "promela-end")) { + type = PROMELA_END_LABEL; + } + + std::stringstream contentSS; + size_t endType = line.find_first_of(": \n"); + + std::string seperator; + if (endType != std::string::npos && endType + 1 < line.size()) { + contentSS << line.substr(endType + 1, line.size() - endType + 1); + seperator = "\n"; + } + + while(std::getline(ssLine, line)) { + boost::trim(line); + if (boost::starts_with(line, "promela")) { + std::cerr << "Split multiple #promela pragmas into multiple comments!" << std::endl; + break; + } + contentSS << seperator << line; + seperator = "\n"; + } + content = contentSS.str(); + +} + +PromelaInlines::PromelaInlines(const XERCESC_NS::DOMNode* node) { + + std::list<DOMNode*> levelNodes; + levelNodes.push_back(const_cast<XERCESC_NS::DOMNode*>(node)); + + size_t level = 0; + while(levelNodes.size() > 0) { + PromelaInline* predecessor = NULL; + + // iterate all nodes at given level + for (auto levelNode : levelNodes) { + + // get all comments + std::list<DOMNode*> comments = DOMUtils::filterChildType(DOMNode::COMMENT_NODE, levelNode); + for (auto comment : comments) { + + PromelaInline* tmp = new PromelaInline(comment); + if (tmp->type == PromelaInline::PROMELA_NIL) { + delete tmp; + continue; + } + + if (predecessor != NULL) { + tmp->prevSibling = predecessor; + predecessor->nextSibling = tmp; + } + tmp->level = level; + tmp->container = static_cast<DOMElement*>(levelNode); + predecessor = tmp; + inlines[levelNode].push_back(tmp); + allInlines.push_back(tmp); + } + } + + levelNodes = DOMUtils::filterChildType(DOMNode::ELEMENT_NODE, levelNodes); + level++; + } + +} + +PromelaInlines::~PromelaInlines() { +} + +std::list<PromelaInline*> PromelaInlines::getRelatedTo(const XERCESC_NS::DOMNode* node, + PromelaInline::PromelaInlineType type) { + std::list<PromelaInline*> related; + + auto inlIter = inlines.begin(); + while (inlIter != inlines.end()) { + std::list<PromelaInline*>::iterator pmlIter = inlIter->second.begin(); + while (pmlIter != inlIter->second.end()) { + if ((type != PromelaInline::PROMELA_NIL || (*pmlIter)->type == type) && (*pmlIter)->relatesTo(node)) { + related.push_back(*pmlIter); + } + pmlIter++; + } + inlIter++; + } + return related; +} + +std::list<PromelaInline*> PromelaInlines::getAllOfType(uint32_t type) { + std::list<PromelaInline*> related; + + auto inlIter = inlines.begin(); + while (inlIter != inlines.end()) { + std::list<PromelaInline*>::iterator pmlIter = inlIter->second.begin(); + while (pmlIter != inlIter->second.end()) { + if ((*pmlIter)->type & type) { + related.push_back(*pmlIter); + } + pmlIter++; + } + inlIter++; + } + return related; + +} + +}
\ No newline at end of file diff --git a/src/uscxml/transform/promela/PromelaInlines.h b/src/uscxml/transform/promela/PromelaInlines.h new file mode 100644 index 0000000..2621f8d --- /dev/null +++ b/src/uscxml/transform/promela/PromelaInlines.h @@ -0,0 +1,113 @@ +/** + * @file + * @author 2016 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) + * @copyright Simplified BSD + * + * @cond + * This program is free software: you can redistribute it and/or modify + * it under the terms of the FreeBSD license as published by the FreeBSD + * project. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the FreeBSD license along with this + * program. If not, see <http://www.opensource.org/licenses/bsd-license>. + * @endcond + */ + +#ifndef PROMELAINLINES_H_29BF8EF3 +#define PROMELAINLINES_H_29BF8EF3 + +#include "uscxml/config.h" +#include "uscxml/Common.h" +#include "uscxml/messages/Data.h" +#include "uscxml/util/DOM.h" + +#include <xercesc/dom/DOM.hpp> +#include <list> +#include <string> + +namespace uscxml { + +class USCXML_API PromelaInline { +public: + enum PromelaInlineType { + PROMELA_NIL = 0x0000, + PROMELA_LTL = 0x0001, + PROMELA_CODE = 0x0002, + PROMELA_EVENT_ALL_BUT = 0x0004, + PROMELA_EVENT_ONLY = 0x0008, + PROMELA_PROGRESS_LABEL = 0x0010, + PROMELA_ACCEPT_LABEL = 0x0020, + PROMELA_END_LABEL = 0x0040 + }; + + PromelaInline(const XERCESC_NS::DOMNode* node); + virtual ~PromelaInline() {} + + operator bool() { + return (type != PROMELA_NIL); + } + + std::list<PromelaInline*> children; + PromelaInline* prevSibling; + PromelaInline* nextSibling; + + virtual void dump(); + + virtual bool relatesTo(const XERCESC_NS::DOMNode* node) { + return container == node; + } + + size_t level; + std::string content; + const XERCESC_NS::DOMElement* container; + PromelaInlineType type; + +protected: + PromelaInline() : prevSibling(NULL), nextSibling(NULL), type(PROMELA_NIL) {}; +}; + + +class USCXML_API PromelaEventSource : public PromelaInline { +public: + PromelaEventSource(const PromelaInline& pmlInline) { + type = pmlInline.type; + container = pmlInline.container; + content = pmlInline.content; + events = Data::fromJSON(pmlInline.content); + } + + virtual bool relatesTo(const XERCESC_NS::DOMNode* node) { + return container == node || DOMUtils::isDescendant(node, container); + } + + Data events; +}; + + +class USCXML_API PromelaInlines { +public: + + PromelaInlines(const XERCESC_NS::DOMNode* node); + PromelaInlines() {} + + virtual ~PromelaInlines(); + + std::list<PromelaInline*> getRelatedTo(const XERCESC_NS::DOMNode* node, PromelaInline::PromelaInlineType type); + std::list<PromelaInline*> getAllOfType(uint32_t type); + + std::map<const XERCESC_NS::DOMNode*, std::list<PromelaInline*> > inlines; + std::list<PromelaInline*> allInlines; + + static std::list<std::string> getStringLiterals(const Data& data); + static std::list<std::string> getEventNames(const Data& data); + + +}; + +} + +#endif /* end of include guard: PROMELAINLINES_H_29BF8EF3 */ |