diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.cpp | 1382 | ||||
-rw-r--r-- | src/uscxml/transform/ChartToVHDL.h | 83 |
2 files changed, 733 insertions, 732 deletions
diff --git a/src/uscxml/transform/ChartToVHDL.cpp b/src/uscxml/transform/ChartToVHDL.cpp index fe2c229..e9dc60d 100644 --- a/src/uscxml/transform/ChartToVHDL.cpp +++ b/src/uscxml/transform/ChartToVHDL.cpp @@ -38,696 +38,696 @@ namespace uscxml { - using namespace Arabica::DOM; - using namespace Arabica::XPath; - - Transformer ChartToVHDL::transform(const Interpreter& other) { - ChartToVHDL* c2c = new ChartToVHDL(other); - - return boost::shared_ptr<TransformerImpl>(c2c); - } - - ChartToVHDL::ChartToVHDL(const Interpreter& other) : TransformerImpl() { - cloneFrom(other.getImpl()); - } - - ChartToVHDL::~ChartToVHDL() { - } - - NodeSet<std::string> ChartToVHDL::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root) { - NodeSet<std::string> nodes; - inPostFixOrder(elements, root, nodes); - return nodes; - } - - void ChartToVHDL::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) { - NodeList<std::string> children = root.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element<std::string> childElem(children.item(i)); - inPostFixOrder(elements, childElem, nodes); - - } - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element<std::string> childElem(children.item(i)); - - if (elements.find(TAGNAME(childElem)) != elements.end()) { - nodes.push_back(childElem); - } - } - } - - void ChartToVHDL::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) { - if (elements.find(TAGNAME(root)) != elements.end()) { - nodes.push_back(root); - } - - NodeList<std::string> children = root.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) - continue; - Arabica::DOM::Element<std::string> childElem(children.item(i)); - inDocumentOrder(elements, childElem, nodes); - } - } - - NodeSet<std::string> ChartToVHDL::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root) { - NodeSet<std::string> nodes; - inDocumentOrder(elements, root, nodes); - return nodes; - } - - - // ASK Where does _scxml,_nsInfo come from - - void ChartToVHDL::writeTo(std::ostream& stream) { - // ASK What is this ? - _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); - // ASK Name for whole state machine? Important ? - _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : "no_name_machine"); - - // filter unsupported stuff - std::set<std::string> elements; - elements.insert(_nsInfo.xmlNSPrefix + "datamodel"); - elements.insert(_nsInfo.xmlNSPrefix + "data"); - elements.insert(_nsInfo.xmlNSPrefix + "assign"); - elements.insert(_nsInfo.xmlNSPrefix + "donedata"); - elements.insert(_nsInfo.xmlNSPrefix + "content"); - elements.insert(_nsInfo.xmlNSPrefix + "param"); - elements.insert(_nsInfo.xmlNSPrefix + "script"); - - elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - elements.insert(_nsInfo.xmlNSPrefix + "history"); - - elements.insert(_nsInfo.xmlNSPrefix + "if"); //implizit elseif und else - elements.insert(_nsInfo.xmlNSPrefix + "foreach"); - elements.insert(_nsInfo.xmlNSPrefix + "send"); - elements.insert(_nsInfo.xmlNSPrefix + "cancel"); - elements.insert(_nsInfo.xmlNSPrefix + "invoke"); - elements.insert(_nsInfo.xmlNSPrefix + "finalize"); - Arabica::XPath::NodeSet<std::string> unsupported = inDocumentOrder(elements, _scxml); - - if (unsupported.size() > 0) { - stream << "contains unsupported elements:" << std::endl; - for (int i = 0; i < unsupported.size(); i++) { - Element<std::string> uElement(unsupported[i]); - stream << TAGNAME(uElement) << std::endl; - } - stream << "ERROR" << std::endl; - return; - } - - elements.clear(); - elements.insert(_nsInfo.xmlNSPrefix + "transition"); - unsupported = inPostFixOrder(elements, _scxml); - - for (int i = 0; i < unsupported.size(); i++) { - Element<std::string> transition(unsupported[i]); - if (HAS_ATTR(transition, "cond")) { - stream << transition << std::endl; - stream << "transition has conditions (not supported)!" << std::endl; - stream << "ERROR" << std::endl; - return; - } - if (!HAS_ATTR(transition, "target")) { - stream << transition << std::endl; - stream << "transition has no target (not supported)!" << std::endl; - stream << "ERROR" << std::endl; - return; - } - if (!HAS_ATTR(transition, "event")) { - stream << transition << std::endl; - stream << "transition is spntaneous (not supported)!" << std::endl; - stream << "ERROR" << std::endl; - return; - } - if (transition.getChildNodes().getLength() > 0) { - stream << transition << std::endl; - stream << "transition executable code (not supported)!" << std::endl; - stream << "ERROR" << std::endl; - return; - } - } - - // create states array - elements.clear(); - // elements.insert(_nsInfo.xmlNSPrefix + "scxml"); - elements.insert(_nsInfo.xmlNSPrefix + "state"); - elements.insert(_nsInfo.xmlNSPrefix + "final"); - elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - elements.insert(_nsInfo.xmlNSPrefix + "history"); - elements.insert(_nsInfo.xmlNSPrefix + "initial"); - // elements.insert(_nsInfo.xmlNSPrefix + "parallel"); - _states = inDocumentOrder(elements, _scxml); - - for (int i = 0; i < _states.size(); i++) { - Element<std::string> state(_states[i]); - state.setAttribute("documentOrder", toStr(i)); - if (!HAS_ATTR(state, "id")) { - std::stringstream ss; - ss << "HWS_" << toStr(i); - state.setAttribute("id", ss.str()); - } - _stateNames[ATTR(state, "id")] = state; - } - _initState = ATTR(_scxml, "initial"); - - // create transitions array & event array - elements.clear(); - elements.insert(_nsInfo.xmlNSPrefix + "transition"); - _transitions = inPostFixOrder(elements, _scxml); - - for (int i = 0; i < _transitions.size(); i++) { - Element<std::string> transition(_transitions[i]); - transition.setAttribute("postFixOrder", toStr(i)); - if (!HAS_ATTR(transition, "event")) { - // spontanious transition - transition.setAttribute("event", CONST_TRANS_SPONTANIOUS); - } - std::stringstream ss; - ss << "HWT" << toStr(i) << "_to_" << ATTR(transition, "target"); - transition.setAttribute("id", ss.str()); - _transitionNames[ss.str()] = transition; - - std::string event = ATTR(transition, "event"); - if (event == "*") { - event = CONST_EVENT_ANY; - transition.setAttribute("event", CONST_EVENT_ANY); - } - if (!(std::find(_events.begin(), _events.end(), event) != _events.end())) { - // if eventname does not exist - _events.push_back(event); - } - } - - // debug - // stream << _scxml; - // return; - - // how many bits do we need to represent the state array? - // std::string seperator; - // _stateCharArraySize = ceil((float) _states.size() / (float) 8); - // _stateCharArrayInit = "{"; - // for (int i = 0; i < _stateCharArraySize; i++) { - // _stateCharArrayInit += seperator + "0"; - // seperator = ", "; - // } - // _stateCharArrayInit += "}"; - // - // seperator = ""; - // _transCharArraySize = ceil((float) _transitions.size() / (float) 8); - // _transCharArrayInit = "{"; - // for (int i = 0; i < _transCharArraySize; i++) { - // _transCharArrayInit += seperator + "0"; - // seperator = ", "; - // } - // _transCharArrayInit += "}"; - - // writeTopDown(stream); - writeTypes(stream); - writeFiFo(stream); - writeFSM(stream); - } - - void ChartToVHDL::writeFSM(std::ostream & stream) { - - // create hardware top level - stream << "-- FSM Logic" << std::endl; - writeIncludes(stream); - stream << "entity fsm_scxml is" << std::endl; - stream << "port(" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk :in std_logic;" << std::endl; - stream << " rst :in std_logic;" << std::endl; - stream << " en :in std_logic;" << std::endl; - stream << " next_event_i :in event_type;" << std::endl; - stream << " next_event_en_i :in std_logic;" << std::endl; - stream << " --outputs" << std::endl; - stream << " completed_o :out std_logic;" << std::endl; - stream << " error_o :out std_logic;" << std::endl; - stream << " current_state_o :out state_type" << std::endl; - stream << ");" << std::endl; - stream << "end fsm_scxml; " << std::endl; - - stream << std::endl; - stream << std::endl; - stream << "architecture behavioral of fsm_scxml is " << std::endl; - stream << std::endl; - - // Add signals and components - writeSignals(stream); - - stream << std::endl; - stream << "begin" << std::endl; - stream << std::endl; - // signal mapping - writeModuleInstantiation(stream); - - // write fsm architecture - writeNextStateLogic(stream); - // writeOutputLogic(stream); - writeErrorHandler(stream); - - stream << std::endl; - stream << "end behavioral; " << std::endl; - stream << "-- END FSM Logic" << std::endl; - } - - void ChartToVHDL::writeTopDown(std::ostream & stream) { - // create hardware top level - stream << "-- top level" << std::endl; - writeIncludes(stream); - stream << "entity top_scxml is" << std::endl; - stream << "port(" << std::endl; - stream << " --inputs" << std::endl; - stream << " clk\t:in std_logic;" << std::endl; - stream << " rst\t:in std_logic;" << std::endl; - stream << " --outputs" << std::endl; - stream << " completed_o\t:out std_logic;" << std::endl; - stream << " result_o\t:out std_logic;" << std::endl; - stream << " error_o\t:out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end top_scxml; " << std::endl; - stream << std::endl; - stream << std::endl; - stream << "architecture behavioral of top_scxml is " << std::endl; - stream << std::endl; - - // Add signals and components - writeSignals(stream); - - stream << std::endl; - stream << "begin" << std::endl; - stream << std::endl; - // signal mapping - writeModuleInstantiation(stream); - - // write fsm architecture - writeNextStateLogic(stream); - writeOutputLogic(stream); - - stream << std::endl; - stream << "end behavioral; " << std::endl; - } - - void ChartToVHDL::writeTypes(std::ostream & stream) { - std::string seperator = ""; - - stream << "-- needed global types" << std::endl; - stream << "library IEEE;" << std::endl; - stream << "use IEEE.std_logic_1164.all;" << std::endl; - stream << std::endl; - stream << "package generated_p1 is" << std::endl; - // create state type - stream << " type state_type is std_logic_vector( "; - stream << _states.size() - 1; - stream << " downto 0)" << std::endl; - - //TODO complete - // create event type - stream << " type event_type is ("; - seperator = ""; - for (int i = 0; i < _events.size(); i++) { - stream << seperator; - stream << _events[i]; - seperator = ", "; - } - if (seperator.size() == 0) { - stream << "NO_EVENTS"; - } - stream << ");" << std::endl; - - stream << "end generated_p1;" << 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.generated_p1.all;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeFiFo(std::ostream & stream) { - // taken from: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ - // alternativly take fifo logic for a ram device: http://www.eng.auburn.edu/~strouce/class/elec4200/vhdlmods.pdf - stream << "-- standard FIFO buffer" << std::endl; - writeIncludes(stream); - stream << "" << std::endl; - stream << "entity std_fifo is" << std::endl; - stream << "generic (" << std::endl; - stream << " constant FIFO_DEPTH : positive := 256" << std::endl; - stream << ");" << std::endl; - stream << "port ( " << std::endl; - stream << " clk : in std_logic;" << std::endl; - stream << " rst : in std_logic;" << std::endl; - stream << " write_en : in std_logic;" << std::endl; - stream << " read_en : in std_logic;" << std::endl; - stream << " data_in : in event_type;" << std::endl; - stream << " data_out : out event_type;" << std::endl; - stream << " empty : out std_logic;" << std::endl; - stream << " full : out std_logic" << std::endl; - stream << ");" << std::endl; - stream << "end std_fifo;" << std::endl; - stream << "" << std::endl; - stream << "architecture behavioral of std_fifo is" << std::endl; - stream << "begin" << std::endl; - stream << "-- Memory Pointer Process" << std::endl; - stream << "fifo_proc : process (clk)" << std::endl; - stream << " type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of event_type;" << std::endl; - stream << " variable Memory : FIFO_Memory;" << std::endl; - stream << "" << std::endl; - stream << " variable Head : natural range 0 to FIFO_DEPTH - 1;" << std::endl; - stream << " variable Tail : natural range 0 to FIFO_DEPTH - 1;" << std::endl; - stream << "" << std::endl; - stream << " variable Looped : boolean;" << std::endl; - stream << "begin" << std::endl; - stream << " if rising_edge(clk) then" << std::endl; - stream << " if rst = '1' then" << std::endl; - stream << " Head := 0;" << std::endl; - stream << " Tail := 0;" << std::endl; - stream << "" << std::endl; - stream << " Looped := false;" << std::endl; - stream << "" << std::endl; - stream << " full <= '0';" << std::endl; - stream << " empty <= '1';" << std::endl; - stream << " else" << std::endl; - stream << " if (read_en = '1') then" << std::endl; - stream << " if ((Looped = true) or (Head /= Tail)) then" << std::endl; - stream << " -- Update data output" << std::endl; - stream << " data_out <= Memory(Tail);" << std::endl; - stream << " " << std::endl; - stream << " -- Update Tail pointer as needed" << std::endl; - stream << " if (Tail = FIFO_DEPTH - 1) then" << std::endl; - stream << " Tail := 0;" << std::endl; - stream << " " << std::endl; - stream << " Looped := false;" << std::endl; - stream << " else" << std::endl; - stream << " Tail := Tail + 1;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " if (write_en = '1') then" << std::endl; - stream << " if ((Looped = false) or (Head /= Tail)) then" << std::endl; - stream << " -- Write Data to Memory" << std::endl; - stream << " Memory(Head) := data_in;" << std::endl; - stream << " " << std::endl; - stream << " -- Increment Head pointer as needed" << std::endl; - stream << " if (Head = FIFO_DEPTH - 1) then" << std::endl; - stream << " Head := 0;" << std::endl; - stream << " " << std::endl; - stream << " Looped := true;" << std::endl; - stream << " else" << std::endl; - stream << " Head := Head + 1;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "" << std::endl; - stream << " -- Update empty and full flags" << std::endl; - stream << " if (Head = Tail) then" << std::endl; - stream << " if Looped then" << std::endl; - stream << " full <= '1';" << std::endl; - stream << " else" << std::endl; - stream << " empty <= '1';" << std::endl; - stream << " end if;" << std::endl; - stream << " else" << std::endl; - stream << " empty <= '0';" << std::endl; - stream << " full <= '0';" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << "" << std::endl; - stream << "end behavioral;" << std::endl; - stream << "-- END standard FIFO buffer" << std::endl; - } - - void ChartToVHDL::writeSignals(std::ostream & stream) { - // create needed internal signals - stream << "-- system signals" << std::endl; - stream << "signal stall : std_logic;" << std::endl; - stream << "-- state signals" << std::endl; - stream << "signal next_state : state_type;" << std::endl; - stream << "signal current_state : state_type;" << std::endl; - - for (int i = 0; i < _states.size(); i++) { - Element<std::string> state(_states[i]); - stream << "signal " << ATTR(state, "id") << "_curr : current_state(" - << toStr(i) << ");" << std::endl; - stream << "signal " << ATTR(state, "id") << "_next : next_state(" - << toStr(i) << ");" << 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 : event_type;" << std::endl; - stream << "signal event_consumed : std_logic;" << std::endl; - stream << std::endl; - stream << "-- transition signals" << std::endl; - stream << "signal transition_spntaneous_en : std_logic;" << std::endl; - - for (int i = 0; i < _transitions.size(); i++) { - Element<std::string> transition(_transitions[i]); - stream << "signal " << ATTR(transition, "id") << "_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 needed 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) { - // tmp mapping for events - stream << "error_o <= reg_error_out; " << std::endl; - stream << "stall <= not en; " << 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_en_i; " << std::endl; - stream << "int_event_input <= next_event_i; " << std::endl; - stream << "int_event_read_en <= not transition_spontanous_en and not stall; " << 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," << 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; - } - - //TODO write event generator - // wie die letzten beiden states erkennen - // process bauen der bei fail 0 ausgibt und bei accept 1 - - void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { - stream << "-- state logic" << std::endl; - stream << "-- only gets active when state changes (microstep?) " << std::endl; - stream << "state_decode_proc: process(current_state)" << std::endl; - stream << "begin" << std::endl; - - std::stringstream nextStateBuffer; - for (int i = 0; i < _states.size(); i++) { - Element<std::string> state(_states[i]); - - // calculate event choises - // _transitions is sorted in Postfix order - // by stating with smalest index the most important - // will be written first - std::vector< Element<std::string> > choises; - std::string spntaneous_trans_sig = ""; - for (int j = 0; j < _transitions.size(); j++) { - Element<std::string> transition(_transitions[j]); - if (ATTR_CAST(transition.getParentNode(), "id") == ATTR(state, "id")) { - choises.push_back(transition); - if (ATTR(transition, "event") == CONST_TRANS_SPONTANIOUS) { - spntaneous_trans_sig = ATTR(transition, "id"); - // FIXME hofully there are just single spntaneous transitions allowed - // else we have to handle this - } - } - } - - // calculate incomming transitions (for later use) - std::vector< Element<std::string> > incommingTransitions; - for (int j = 0; j < _transitions.size(); j++) { - Element<std::string> transition(_transitions[j]); - if (ATTR_CAST(transition, "target") == ATTR(state, "id")) { - incommingTransitions.push_back(transition); - } - } - - if (choises.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything - - stream << " if ( " << ATTR(state, "id") << " = '1' ) then" << std::endl; - stream << " if ( transition_spntaneous_en = '1' ) then" << std::endl; - // enable spntaneous transition (if any) and disable all other - for (int j = 0; j < choises.size(); j++) { - Element<std::string> transition(choises[j]); - if (ATTR(transition, "id") == spntaneous_trans_sig) { - stream << " " << ATTR(transition, "id") << "_sig <= '1';" << std::endl; - } else { - stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl; - } - } - - stream << " elsif ( next_event_re = '1' ) then" << std::endl; - // if no spntaneous transition enables, look at events - // since there is just one event at a time, we use case statement - // to check transitions matching in postfix order - // FIXME hopefully there is just one transition per state and event at a time - stream << " case next_event is" << std::endl; - bool hasWildcardTransition = false; - for (int j = 0; j < choises.size(); j++) { - Element<std::string> transition(choises[j]); - std::string eventName = ATTR(transition, "event"); - if (eventName == CONST_EVENT_ANY) { - eventName = "others"; - hasWildcardTransition = true; - } - stream << " when " << eventName << " =>" << std::endl; - // activate transition and deactivete others - for (int k = 0; k < choises.size(); k++) { - Element<std::string> tmp_t(choises[k]); - if (ATTR(tmp_t, "event") == ATTR(transition, "event")) { - stream << " " << ATTR(tmp_t, "id") << "_sig <= '1';" << std::endl; - } else { - stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl; - } - } - } - if (!hasWildcardTransition) { - // if there is no others we create one for deactivating everything - stream << " when others =>" << std::endl; - for (int j = 0; j < choises.size(); j++) { - Element<std::string> tmp_t(choises[j]); - stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl; - } - } - stream << " end case;" << std::endl; - //TODO umkehren oder other abfangen - //stream << " when others =>" << std::endl; - //stream << " next_state <= current_state;" << std::endl; - - stream << " else" << std::endl; - // no enabled event ? disable all transitions (looks like we have to wait) - for (int j = 0; j < choises.size(); j++) { - Element<std::string> transition(choises[j]); - stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl; - } - stream << " end if;" << std::endl; - stream << " end if;" << std::endl; - stream << std::endl; - } - // write next state calculation in buffer for later use - nextStateBuffer << ATTR(state, "id") << "_next <= ( ( '0'"; - std::string seperator = " or "; - for (int j = 0; j < incommingTransitions.size(); j++) { - nextStateBuffer << seperator - << ATTR(incommingTransitions[j], "id") << "_sig"; - } - nextStateBuffer << " ) or "; - nextStateBuffer << "( ( not ( '0'"; - seperator = " or "; - for (int j = 0; j < choises.size(); j++) { - nextStateBuffer << seperator - << ATTR(choises[j], "id") << "_sig"; - } - nextStateBuffer << " ) ) and " << ATTR(state, "id") - << "_curr ));" << std::endl; - } - stream << "end process;" << std::endl; - stream << std::endl; - // write outgoing transition buffer - stream << nextStateBuffer.str() << std::endl; - - // updater for current state - stream << "-- update current state" << std::endl; - stream << "state_proc: process(clk, rst, stall)" << std::endl; - stream << "begin" << std::endl; - stream << " if rst = '1' then" << std::endl; - stream << " current_state <= (others => '0');" << std::endl; - stream << " " << _initState << "_curr <= '1';" << std::endl; - stream << " elsif (rising_edge(clk) and stall = '0') then" << std::endl; - stream << " current_state <= next_state;" << std::endl; - stream << " end if;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - } - - void ChartToVHDL::writeOutputLogic(std::ostream & stream) { - stream << "-- output logic" << std::endl; - stream << "output_proc: process(current_state)" << std::endl; - stream << "begin" << std::endl; - stream << " case current_state is" << std::endl; - - for (int i = 0; i < _states.size(); i++) { - //TODO - // if end state set completed and result - // on entry events generated here - } - - stream << " when others =>" << std::endl; - stream << " completed_o <= '0';" << std::endl; - stream << " result_o <= '0';" << std::endl; - - stream << "end case;" << std::endl; - stream << "end process;" << std::endl; - stream << std::endl; - } +using namespace Arabica::DOM; +using namespace Arabica::XPath; + +Transformer ChartToVHDL::transform(const Interpreter& other) { + ChartToVHDL* c2c = new ChartToVHDL(other); + + return boost::shared_ptr<TransformerImpl>(c2c); +} + +ChartToVHDL::ChartToVHDL(const Interpreter& other) : TransformerImpl() { + cloneFrom(other.getImpl()); +} + +ChartToVHDL::~ChartToVHDL() { +} + +NodeSet<std::string> ChartToVHDL::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root) { + NodeSet<std::string> nodes; + inPostFixOrder(elements, root, nodes); + return nodes; +} + +void ChartToVHDL::inPostFixOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) { + NodeList<std::string> children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element<std::string> childElem(children.item(i)); + inPostFixOrder(elements, childElem, nodes); + + } + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element<std::string> childElem(children.item(i)); + + if (elements.find(TAGNAME(childElem)) != elements.end()) { + nodes.push_back(childElem); + } + } +} + +void ChartToVHDL::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root, NodeSet<std::string>& nodes) { + if (elements.find(TAGNAME(root)) != elements.end()) { + nodes.push_back(root); + } + + NodeList<std::string> children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i).getNodeType() != Node_base::ELEMENT_NODE) + continue; + Arabica::DOM::Element<std::string> childElem(children.item(i)); + inDocumentOrder(elements, childElem, nodes); + } +} + +NodeSet<std::string> ChartToVHDL::inDocumentOrder(const std::set<std::string>& elements, const Element<std::string>& root) { + NodeSet<std::string> nodes; + inDocumentOrder(elements, root, nodes); + return nodes; +} + + +// ASK Where does _scxml,_nsInfo come from + +void ChartToVHDL::writeTo(std::ostream& stream) { + // ASK What is this ? + _binding = (HAS_ATTR(_scxml, "binding") && iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); + // ASK Name for whole state machine? Important ? + _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : "no_name_machine"); + + // filter unsupported stuff + std::set<std::string> elements; + elements.insert(_nsInfo.xmlNSPrefix + "datamodel"); + elements.insert(_nsInfo.xmlNSPrefix + "data"); + elements.insert(_nsInfo.xmlNSPrefix + "assign"); + elements.insert(_nsInfo.xmlNSPrefix + "donedata"); + elements.insert(_nsInfo.xmlNSPrefix + "content"); + elements.insert(_nsInfo.xmlNSPrefix + "param"); + elements.insert(_nsInfo.xmlNSPrefix + "script"); + + elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + elements.insert(_nsInfo.xmlNSPrefix + "history"); + + elements.insert(_nsInfo.xmlNSPrefix + "if"); //implizit elseif und else + elements.insert(_nsInfo.xmlNSPrefix + "foreach"); + elements.insert(_nsInfo.xmlNSPrefix + "send"); + elements.insert(_nsInfo.xmlNSPrefix + "cancel"); + elements.insert(_nsInfo.xmlNSPrefix + "invoke"); + elements.insert(_nsInfo.xmlNSPrefix + "finalize"); + Arabica::XPath::NodeSet<std::string> unsupported = inDocumentOrder(elements, _scxml); + + if (unsupported.size() > 0) { + stream << "contains unsupported elements:" << std::endl; + for (int i = 0; i < unsupported.size(); i++) { + Element<std::string> uElement(unsupported[i]); + stream << TAGNAME(uElement) << std::endl; + } + stream << "ERROR" << std::endl; + return; + } + + elements.clear(); + elements.insert(_nsInfo.xmlNSPrefix + "transition"); + unsupported = inPostFixOrder(elements, _scxml); + + for (int i = 0; i < unsupported.size(); i++) { + Element<std::string> transition(unsupported[i]); + if (HAS_ATTR(transition, "cond")) { + stream << transition << std::endl; + stream << "transition has conditions (not supported)!" << std::endl; + stream << "ERROR" << std::endl; + return; + } + if (!HAS_ATTR(transition, "target")) { + stream << transition << std::endl; + stream << "transition has no target (not supported)!" << std::endl; + stream << "ERROR" << std::endl; + return; + } + if (!HAS_ATTR(transition, "event")) { + stream << transition << std::endl; + stream << "transition is spntaneous (not supported)!" << std::endl; + stream << "ERROR" << std::endl; + return; + } + if (transition.getChildNodes().getLength() > 0) { + stream << transition << std::endl; + stream << "transition executable code (not supported)!" << std::endl; + stream << "ERROR" << std::endl; + return; + } + } + + // create states array + elements.clear(); + // elements.insert(_nsInfo.xmlNSPrefix + "scxml"); + elements.insert(_nsInfo.xmlNSPrefix + "state"); + elements.insert(_nsInfo.xmlNSPrefix + "final"); + elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + elements.insert(_nsInfo.xmlNSPrefix + "history"); + elements.insert(_nsInfo.xmlNSPrefix + "initial"); + // elements.insert(_nsInfo.xmlNSPrefix + "parallel"); + _states = inDocumentOrder(elements, _scxml); + + for (int i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + state.setAttribute("documentOrder", toStr(i)); + if (!HAS_ATTR(state, "id")) { + std::stringstream ss; + ss << "HWS_" << toStr(i); + state.setAttribute("id", ss.str()); + } + _stateNames[ATTR(state, "id")] = state; + } + _initState = ATTR(_scxml, "initial"); + + // create transitions array & event array + elements.clear(); + elements.insert(_nsInfo.xmlNSPrefix + "transition"); + _transitions = inPostFixOrder(elements, _scxml); + + for (int i = 0; i < _transitions.size(); i++) { + Element<std::string> transition(_transitions[i]); + transition.setAttribute("postFixOrder", toStr(i)); + if (!HAS_ATTR(transition, "event")) { + // spontanious transition + transition.setAttribute("event", CONST_TRANS_SPONTANIOUS); + } + std::stringstream ss; + ss << "HWT" << toStr(i) << "_to_" << ATTR(transition, "target"); + transition.setAttribute("id", ss.str()); + _transitionNames[ss.str()] = transition; + + std::string event = ATTR(transition, "event"); + if (event == "*") { + event = CONST_EVENT_ANY; + transition.setAttribute("event", CONST_EVENT_ANY); + } + if (!(std::find(_events.begin(), _events.end(), event) != _events.end())) { + // if eventname does not exist + _events.push_back(event); + } + } + + // debug + // stream << _scxml; + // return; + + // how many bits do we need to represent the state array? + // std::string seperator; + // _stateCharArraySize = ceil((float) _states.size() / (float) 8); + // _stateCharArrayInit = "{"; + // for (int i = 0; i < _stateCharArraySize; i++) { + // _stateCharArrayInit += seperator + "0"; + // seperator = ", "; + // } + // _stateCharArrayInit += "}"; + // + // seperator = ""; + // _transCharArraySize = ceil((float) _transitions.size() / (float) 8); + // _transCharArrayInit = "{"; + // for (int i = 0; i < _transCharArraySize; i++) { + // _transCharArrayInit += seperator + "0"; + // seperator = ", "; + // } + // _transCharArrayInit += "}"; + + // writeTopDown(stream); + writeTypes(stream); + writeFiFo(stream); + writeFSM(stream); +} + +void ChartToVHDL::writeFSM(std::ostream & stream) { + + // create hardware top level + stream << "-- FSM Logic" << std::endl; + writeIncludes(stream); + stream << "entity fsm_scxml is" << std::endl; + stream << "port(" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk :in std_logic;" << std::endl; + stream << " rst :in std_logic;" << std::endl; + stream << " en :in std_logic;" << std::endl; + stream << " next_event_i :in event_type;" << std::endl; + stream << " next_event_en_i :in std_logic;" << std::endl; + stream << " --outputs" << std::endl; + stream << " completed_o :out std_logic;" << std::endl; + stream << " error_o :out std_logic;" << std::endl; + stream << " current_state_o :out state_type" << std::endl; + stream << ");" << std::endl; + stream << "end fsm_scxml; " << std::endl; + + stream << std::endl; + stream << std::endl; + stream << "architecture behavioral of fsm_scxml is " << std::endl; + stream << std::endl; + + // Add signals and components + writeSignals(stream); + + stream << std::endl; + stream << "begin" << std::endl; + stream << std::endl; + // signal mapping + writeModuleInstantiation(stream); + + // write fsm architecture + writeNextStateLogic(stream); + // writeOutputLogic(stream); + writeErrorHandler(stream); + + stream << std::endl; + stream << "end behavioral; " << std::endl; + stream << "-- END FSM Logic" << std::endl; +} + +void ChartToVHDL::writeTopDown(std::ostream & stream) { + // create hardware top level + stream << "-- top level" << std::endl; + writeIncludes(stream); + stream << "entity top_scxml is" << std::endl; + stream << "port(" << std::endl; + stream << " --inputs" << std::endl; + stream << " clk\t:in std_logic;" << std::endl; + stream << " rst\t:in std_logic;" << std::endl; + stream << " --outputs" << std::endl; + stream << " completed_o\t:out std_logic;" << std::endl; + stream << " result_o\t:out std_logic;" << std::endl; + stream << " error_o\t:out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end top_scxml; " << std::endl; + stream << std::endl; + stream << std::endl; + stream << "architecture behavioral of top_scxml is " << std::endl; + stream << std::endl; + + // Add signals and components + writeSignals(stream); + + stream << std::endl; + stream << "begin" << std::endl; + stream << std::endl; + // signal mapping + writeModuleInstantiation(stream); + + // write fsm architecture + writeNextStateLogic(stream); + writeOutputLogic(stream); + + stream << std::endl; + stream << "end behavioral; " << std::endl; +} + +void ChartToVHDL::writeTypes(std::ostream & stream) { + std::string seperator = ""; + + stream << "-- needed global types" << std::endl; + stream << "library IEEE;" << std::endl; + stream << "use IEEE.std_logic_1164.all;" << std::endl; + stream << std::endl; + stream << "package generated_p1 is" << std::endl; + // create state type + stream << " type state_type is std_logic_vector( "; + stream << _states.size() - 1; + stream << " downto 0)" << std::endl; + + //TODO complete + // create event type + stream << " type event_type is ("; + seperator = ""; + for (int i = 0; i < _events.size(); i++) { + stream << seperator; + stream << _events[i]; + seperator = ", "; + } + if (seperator.size() == 0) { + stream << "NO_EVENTS"; + } + stream << ");" << std::endl; + + stream << "end generated_p1;" << 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.generated_p1.all;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeFiFo(std::ostream & stream) { + // taken from: http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/ + // alternativly take fifo logic for a ram device: http://www.eng.auburn.edu/~strouce/class/elec4200/vhdlmods.pdf + stream << "-- standard FIFO buffer" << std::endl; + writeIncludes(stream); + stream << "" << std::endl; + stream << "entity std_fifo is" << std::endl; + stream << "generic (" << std::endl; + stream << " constant FIFO_DEPTH : positive := 256" << std::endl; + stream << ");" << std::endl; + stream << "port ( " << std::endl; + stream << " clk : in std_logic;" << std::endl; + stream << " rst : in std_logic;" << std::endl; + stream << " write_en : in std_logic;" << std::endl; + stream << " read_en : in std_logic;" << std::endl; + stream << " data_in : in event_type;" << std::endl; + stream << " data_out : out event_type;" << std::endl; + stream << " empty : out std_logic;" << std::endl; + stream << " full : out std_logic" << std::endl; + stream << ");" << std::endl; + stream << "end std_fifo;" << std::endl; + stream << "" << std::endl; + stream << "architecture behavioral of std_fifo is" << std::endl; + stream << "begin" << std::endl; + stream << "-- Memory Pointer Process" << std::endl; + stream << "fifo_proc : process (clk)" << std::endl; + stream << " type FIFO_Memory is array (0 to FIFO_DEPTH - 1) of event_type;" << std::endl; + stream << " variable Memory : FIFO_Memory;" << std::endl; + stream << "" << std::endl; + stream << " variable Head : natural range 0 to FIFO_DEPTH - 1;" << std::endl; + stream << " variable Tail : natural range 0 to FIFO_DEPTH - 1;" << std::endl; + stream << "" << std::endl; + stream << " variable Looped : boolean;" << std::endl; + stream << "begin" << std::endl; + stream << " if rising_edge(clk) then" << std::endl; + stream << " if rst = '1' then" << std::endl; + stream << " Head := 0;" << std::endl; + stream << " Tail := 0;" << std::endl; + stream << "" << std::endl; + stream << " Looped := false;" << std::endl; + stream << "" << std::endl; + stream << " full <= '0';" << std::endl; + stream << " empty <= '1';" << std::endl; + stream << " else" << std::endl; + stream << " if (read_en = '1') then" << std::endl; + stream << " if ((Looped = true) or (Head /= Tail)) then" << std::endl; + stream << " -- Update data output" << std::endl; + stream << " data_out <= Memory(Tail);" << std::endl; + stream << " " << std::endl; + stream << " -- Update Tail pointer as needed" << std::endl; + stream << " if (Tail = FIFO_DEPTH - 1) then" << std::endl; + stream << " Tail := 0;" << std::endl; + stream << " " << std::endl; + stream << " Looped := false;" << std::endl; + stream << " else" << std::endl; + stream << " Tail := Tail + 1;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " if (write_en = '1') then" << std::endl; + stream << " if ((Looped = false) or (Head /= Tail)) then" << std::endl; + stream << " -- Write Data to Memory" << std::endl; + stream << " Memory(Head) := data_in;" << std::endl; + stream << " " << std::endl; + stream << " -- Increment Head pointer as needed" << std::endl; + stream << " if (Head = FIFO_DEPTH - 1) then" << std::endl; + stream << " Head := 0;" << std::endl; + stream << " " << std::endl; + stream << " Looped := true;" << std::endl; + stream << " else" << std::endl; + stream << " Head := Head + 1;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "" << std::endl; + stream << " -- Update empty and full flags" << std::endl; + stream << " if (Head = Tail) then" << std::endl; + stream << " if Looped then" << std::endl; + stream << " full <= '1';" << std::endl; + stream << " else" << std::endl; + stream << " empty <= '1';" << std::endl; + stream << " end if;" << std::endl; + stream << " else" << std::endl; + stream << " empty <= '0';" << std::endl; + stream << " full <= '0';" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << "" << std::endl; + stream << "end behavioral;" << std::endl; + stream << "-- END standard FIFO buffer" << std::endl; +} + +void ChartToVHDL::writeSignals(std::ostream & stream) { + // create needed internal signals + stream << "-- system signals" << std::endl; + stream << "signal stall : std_logic;" << std::endl; + stream << "-- state signals" << std::endl; + stream << "signal next_state : state_type;" << std::endl; + stream << "signal current_state : state_type;" << std::endl; + + for (int i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + stream << "signal " << ATTR(state, "id") << "_curr : current_state(" + << toStr(i) << ");" << std::endl; + stream << "signal " << ATTR(state, "id") << "_next : next_state(" + << toStr(i) << ");" << 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 : event_type;" << std::endl; + stream << "signal event_consumed : std_logic;" << std::endl; + stream << std::endl; + stream << "-- transition signals" << std::endl; + stream << "signal transition_spntaneous_en : std_logic;" << std::endl; + + for (int i = 0; i < _transitions.size(); i++) { + Element<std::string> transition(_transitions[i]); + stream << "signal " << ATTR(transition, "id") << "_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 needed 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) { + // tmp mapping for events + stream << "error_o <= reg_error_out; " << std::endl; + stream << "stall <= not en; " << 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_en_i; " << std::endl; + stream << "int_event_input <= next_event_i; " << std::endl; + stream << "int_event_read_en <= not transition_spontanous_en and not stall; " << 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," << 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; +} + +//TODO write event generator +// wie die letzten beiden states erkennen +// process bauen der bei fail 0 ausgibt und bei accept 1 + +void ChartToVHDL::writeNextStateLogic(std::ostream & stream) { + stream << "-- state logic" << std::endl; + stream << "-- only gets active when state changes (microstep?) " << std::endl; + stream << "state_decode_proc: process(current_state)" << std::endl; + stream << "begin" << std::endl; + + std::stringstream nextStateBuffer; + for (int i = 0; i < _states.size(); i++) { + Element<std::string> state(_states[i]); + + // calculate event choises + // _transitions is sorted in Postfix order + // by stating with smalest index the most important + // will be written first + std::vector< Element<std::string> > choises; + std::string spntaneous_trans_sig = ""; + for (int j = 0; j < _transitions.size(); j++) { + Element<std::string> transition(_transitions[j]); + if (ATTR_CAST(transition.getParentNode(), "id") == ATTR(state, "id")) { + choises.push_back(transition); + if (ATTR(transition, "event") == CONST_TRANS_SPONTANIOUS) { + spntaneous_trans_sig = ATTR(transition, "id"); + // FIXME hofully there are just single spntaneous transitions allowed + // else we have to handle this + } + } + } + + // calculate incomming transitions (for later use) + std::vector< Element<std::string> > incommingTransitions; + for (int j = 0; j < _transitions.size(); j++) { + Element<std::string> transition(_transitions[j]); + if (ATTR_CAST(transition, "target") == ATTR(state, "id")) { + incommingTransitions.push_back(transition); + } + } + + if (choises.size() > 0) {// if no outgoing transitions (maybe final state :D) we don't write anything + + stream << " if ( " << ATTR(state, "id") << " = '1' ) then" << std::endl; + stream << " if ( transition_spntaneous_en = '1' ) then" << std::endl; + // enable spntaneous transition (if any) and disable all other + for (int j = 0; j < choises.size(); j++) { + Element<std::string> transition(choises[j]); + if (ATTR(transition, "id") == spntaneous_trans_sig) { + stream << " " << ATTR(transition, "id") << "_sig <= '1';" << std::endl; + } else { + stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl; + } + } + + stream << " elsif ( next_event_re = '1' ) then" << std::endl; + // if no spntaneous transition enables, look at events + // since there is just one event at a time, we use case statement + // to check transitions matching in postfix order + // FIXME hopefully there is just one transition per state and event at a time + stream << " case next_event is" << std::endl; + bool hasWildcardTransition = false; + for (int j = 0; j < choises.size(); j++) { + Element<std::string> transition(choises[j]); + std::string eventName = ATTR(transition, "event"); + if (eventName == CONST_EVENT_ANY) { + eventName = "others"; + hasWildcardTransition = true; + } + stream << " when " << eventName << " =>" << std::endl; + // activate transition and deactivete others + for (int k = 0; k < choises.size(); k++) { + Element<std::string> tmp_t(choises[k]); + if (ATTR(tmp_t, "event") == ATTR(transition, "event")) { + stream << " " << ATTR(tmp_t, "id") << "_sig <= '1';" << std::endl; + } else { + stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl; + } + } + } + if (!hasWildcardTransition) { + // if there is no others we create one for deactivating everything + stream << " when others =>" << std::endl; + for (int j = 0; j < choises.size(); j++) { + Element<std::string> tmp_t(choises[j]); + stream << " " << ATTR(tmp_t, "id") << "_sig <= '0';" << std::endl; + } + } + stream << " end case;" << std::endl; + //TODO umkehren oder other abfangen + //stream << " when others =>" << std::endl; + //stream << " next_state <= current_state;" << std::endl; + + stream << " else" << std::endl; + // no enabled event ? disable all transitions (looks like we have to wait) + for (int j = 0; j < choises.size(); j++) { + Element<std::string> transition(choises[j]); + stream << " " << ATTR(transition, "id") << "_sig <= '0';" << std::endl; + } + stream << " end if;" << std::endl; + stream << " end if;" << std::endl; + stream << std::endl; + } + // write next state calculation in buffer for later use + nextStateBuffer << ATTR(state, "id") << "_next <= ( ( '0'"; + std::string seperator = " or "; + for (int j = 0; j < incommingTransitions.size(); j++) { + nextStateBuffer << seperator + << ATTR(incommingTransitions[j], "id") << "_sig"; + } + nextStateBuffer << " ) or "; + nextStateBuffer << "( ( not ( '0'"; + seperator = " or "; + for (int j = 0; j < choises.size(); j++) { + nextStateBuffer << seperator + << ATTR(choises[j], "id") << "_sig"; + } + nextStateBuffer << " ) ) and " << ATTR(state, "id") + << "_curr ));" << std::endl; + } + stream << "end process;" << std::endl; + stream << std::endl; + // write outgoing transition buffer + stream << nextStateBuffer.str() << std::endl; + + // updater for current state + stream << "-- update current state" << std::endl; + stream << "state_proc: process(clk, rst, stall)" << std::endl; + stream << "begin" << std::endl; + stream << " if rst = '1' then" << std::endl; + stream << " current_state <= (others => '0');" << std::endl; + stream << " " << _initState << "_curr <= '1';" << std::endl; + stream << " elsif (rising_edge(clk) and stall = '0') then" << std::endl; + stream << " current_state <= next_state;" << std::endl; + stream << " end if;" << std::endl; + stream << "end process;" << std::endl; + stream << std::endl; +} + +void ChartToVHDL::writeOutputLogic(std::ostream & stream) { + stream << "-- output logic" << std::endl; + stream << "output_proc: process(current_state)" << std::endl; + stream << "begin" << std::endl; + stream << " case current_state is" << std::endl; + + for (int i = 0; i < _states.size(); i++) { + //TODO + // if end state set completed and result + // on entry events generated here + } + + stream << " when others =>" << std::endl; + stream << " completed_o <= '0';" << std::endl; + stream << " result_o <= '0';" << std::endl; + + stream << "end case;" << std::endl; + stream << "end process;" << 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 05397cb..ec649f4 100644 --- a/src/uscxml/transform/ChartToVHDL.h +++ b/src/uscxml/transform/ChartToVHDL.h @@ -32,61 +32,62 @@ namespace uscxml { - class USCXML_API ChartToVHDL : public InterpreterRC, public TransformerImpl { - public: +class USCXML_API ChartToVHDL : public InterpreterRC, public TransformerImpl { +public: - virtual ~ChartToVHDL(); - static Transformer transform(const Interpreter& other); + virtual ~ChartToVHDL(); + static Transformer transform(const Interpreter& other); - void writeTo(std::ostream& stream); + void writeTo(std::ostream& stream); - static Arabica::XPath::NodeSet<std::string> inPostFixOrder(const std::set<std::string>& elements, - const Arabica::DOM::Element<std::string>& root); - static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::set<std::string>& elements, - const Arabica::DOM::Element<std::string>& root); - protected: - ChartToVHDL(const Interpreter& other); + static Arabica::XPath::NodeSet<std::string> inPostFixOrder(const std::set<std::string>& elements, + const Arabica::DOM::Element<std::string>& root); + static Arabica::XPath::NodeSet<std::string> inDocumentOrder(const std::set<std::string>& elements, + const Arabica::DOM::Element<std::string>& root); - static void inPostFixOrder(const std::set<std::string>& elements, - const Arabica::DOM::Element<std::string>& root, - Arabica::XPath::NodeSet<std::string>& nodes); +protected: + ChartToVHDL(const Interpreter& other); - static void inDocumentOrder(const std::set<std::string>& elements, - const Arabica::DOM::Element<std::string>& root, - Arabica::XPath::NodeSet<std::string>& nodes); + static void inPostFixOrder(const std::set<std::string>& elements, + const Arabica::DOM::Element<std::string>& root, + Arabica::XPath::NodeSet<std::string>& nodes); - void writeIncludes(std::ostream& stream); - void writeTopDown(std::ostream& stream); + static void inDocumentOrder(const std::set<std::string>& elements, + const Arabica::DOM::Element<std::string>& root, + Arabica::XPath::NodeSet<std::string>& nodes); - void writeTypes(std::ostream& stream); - void writeNextStateLogic(std::ostream& stream); - void writeOutputLogic(std::ostream& stream); - void writeSignals(std::ostream& stream); - void writeFiFo(std::ostream& stream); - void writeModuleInstantiation(std::ostream& stream); - void writeErrorHandler(std::ostream& stream); - void writeFSM(std::ostream& stream); + void writeIncludes(std::ostream& stream); + void writeTopDown(std::ostream& stream); + void writeTypes(std::ostream& stream); + void writeNextStateLogic(std::ostream& stream); + void writeOutputLogic(std::ostream& stream); + void writeSignals(std::ostream& stream); + void writeFiFo(std::ostream& stream); + void writeModuleInstantiation(std::ostream& stream); + void writeErrorHandler(std::ostream& stream); + void writeFSM(std::ostream& stream); - Interpreter interpreter; - std::string _initState; - Arabica::XPath::NodeSet<std::string> _states; - std::map<std::string, Arabica::DOM::Element<std::string> > _stateNames; - Arabica::XPath::NodeSet<std::string> _transitions; - std::map<std::string, Arabica::DOM::Element<std::string> > _transitionNames; - std::vector<std::string> _events; + Interpreter interpreter; - bool _hasGlobalScripts; - bool _hasDoneData; + std::string _initState; + Arabica::XPath::NodeSet<std::string> _states; + std::map<std::string, Arabica::DOM::Element<std::string> > _stateNames; + Arabica::XPath::NodeSet<std::string> _transitions; + std::map<std::string, Arabica::DOM::Element<std::string> > _transitionNames; + std::vector<std::string> _events; - size_t _transCharArraySize; - std::string _transCharArrayInit; + bool _hasGlobalScripts; + bool _hasDoneData; - size_t _stateCharArraySize; - std::string _stateCharArrayInit; - }; + size_t _transCharArraySize; + std::string _transCharArrayInit; + + size_t _stateCharArraySize; + std::string _stateCharArrayInit; +}; } |