slicc: support for transitions with a wildcard next state
authorDavid Hashe <david.hashe@amd.com>
Mon, 20 Jul 2015 14:15:18 +0000 (09:15 -0500)
committerDavid Hashe <david.hashe@amd.com>
Mon, 20 Jul 2015 14:15:18 +0000 (09:15 -0500)
This patches adds support for transitions of the form:

transition(START, EVENTS, *) { ACTIONS }

This allows a machine to collapse states that differ only in the next state
transition to collapse into one, and can help shorten/simplfy some protocols
significantly.

When * is encountered as an end state of a transition, the next state is
determined by calling the machine-specific getNextState function. The next
state is determined before any actions of the transition execute, and
therefore the next state calculation cannot depend on any of the transition
actions.

src/mem/slicc/parser.py
src/mem/slicc/symbols/State.py
src/mem/slicc/symbols/StateMachine.py
src/mem/slicc/symbols/Transition.py

index 10dd99ecefd2e6c71e6d791a270e79712a61f117..1ce8bf1bd4511b8c68d08fa40b0e0c9d04a4456e 100644 (file)
@@ -278,7 +278,7 @@ class SLICC(Grammar):
         p[0] = ast.OutPortDeclAST(self, p[3], p[5], p[7], p[8])
 
     def p_decl__trans0(self, p):
-        "decl : TRANS '(' idents ',' idents ',' ident ')' idents"
+        "decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents"
         p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], p[7], p[9])
 
     def p_decl__trans1(self, p):
@@ -286,7 +286,7 @@ class SLICC(Grammar):
         p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], None, p[7])
 
     def p_decl__trans2(self, p):
-        "decl : TRANS '(' idents ',' idents ',' ident ')' idents idents"
+        "decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents idents"
         p[0] = ast.TransitionDeclAST(self, p[9], p[3], p[5], p[7], p[10])
 
     def p_decl__trans3(self, p):
@@ -506,6 +506,11 @@ class SLICC(Grammar):
         "ident : IDENT"
         p[0] = p[1]
 
+    def p_ident_or_star(self, p):
+        """ident_or_star : ident
+                         | STAR"""
+        p[0] = p[1]
+
     # Pair and pair lists
     def p_pairs__list(self, p):
         "pairs : ',' pairsx"
index 1236932564c5dda97885f90e36f4f0273bbfc930..164c585f6cddb86b6cba429c38b042916ae42020 100644 (file)
@@ -30,5 +30,13 @@ from slicc.symbols.Symbol import Symbol
 class State(Symbol):
     def __repr__(self):
         return "[State: %s]" % self.ident
+    def isWildcard(self):
+        return False
+
+class WildcardState(State):
+    def __repr__(self):
+        return "[State: *]"
+    def isWildcard(self):
+        return True
 
 __all__ = [ "State" ]
index 174d66e0fbd1f1e3ed47399676855fd9bb6f190b..8a4d7d9b541eff5c5c59c05a8e26ae59c12163a1 100644 (file)
@@ -1310,8 +1310,17 @@ ${ident}_Controller::doTransitionWorker(${ident}_Event event,
             case = self.symtab.codeFormatter()
             # Only set next_state if it changes
             if trans.state != trans.nextState:
-                ns_ident = trans.nextState.ident
-                case('next_state = ${ident}_State_${ns_ident};')
+                if trans.nextState.isWildcard():
+                    # When * is encountered as an end state of a transition,
+                    # the next state is determined by calling the
+                    # machine-specific getNextState function. The next state
+                    # is determined before any actions of the transition
+                    # execute, and therefore the next state calculation cannot
+                    # depend on any of the transitionactions.
+                    case('next_state = getNextState(addr);')
+                else:
+                    ns_ident = trans.nextState.ident
+                    case('next_state = ${ident}_State_${ns_ident};')
 
             actions = trans.actions
             request_types = trans.request_types
index 901d4a0e8714d86b03f3e7702fe37de7979b6cb1..9ecd6c54bd51d7b9f5e09c40fd4906d825a8ba39 100644 (file)
@@ -26,6 +26,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 from slicc.symbols.Symbol import Symbol
+from slicc.symbols.State import WildcardState
 
 class Transition(Symbol):
     def __init__(self, table, machine, state, event, nextState, actions,
@@ -35,7 +36,19 @@ class Transition(Symbol):
 
         self.state = machine.states[state]
         self.event = machine.events[event]
-        self.nextState = machine.states[nextState]
+        if nextState == '*':
+            # check to make sure there is a getNextState function declared
+            found = False
+            for func in machine.functions:
+                if func.c_ident == 'getNextState':
+                    found = True
+                    break
+            if found == False:
+                fatal("Machine uses a wildcard transition without getNextState defined")
+            self.nextState = WildcardState(machine.symtab,
+                                           '*', location)
+        else:
+            self.nextState = machine.states[nextState]
         self.actions = [ machine.actions[a] for a in actions ]
         self.request_types = [ machine.request_types[s] for s in request_types ]
         self.resources = {}