summaryrefslogtreecommitdiff
path: root/src/mem/slicc/symbols/StateMachine.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/slicc/symbols/StateMachine.cc')
-rw-r--r--src/mem/slicc/symbols/StateMachine.cc993
1 files changed, 993 insertions, 0 deletions
diff --git a/src/mem/slicc/symbols/StateMachine.cc b/src/mem/slicc/symbols/StateMachine.cc
new file mode 100644
index 000000000..d4436870e
--- /dev/null
+++ b/src/mem/slicc/symbols/StateMachine.cc
@@ -0,0 +1,993 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ *
+ * */
+
+#include "StateMachine.hh"
+#include "fileio.hh"
+#include "html_gen.hh"
+#include "Action.hh"
+#include "Event.hh"
+#include "State.hh"
+#include "Transition.hh"
+#include "Var.hh"
+#include "SymbolTable.hh"
+#include "util.hh"
+#include "Vector.hh"
+
+StateMachine::StateMachine(string ident, const Location& location, const Map<string, string>& pairs)
+ : Symbol(ident, location, pairs)
+{
+ m_table_built = false;
+}
+
+StateMachine::~StateMachine()
+{
+ // FIXME
+ // assert(0);
+}
+
+void StateMachine::addState(State* state_ptr)
+{
+ assert(m_table_built == false);
+ m_state_map.add(state_ptr, m_states.size());
+ m_states.insertAtBottom(state_ptr);
+}
+
+void StateMachine::addEvent(Event* event_ptr)
+{
+ assert(m_table_built == false);
+ m_event_map.add(event_ptr, m_events.size());
+ m_events.insertAtBottom(event_ptr);
+}
+
+void StateMachine::addAction(Action* action_ptr)
+{
+ assert(m_table_built == false);
+
+ // Check for duplicate action
+ int size = m_actions.size();
+ for(int i=0; i<size; i++) {
+ if (m_actions[i]->getIdent() == action_ptr->getIdent()) {
+ m_actions[i]->warning("Duplicate action definition: " + m_actions[i]->getIdent());
+ action_ptr->error("Duplicate action definition: " + action_ptr->getIdent());
+ }
+ if (m_actions[i]->getShorthand() == action_ptr->getShorthand()) {
+ m_actions[i]->warning("Duplicate action shorthand: " + m_actions[i]->getIdent());
+ m_actions[i]->warning(" shorthand = " + m_actions[i]->getShorthand());
+ action_ptr->warning("Duplicate action shorthand: " + action_ptr->getIdent());
+ action_ptr->error(" shorthand = " + action_ptr->getShorthand());
+ }
+ }
+
+ m_actions.insertAtBottom(action_ptr);
+}
+
+void StateMachine::addTransition(Transition* trans_ptr)
+{
+ assert(m_table_built == false);
+ trans_ptr->checkIdents(m_states, m_events, m_actions);
+ m_transitions.insertAtBottom(trans_ptr);
+}
+
+void StateMachine::addFunc(Func* func_ptr)
+{
+ // register func in the symbol table
+ g_sym_table.registerSym(func_ptr->toString(), func_ptr);
+ m_internal_func_vec.insertAtBottom(func_ptr);
+}
+
+void StateMachine::buildTable()
+{
+ assert(m_table_built == false);
+ int numStates = m_states.size();
+ int numEvents = m_events.size();
+ int numTransitions = m_transitions.size();
+ int stateIndex, eventIndex;
+
+ for(stateIndex=0; stateIndex < numStates; stateIndex++) {
+ m_table.insertAtBottom(Vector<Transition*>());
+ for(eventIndex=0; eventIndex < numEvents; eventIndex++) {
+ m_table[stateIndex].insertAtBottom(NULL);
+ }
+ }
+
+ for(int i=0; i<numTransitions; i++) {
+ Transition* trans_ptr = m_transitions[i];
+
+ // Track which actions we touch so we know if we use them all --
+ // really this should be done for all symbols as part of the
+ // symbol table, then only trigger it for Actions, States, Events,
+ // etc.
+
+ Vector<Action*> actions = trans_ptr->getActions();
+ for(int actionIndex=0; actionIndex < actions.size(); actionIndex++) {
+ actions[actionIndex]->markUsed();
+ }
+
+ stateIndex = getStateIndex(trans_ptr->getStatePtr());
+ eventIndex = getEventIndex(trans_ptr->getEventPtr());
+ if (m_table[stateIndex][eventIndex] != NULL) {
+ m_table[stateIndex][eventIndex]->warning("Duplicate transition: " + m_table[stateIndex][eventIndex]->toString());
+ trans_ptr->error("Duplicate transition: " + trans_ptr->toString());
+ }
+ m_table[stateIndex][eventIndex] = trans_ptr;
+ }
+
+ // Look at all actions to make sure we used them all
+ for(int actionIndex=0; actionIndex < m_actions.size(); actionIndex++) {
+ Action* action_ptr = m_actions[actionIndex];
+ if (!action_ptr->wasUsed()) {
+ string error_msg = "Unused action: " + action_ptr->getIdent();
+ if (action_ptr->existPair("desc")) {
+ error_msg += ", " + action_ptr->getDescription();
+ }
+ action_ptr->warning(error_msg);
+ }
+ }
+
+ m_table_built = true;
+}
+
+const Transition* StateMachine::getTransPtr(int stateIndex, int eventIndex) const
+{
+ return m_table[stateIndex][eventIndex];
+}
+
+// *********************** //
+// ******* C Files ******* //
+// *********************** //
+
+void StateMachine::writeCFiles(string path) const
+{
+ string comp = getIdent();
+ string filename;
+
+ // Output switch statement for transition table
+ {
+ ostringstream sstr;
+ printCSwitch(sstr, comp);
+ conditionally_write_file(path + comp + "_Transitions.cc", sstr);
+ }
+
+ // Output the actions for performing the actions
+ {
+ ostringstream sstr;
+ printControllerC(sstr, comp);
+ conditionally_write_file(path + comp + "_Controller.cc", sstr);
+ }
+
+ // Output the method declarations for the class declaration
+ {
+ ostringstream sstr;
+ printControllerH(sstr, comp);
+ conditionally_write_file(path + comp + "_Controller.hh", sstr);
+ }
+
+ // Output the wakeup loop for the events
+ {
+ ostringstream sstr;
+ printCWakeup(sstr, comp);
+ conditionally_write_file(path + comp + "_Wakeup.cc", sstr);
+ }
+
+ // Profiling
+ {
+ ostringstream sstr;
+ printProfilerC(sstr, comp);
+ conditionally_write_file(path + comp + "_Profiler.cc", sstr);
+ }
+ {
+ ostringstream sstr;
+ printProfilerH(sstr, comp);
+ conditionally_write_file(path + comp + "_Profiler.hh", sstr);
+ }
+
+ // Write internal func files
+ for(int i=0; i<m_internal_func_vec.size(); i++) {
+ m_internal_func_vec[i]->writeCFiles(path);
+ }
+
+}
+
+void StateMachine::printControllerH(ostream& out, string component) const
+{
+ out << "/** \\file " << getIdent() << ".hh" << endl;
+ out << " * " << endl;
+ out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << " * Created by slicc definition of Module \"" << getShorthand() << "\"" << endl;
+ out << " */" << endl;
+ out << endl;
+ out << "#ifndef " << component << "_CONTROLLER_H" << endl;
+ out << "#define " << component << "_CONTROLLER_H" << endl;
+ out << endl;
+ out << "#include \"Global.hh\"" << endl;
+ out << "#include \"Consumer.hh\"" << endl;
+ out << "#include \"TransitionResult.hh\"" << endl;
+ out << "#include \"Types.hh\"" << endl;
+ out << "#include \"" << component << "_Profiler.hh\"" << endl;
+ out << endl;
+
+ // for adding information to the protocol debug trace
+ out << "extern stringstream " << component << "_" << "transitionComment;" << endl;
+
+ out << "class " << component << "_Controller : public Consumer {" << endl;
+
+ /* the coherence checker needs to call isBlockExclusive() and isBlockShared()
+ making the Chip a friend class is an easy way to do this for now */
+ out << "#ifdef CHECK_COHERENCE" << endl;
+ out << " friend class Chip;" << endl;
+ out << "#endif /* CHECK_COHERENCE */" << endl;
+
+ out << "public:" << endl;
+ out << " " << component << "_Controller(Chip* chip_ptr, int version);" << endl;
+ out << " void print(ostream& out) const;" << endl;
+ out << " void wakeup();" << endl;
+ out << " static void dumpStats(ostream& out) { s_profiler.dumpStats(out); }" << endl;
+ out << " static void clearStats() { s_profiler.clearStats(); }" << endl;
+ out << "private:" << endl;
+ out << " TransitionResult doTransition(" << component << "_Event event, " << component
+ << "_State state, const Address& addr";
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ out << ", int priority";
+ }
+ out << "); // in " << component << "_Transitions.cc" << endl;
+ out << " TransitionResult doTransitionWorker(" << component << "_Event event, " << component
+ << "_State state, " << component << "_State& next_state, const Address& addr";
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ out << ", int priority";
+ }
+ out << "); // in " << component << "_Transitions.cc" << endl;
+ out << " Chip* m_chip_ptr;" << endl;
+ out << " NodeID m_id;" << endl;
+ out << " NodeID m_version;" << endl;
+ out << " MachineID m_machineID;" << endl;
+ out << " static " << component << "_Profiler s_profiler;" << endl;
+
+ // internal function protypes
+ out << " // Internal functions" << endl;
+ for(int i=0; i<m_internal_func_vec.size(); i++) {
+ Func* func = m_internal_func_vec[i];
+ string proto;
+ func->funcPrototype(proto);
+ if (proto != "") {
+ out << " " << proto;
+ }
+ }
+
+ out << " // Actions" << endl;
+ for(int i=0; i < numActions(); i++) {
+ const Action& action = getAction(i);
+ out << "/** \\brief " << action.getDescription() << "*/" << endl;
+ out << " void " << action.getIdent() << "(const Address& addr);" << endl;
+ }
+ out << "};" << endl;
+ out << "#endif // " << component << "_CONTROLLER_H" << endl;
+}
+
+void StateMachine::printControllerC(ostream& out, string component) const
+{
+ out << "/** \\file " << getIdent() << ".cc" << endl;
+ out << " * " << endl;
+ out << " * Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << " * Created by slicc definition of Module \"" << getShorthand() << "\"" << endl;
+ out << " */" << endl;
+ out << endl;
+ out << "#include \"Global.hh\"" << endl;
+ out << "#include \"RubySlicc_includes.hh\"" << endl;
+ out << "#include \"" << component << "_Controller.hh\"" << endl;
+ out << "#include \"" << component << "_State.hh\"" << endl;
+ out << "#include \"" << component << "_Event.hh\"" << endl;
+ out << "#include \"Types.hh\"" << endl;
+ out << "#include \"System.hh\"" << endl;
+ out << "#include \"Chip.hh\"" << endl;
+ out << endl;
+
+ // for adding information to the protocol debug trace
+ out << "stringstream " << component << "_" << "transitionComment;" << endl;
+ out << "#define APPEND_TRANSITION_COMMENT(str) (" << component << "_" << "transitionComment << str)" << endl;
+
+ out << "/** \\brief static profiler defn */" << endl;
+ out << component << "_Profiler " << component << "_Controller::s_profiler;" << endl;
+ out << endl;
+
+ out << "/** \\brief constructor */" << endl;
+ out << component << "_Controller::" << component
+ << "_Controller(Chip* chip_ptr, int version)" << endl;
+ out << "{" << endl;
+ out << " m_chip_ptr = chip_ptr;" << endl;
+ out << " m_id = m_chip_ptr->getID();" << endl;
+ out << " m_version = version;" << endl;
+ out << " m_machineID.type = MachineType_" << component << ";" << endl;
+ out << " m_machineID.num = m_id*RubyConfig::numberOf"<< component << "PerChip()+m_version;" << endl;
+
+ // Set the queue consumers
+ for(int i=0; i < m_in_ports.size(); i++) {
+ const Var* port = m_in_ports[i];
+ out << " " << port->getCode() << ".setConsumer(this);" << endl;
+ }
+
+ out << endl;
+ // Set the queue descriptions
+ for(int i=0; i < m_in_ports.size(); i++) {
+ const Var* port = m_in_ports[i];
+ out << " " << port->getCode()
+ << ".setDescription(\"[Chip \" + int_to_string(m_chip_ptr->getID()) + \" \" + int_to_string(m_version) + \", "
+ << component << ", " << port->toString() << "]\");" << endl;
+ }
+
+ // Initialize the transition profiling
+ out << endl;
+ for(int i=0; i<numTransitions(); i++) {
+ const Transition& t = getTransition(i);
+ const Vector<Action*>& action_vec = t.getActions();
+ int numActions = action_vec.size();
+
+ // Figure out if we stall
+ bool stall = false;
+ for (int i=0; i<numActions; i++) {
+ if(action_vec[i]->getIdent() == "z_stall") {
+ stall = true;
+ }
+ }
+
+ // Only possible if it is not a 'z' case
+ if (!stall) {
+ out << " s_profiler.possibleTransition(" << component << "_State_"
+ << t.getStatePtr()->getIdent() << ", " << component << "_Event_"
+ << t.getEventPtr()->getIdent() << ");" << endl;
+ }
+ }
+
+ out << "}" << endl;
+
+ out << endl;
+
+ out << "void " << component << "_Controller::print(ostream& out) const { out << \"[" << component
+ << "_Controller \" << m_chip_ptr->getID() << \" \" << m_version << \"]\"; }" << endl;
+
+ out << endl;
+ out << "// Actions" << endl;
+ out << endl;
+
+ for(int i=0; i < numActions(); i++) {
+ const Action& action = getAction(i);
+ if (action.existPair("c_code")) {
+ out << "/** \\brief " << action.getDescription() << "*/" << endl;
+ out << "void " << component << "_Controller::"
+ << action.getIdent() << "(const Address& addr)" << endl;
+ out << "{" << endl;
+ out << " DEBUG_MSG(GENERATED_COMP, HighPrio,\"executing\");" << endl;
+ out << action.lookupPair("c_code");
+ out << "}" << endl;
+ }
+ out << endl;
+ }
+}
+
+void StateMachine::printCWakeup(ostream& out, string component) const
+{
+ out << "// Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << "// " << getIdent() << ": " << getShorthand() << endl;
+ out << endl;
+ out << "#include \"Global.hh\"" << endl;
+ out << "#include \"RubySlicc_includes.hh\"" << endl;
+ out << "#include \"" << component << "_Controller.hh\"" << endl;
+ out << "#include \"" << component << "_State.hh\"" << endl;
+ out << "#include \"" << component << "_Event.hh\"" << endl;
+ out << "#include \"Types.hh\"" << endl;
+ out << "#include \"System.hh\"" << endl;
+ out << "#include \"Chip.hh\"" << endl;
+ out << endl;
+ out << "void " << component << "_Controller::wakeup()" << endl;
+ out << "{" << endl;
+ // out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,*this);" << endl;
+ // out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,g_eventQueue_ptr->getTime());" << endl;
+ out << endl;
+ out << "int counter = 0;" << endl;
+ out << " while (true) {" << endl;
+ out << " // Some cases will put us into an infinite loop without this limit" << endl;
+ out << " assert(counter <= RubyConfig::" << getIdent() << "TransitionsPerCycle());" << endl;
+ out << " if (counter == RubyConfig::" << getIdent() << "TransitionsPerCycle()) {" << endl;
+ out << " g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we're fully utilized" << endl;
+ out << " g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again" << endl;
+ out << " break;" << endl;
+ out << " }" << endl;
+
+ // InPorts
+ for(int i=0; i < m_in_ports.size(); i++) {
+ const Var* port = m_in_ports[i];
+ assert(port->existPair("c_code_in_port"));
+ out << " // "
+ << component << "InPort " << port->toString()
+ << endl;
+ out << port->lookupPair("c_code_in_port");
+ out << endl;
+ }
+
+ out << " break; // If we got this far, we have nothing left todo" << endl;
+ out << " }" << endl;
+ // out << " g_eventQueue_ptr->scheduleEvent(this, 1);" << endl;
+ // out << " DEBUG_NEWLINE(GENERATED_COMP, MedPrio);" << endl;
+ out << "}" << endl;
+ out << endl;
+}
+
+void StateMachine::printCSwitch(ostream& out, string component) const
+{
+ out << "// Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << "// " << getIdent() << ": " << getShorthand() << endl;
+ out << endl;
+ out << "#include \"Global.hh\"" << endl;
+ out << "#include \"" << component << "_Controller.hh\"" << endl;
+ out << "#include \"" << component << "_State.hh\"" << endl;
+ out << "#include \"" << component << "_Event.hh\"" << endl;
+ out << "#include \"Types.hh\"" << endl;
+ out << "#include \"System.hh\"" << endl;
+ out << "#include \"Chip.hh\"" << endl;
+ out << endl;
+ out << "#define HASH_FUN(state, event) ((int(state)*" << component
+ << "_Event_NUM)+int(event))" << endl;
+ out << endl;
+ out << "#define GET_TRANSITION_COMMENT() (" << component << "_" << "transitionComment.str())" << endl;
+ out << "#define CLEAR_TRANSITION_COMMENT() (" << component << "_" << "transitionComment.str(\"\"))" << endl;
+ out << endl;
+ out << "TransitionResult " << component << "_Controller::doTransition("
+ << component << "_Event event, "
+ << component << "_State state, "
+ << "const Address& addr" << endl;
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ out << ", int priority";
+ }
+ out << ")" << endl;
+
+ out << "{" << endl;
+ out << " " << component << "_State next_state = state;" << endl;
+ out << endl;
+ out << " DEBUG_NEWLINE(GENERATED_COMP, MedPrio);" << endl;
+ out << " DEBUG_MSG(GENERATED_COMP, MedPrio,*this);" << endl;
+ out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,g_eventQueue_ptr->getTime());" << endl;
+ out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,state);" << endl;
+ out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,event);" << endl;
+ out << " DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);" << endl;
+ out << endl;
+ out << " TransitionResult result = doTransitionWorker(event, state, next_state, addr";
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ out << ", priority";
+ }
+ out << ");" << endl;
+ out << endl;
+ out << " if (result == TransitionResult_Valid) {" << endl;
+ out << " DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);" << endl;
+ out << " DEBUG_NEWLINE(GENERATED_COMP, MedPrio);" << endl;
+ out << " s_profiler.countTransition(state, event);" << endl;
+ out << " if (PROTOCOL_DEBUG_TRACE) {" << endl
+ << " g_system_ptr->getProfiler()->profileTransition(\"" << component
+ << "\", m_chip_ptr->getID(), m_version, addr, " << endl
+ << " " << component << "_State_to_string(state), " << endl
+ << " " << component << "_Event_to_string(event), " << endl
+ << " " << component << "_State_to_string(next_state), GET_TRANSITION_COMMENT());" << endl
+ << " }" << endl;
+ out << " CLEAR_TRANSITION_COMMENT();" << endl;
+ out << " " << component << "_setState(addr, next_state);" << endl;
+ out << " " << endl;
+ out << " } else if (result == TransitionResult_ResourceStall) {" << endl;
+ out << " if (PROTOCOL_DEBUG_TRACE) {" << endl
+ << " g_system_ptr->getProfiler()->profileTransition(\"" << component
+ << "\", m_chip_ptr->getID(), m_version, addr, " << endl
+ << " " << component << "_State_to_string(state), " << endl
+ << " " << component << "_Event_to_string(event), " << endl
+ << " " << component << "_State_to_string(next_state), " << endl
+ << " \"Resource Stall\");" << endl
+ << " }" << endl;
+ out << " } else if (result == TransitionResult_ProtocolStall) {" << endl;
+ out << " DEBUG_MSG(GENERATED_COMP,HighPrio,\"stalling\");" << endl
+ << " DEBUG_NEWLINE(GENERATED_COMP, MedPrio);" << endl;
+ out << " if (PROTOCOL_DEBUG_TRACE) {" << endl
+ << " g_system_ptr->getProfiler()->profileTransition(\"" << component
+ << "\", m_chip_ptr->getID(), m_version, addr, " << endl
+ << " " << component << "_State_to_string(state), " << endl
+ << " " << component << "_Event_to_string(event), " << endl
+ << " " << component << "_State_to_string(next_state), " << endl
+ << " \"Protocol Stall\");" << endl
+ << " }" << endl
+ << " }" << endl;
+ out << " return result;" << endl;
+ out << "}" << endl;
+ out << endl;
+ out << "TransitionResult " << component << "_Controller::doTransitionWorker("
+ << component << "_Event event, "
+ << component << "_State state, "
+ << component << "_State& next_state, "
+ << "const Address& addr" << endl;
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ out << ", int priority" << endl;
+ }
+ out << ")" << endl;
+
+ out << "{" << endl;
+ out << "" << endl;
+
+ out << " switch(HASH_FUN(state, event)) {" << endl;
+
+ Map<string, Vector<string> > code_map; // This map will allow suppress generating duplicate code
+ Vector<string> code_vec;
+
+ for(int i=0; i<numTransitions(); i++) {
+ const Transition& t = getTransition(i);
+ string case_string = component + "_State_" + t.getStatePtr()->getIdent()
+ + ", " + component + "_Event_" + t.getEventPtr()->getIdent();
+
+ string code;
+
+ code += " {\n";
+ // Only set next_state if it changes
+ if (t.getStatePtr() != t.getNextStatePtr()) {
+ code += " next_state = " + component + "_State_" + t.getNextStatePtr()->getIdent() + ";\n";
+ }
+
+ const Vector<Action*>& action_vec = t.getActions();
+ int numActions = action_vec.size();
+
+ // Check for resources
+ Vector<string> code_sorter;
+ const Map<Var*, string>& res = t.getResources();
+ Vector<Var*> res_keys = res.keys();
+ for (int i=0; i<res_keys.size(); i++) {
+ string temp_code;
+ if (res_keys[i]->getType()->cIdent() == "DNUCAStopTable") {
+ temp_code += res.lookup(res_keys[i]);
+ } else {
+ temp_code += " if (!" + (res_keys[i]->getCode()) + ".areNSlotsAvailable(" + res.lookup(res_keys[i]) + ")) {\n";
+ if(CHECK_INVALID_RESOURCE_STALLS) {
+ // assert that the resource stall is for a resource of equal or greater priority
+ temp_code += " assert(priority >= "+ (res_keys[i]->getCode()) + ".getPriority());\n";
+ }
+ temp_code += " return TransitionResult_ResourceStall;\n";
+ temp_code += " }\n";
+ }
+ code_sorter.insertAtBottom(temp_code);
+ }
+
+ // Emit the code sequences in a sorted order. This makes the
+ // output deterministic (without this the output order can vary
+ // since Map's keys() on a vector of pointers is not deterministic
+ code_sorter.sortVector();
+ for (int i=0; i<code_sorter.size(); i++) {
+ code += code_sorter[i];
+ }
+
+ // Figure out if we stall
+ bool stall = false;
+ for (int i=0; i<numActions; i++) {
+ if(action_vec[i]->getIdent() == "z_stall") {
+ stall = true;
+ }
+ }
+
+ if (stall) {
+ code += " return TransitionResult_ProtocolStall;\n";
+ } else {
+ for (int i=0; i<numActions; i++) {
+ code += " " + action_vec[i]->getIdent() + "(addr);\n";
+ }
+ code += " return TransitionResult_Valid;\n";
+ }
+ code += " }\n";
+
+
+ // Look to see if this transition code is unique.
+ if (code_map.exist(code)) {
+ code_map.lookup(code).insertAtBottom(case_string);
+ } else {
+ Vector<string> vec;
+ vec.insertAtBottom(case_string);
+ code_map.add(code, vec);
+ code_vec.insertAtBottom(code);
+ }
+ }
+
+ // Walk through all of the unique code blocks and spit out the
+ // corresponding case statement elements
+ for (int i=0; i<code_vec.size(); i++) {
+ string code = code_vec[i];
+
+ // Iterative over all the multiple transitions that share the same code
+ for (int case_num=0; case_num<code_map.lookup(code).size(); case_num++) {
+ string case_string = code_map.lookup(code)[case_num];
+ out << " case HASH_FUN(" << case_string << "):" << endl;
+ }
+ out << code;
+ }
+
+ out << " default:" << endl;
+ out << " WARN_EXPR(m_id);" << endl;
+ out << " WARN_EXPR(m_version);" << endl;
+ out << " WARN_EXPR(g_eventQueue_ptr->getTime());" << endl;
+ out << " WARN_EXPR(addr);" << endl;
+ out << " WARN_EXPR(event);" << endl;
+ out << " WARN_EXPR(state);" << endl;
+ out << " ERROR_MSG(\"Invalid transition\");" << endl;
+ out << " }" << endl;
+ out << " return TransitionResult_Valid;" << endl;
+ out << "}" << endl;
+}
+
+void StateMachine::printProfilerH(ostream& out, string component) const
+{
+ out << "// Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << "// " << getIdent() << ": " << getShorthand() << endl;
+ out << endl;
+ out << "#ifndef " << component << "_PROFILER_H" << endl;
+ out << "#define " << component << "_PROFILER_H" << endl;
+ out << endl;
+ out << "#include \"Global.hh\"" << endl;
+ out << "#include \"" << component << "_State.hh\"" << endl;
+ out << "#include \"" << component << "_Event.hh\"" << endl;
+ out << endl;
+ out << "class " << component << "_Profiler {" << endl;
+ out << "public:" << endl;
+ out << " " << component << "_Profiler();" << endl;
+ out << " void countTransition(" << component << "_State state, " << component << "_Event event);" << endl;
+ out << " void possibleTransition(" << component << "_State state, " << component << "_Event event);" << endl;
+ out << " void dumpStats(ostream& out) const;" << endl;
+ out << " void clearStats();" << endl;
+ out << "private:" << endl;
+ out << " int m_counters[" << component << "_State_NUM][" << component << "_Event_NUM];" << endl;
+ out << " int m_event_counters[" << component << "_Event_NUM];" << endl;
+ out << " bool m_possible[" << component << "_State_NUM][" << component << "_Event_NUM];" << endl;
+ out << "};" << endl;
+ out << "#endif // " << component << "_PROFILER_H" << endl;
+}
+
+void StateMachine::printProfilerC(ostream& out, string component) const
+{
+ out << "// Auto generated C++ code started by "<<__FILE__<<":"<<__LINE__<< endl;
+ out << "// " << getIdent() << ": " << getShorthand() << endl;
+ out << endl;
+ out << "#include \"" << component << "_Profiler.hh\"" << endl;
+ out << endl;
+
+ // Constructor
+ out << component << "_Profiler::" << component << "_Profiler()" << endl;
+ out << "{" << endl;
+ out << " for (int state = 0; state < " << component << "_State_NUM; state++) {" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " m_possible[state][event] = false;" << endl;
+ out << " m_counters[state][event] = 0;" << endl;
+ out << " }" << endl;
+ out << " }" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " m_event_counters[event] = 0;" << endl;
+ out << " }" << endl;
+ out << "}" << endl;
+
+ // Clearstats
+ out << "void " << component << "_Profiler::clearStats()" << endl;
+ out << "{" << endl;
+ out << " for (int state = 0; state < " << component << "_State_NUM; state++) {" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " m_counters[state][event] = 0;" << endl;
+ out << " }" << endl;
+ out << " }" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " m_event_counters[event] = 0;" << endl;
+ out << " }" << endl;
+ out << "}" << endl;
+
+ // Count Transition
+ out << "void " << component << "_Profiler::countTransition(" << component << "_State state, " << component << "_Event event)" << endl;
+ out << "{" << endl;
+ out << " assert(m_possible[state][event]);" << endl;
+ out << " m_counters[state][event]++;" << endl;
+ out << " m_event_counters[event]++;" << endl;
+ out << "}" << endl;
+
+ // Possible Transition
+ out << "void " << component << "_Profiler::possibleTransition(" << component << "_State state, " << component << "_Event event)" << endl;
+ out << "{" << endl;
+ out << " m_possible[state][event] = true;" << endl;
+ out << "}" << endl;
+
+ // dumpStats
+ out << "void " << component << "_Profiler::dumpStats(ostream& out) const" << endl;
+ out << "{" << endl;
+ out << " out << \" --- " << component << " ---\" << endl;" << endl;
+ out << " out << \" - Event Counts -\" << endl;" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " int count = m_event_counters[event];" << endl;
+ out << " out << (" << component << "_Event) event << \" \" << count << endl;" << endl;
+ out << " }" << endl;
+ out << " out << endl;" << endl;
+ out << " out << \" - Transitions -\" << endl;" << endl;
+ out << " for (int state = 0; state < " << component << "_State_NUM; state++) {" << endl;
+ out << " for (int event = 0; event < " << component << "_Event_NUM; event++) {" << endl;
+ out << " if (m_possible[state][event]) {" << endl;
+ out << " int count = m_counters[state][event];" << endl;
+ out << " out << (" << component << "_State) state << \" \" << (" << component << "_Event) event << \" \" << count;" << endl;
+ out << " if (count == 0) {" << endl;
+ out << " out << \" <-- \";" << endl;
+ out << " }" << endl;
+ out << " out << endl;" << endl;
+ out << " }" << endl;
+ out << " }" << endl;
+ out << " out << endl;" << endl;
+ out << " }" << endl;
+ out << "}" << endl;
+}
+
+
+
+// ************************** //
+// ******* HTML Files ******* //
+// ************************** //
+
+string frameRef(string click_href, string click_target, string over_href, string over_target_num, string text)
+{
+ string temp;
+ temp += "<A href=\"" + click_href + "\" ";
+ temp += "target=\"" + click_target + "\" ";
+ string javascript = "if (parent.frames[" + over_target_num + "].location != parent.location + '" + over_href + "') { parent.frames[" + over_target_num + "].location='" + over_href + "' }";
+ // string javascript = "parent." + target + ".location='" + href + "'";
+ temp += "onMouseOver=\"" + javascript + "\" ";
+ temp += ">" + text + "</A>";
+ return temp;
+}
+
+string frameRef(string href, string target, string target_num, string text)
+{
+ return frameRef(href, target, href, target_num, text);
+}
+
+
+void StateMachine::writeHTMLFiles(string path) const
+{
+ string filename;
+ string component = getIdent();
+
+ /*
+ {
+ ostringstream out;
+ out << "<html>" << endl;
+ out << "<head>" << endl;
+ out << "<title>" << component << "</title>" << endl;
+ out << "</head>" << endl;
+ out << "<frameset rows=\"30,30,*\" frameborder=\"1\">" << endl;
+ out << " <frame name=\"Status\" src=\"empty.html\" marginheight=\"1\">" << endl;
+ out << " <frame name=\"Table\" src=\"" << component << "_table.html\" marginheight=\"1\">" << endl;
+ out << "</frameset>" << endl;
+ out << "</html>" << endl;
+ conditionally_write_file(path + component + ".html", out);
+ }
+ */
+
+ // Create table with no row hilighted
+ {
+ ostringstream out;
+ printHTMLTransitions(out, numStates()+1);
+
+ // -- Write file
+ filename = component + "_table.html";
+ conditionally_write_file(path + filename, out);
+ }
+
+ // Generate transition tables
+ for(int i=0; i<numStates(); i++) {
+ ostringstream out;
+ printHTMLTransitions(out, i);
+
+ // -- Write file
+ filename = component + "_table_" + getState(i).getIdent() + ".html";
+ conditionally_write_file(path + filename, out);
+ }
+
+ // Generate action descriptions
+ for(int i=0; i<numActions(); i++) {
+ ostringstream out;
+ createHTMLSymbol(getAction(i), "Action", out);
+
+ // -- Write file
+ filename = component + "_action_" + getAction(i).getIdent() + ".html";
+ conditionally_write_file(path + filename, out);
+ }
+
+ // Generate state descriptions
+ for(int i=0; i<numStates(); i++) {
+ ostringstream out;
+ createHTMLSymbol(getState(i), "State", out);
+
+ // -- Write file
+ filename = component + "_State_" + getState(i).getIdent() + ".html";
+ conditionally_write_file(path + filename, out);
+ }
+
+ // Generate event descriptions
+ for(int i=0; i<numEvents(); i++) {
+ ostringstream out;
+ createHTMLSymbol(getEvent(i), "Event", out);
+
+ // -- Write file
+ filename = component + "_Event_" + getEvent(i).getIdent() + ".html";
+ conditionally_write_file(path + filename, out);
+ }
+}
+
+void StateMachine::printHTMLTransitions(ostream& out, int active_state) const
+{
+ // -- Prolog
+ out << "<HTML><BODY link=\"blue\" vlink=\"blue\">" << endl;
+
+ // -- Header
+ out << "<H1 align=\"center\">" << formatHTMLShorthand(getShorthand()) << ": " << endl;
+ Vector<StateMachine*> machine_vec = g_sym_table.getStateMachines();
+ for (int i=0; i<machine_vec.size(); i++) {
+ StateMachine* type = machine_vec[i];
+ if (i != 0) {
+ out << " - ";
+ }
+ if (type == this) {
+ out << type->getIdent() << endl;
+ } else {
+ out << "<A target=\"Table\"href=\"" + type->getIdent() + "_table.html\">" + type->getIdent() + "</A> " << endl;
+ }
+ }
+ out << "</H1>" << endl;
+
+ // -- Table header
+ out << "<TABLE border=1>" << endl;
+
+ // -- Column headers
+ out << "<TR>" << endl;
+
+ // -- First column header
+ out << " <TH> </TH>" << endl;
+
+ for(int event = 0; event < numEvents(); event++ ) {
+ out << " <TH bgcolor=white>";
+ out << frameRef(getIdent() + "_Event_" + getEvent(event).getIdent() + ".html", "Status", "1", formatHTMLShorthand(getEvent(event).getShorthand()));
+ out << "</TH>" << endl;
+ }
+
+ out << "</TR>" << endl;
+
+ // -- Body of table
+ for(int state = 0; state < numStates(); state++ ) {
+ out << "<TR>" << endl;
+
+ // -- Each row
+ if (state == active_state) {
+ out << " <TH bgcolor=yellow>";
+ } else {
+ out << " <TH bgcolor=white>";
+ }
+
+ string click_href = getIdent() + "_table_" + getState(state).getIdent() + ".html";
+ string text = formatHTMLShorthand(getState(state).getShorthand());
+
+ out << frameRef(click_href, "Table", getIdent() + "_State_" + getState(state).getIdent() + ".html", "1", formatHTMLShorthand(getState(state).getShorthand()));
+ out << "</TH>" << endl;
+
+ // -- One column for each event
+ for(int event = 0; event < numEvents(); event++ ) {
+ const Transition* trans_ptr = getTransPtr(state, event);
+
+ if( trans_ptr != NULL ) {
+ bool stall_action = false;
+ string nextState;
+ string actions_str;
+
+ // -- Get the actions
+ // actions = trans_ptr->getActionShorthands();
+ const Vector<Action*> actions = trans_ptr->getActions();
+ for (int action=0; action < actions.size(); action++) {
+ if ((actions[action]->getIdent() == "z_stall") ||
+ (actions[action]->getIdent() == "zz_recycleMandatoryQueue")) {
+ stall_action = true;
+ }
+ actions_str += " ";
+ actions_str += frameRef(getIdent() + "_action_" + actions[action]->getIdent() + ".html", "Status", "1",
+ formatHTMLShorthand(actions[action]->getShorthand()));
+ actions_str += "\n";
+ }
+
+ // -- Get the next state
+ if (trans_ptr->getNextStatePtr()->getIdent() != getState(state).getIdent()) {
+ string click_href = getIdent() + "_table_" + trans_ptr->getNextStatePtr()->getIdent() + ".html";
+ nextState = frameRef(click_href, "Table", getIdent() + "_State_" + trans_ptr->getNextStatePtr()->getIdent() + ".html", "1",
+ formatHTMLShorthand(trans_ptr->getNextStateShorthand()));
+ } else {
+ nextState = "";
+ }
+
+ // -- Print out "actions/next-state"
+ if (stall_action) {
+ if (state == active_state) {
+ out << " <TD bgcolor=#C0C000>";
+ } else {
+ out << " <TD bgcolor=lightgrey>";
+ }
+ } else if (active_state < numStates() && (trans_ptr->getNextStatePtr()->getIdent() == getState(active_state).getIdent())) {
+ out << " <TD bgcolor=aqua>";
+ } else if (state == active_state) {
+ out << " <TD bgcolor=yellow>";
+ } else {
+ out << " <TD bgcolor=white>";
+ }
+
+ out << actions_str;
+ if ((nextState.length() != 0) && (actions_str.length() != 0)) {
+ out << "/";
+ }
+ out << nextState;
+ out << "</TD>" << endl;
+ } else {
+ // This is the no transition case
+ if (state == active_state) {
+ out << " <TD bgcolor=#C0C000>&nbsp;</TD>" << endl;
+ } else {
+ out << " <TD bgcolor=lightgrey>&nbsp;</TD>" << endl;
+ }
+ }
+ }
+ // -- Each row
+ if (state == active_state) {
+ out << " <TH bgcolor=yellow>";
+ } else {
+ out << " <TH bgcolor=white>";
+ }
+
+ click_href = getIdent() + "_table_" + getState(state).getIdent() + ".html";
+ text = formatHTMLShorthand(getState(state).getShorthand());
+
+ out << frameRef(click_href, "Table", getIdent() + "_State_" + getState(state).getIdent() + ".html", "1", formatHTMLShorthand(getState(state).getShorthand()));
+ out << "</TH>" << endl;
+
+ out << "</TR>" << endl;
+ }
+
+ // -- Column footer
+ out << "<TR>" << endl;
+ out << " <TH> </TH>" << endl;
+
+ for(int i = 0; i < numEvents(); i++ ) {
+ out << " <TH bgcolor=white>";
+ out << frameRef(getIdent() + "_Event_" + getEvent(i).getIdent() + ".html", "Status", "1", formatHTMLShorthand(getEvent(i).getShorthand()));
+ out << "</TH>" << endl;
+ }
+ out << "</TR>" << endl;
+
+ // -- Epilog
+ out << "</TABLE>" << endl;
+ out << "</BODY></HTML>" << endl;
+}
+
+