mem-ruby: able to define resource stalls handlers
authorTiago Mück <tiago.muck@arm.com>
Fri, 28 Feb 2020 21:32:00 +0000 (15:32 -0600)
committerTiago Mück <tiago.muck@arm.com>
Mon, 7 Dec 2020 19:53:43 +0000 (19:53 +0000)
Input ports can specify a custom handler that is called
on resource stalls. The handler should return 'true' to
indicate the stall was handled and new messages from that
queue can be processed on that cycle. When it returns
'false' or no handler is defined, a resource stall is
generated.

Handlers are defined using the 'rsc_stall_handler' (for
resource stalls) and the 'prot_stall_handler' (for
protocol stalls) parameters. For example:

in_port(mandatory_in, RubyRequest, mandatoryQueue,
        rsc_stall_handler=mandatory_in_stall_handler) {
    ...
}

bool mandatory_in_stall_handler() {
    // Do something here to handle the stall !
    return true;
    // or return false if we don't want to do anything
}

Note: this patch required a change to the generate()
functions interface in the SLICC compiler, so we
could propagate a reference to the in_port to the
appropriate generate() functions. The updated interface
allows passing and forwarding of keyword arguments.

Change-Id: I3481d130d5eb411e6760a54d098d3da5de511c86
Signed-off-by: Tiago Mück <tiago.muck@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31265
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
29 files changed:
src/mem/slicc/ast/AssignStatementAST.py
src/mem/slicc/ast/CheckAllocateStatementAST.py
src/mem/slicc/ast/CheckNextCycleAST.py
src/mem/slicc/ast/CheckProbeStatementAST.py
src/mem/slicc/ast/DeferEnqueueingStatementAST.py
src/mem/slicc/ast/EnqueueStatementAST.py
src/mem/slicc/ast/EnumExprAST.py
src/mem/slicc/ast/ExprAST.py
src/mem/slicc/ast/ExprStatementAST.py
src/mem/slicc/ast/FuncCallExprAST.py
src/mem/slicc/ast/FuncDeclAST.py
src/mem/slicc/ast/IfStatementAST.py
src/mem/slicc/ast/InPortDeclAST.py
src/mem/slicc/ast/IsValidPtrExprAST.py
src/mem/slicc/ast/LiteralExprAST.py
src/mem/slicc/ast/LocalVariableAST.py
src/mem/slicc/ast/MethodCallExprAST.py
src/mem/slicc/ast/NewExprAST.py
src/mem/slicc/ast/ObjDeclAST.py
src/mem/slicc/ast/OodAST.py
src/mem/slicc/ast/OperatorExprAST.py
src/mem/slicc/ast/PeekStatementAST.py
src/mem/slicc/ast/ReturnStatementAST.py
src/mem/slicc/ast/StallAndWaitStatementAST.py
src/mem/slicc/ast/StatementListAST.py
src/mem/slicc/ast/StaticCastAST.py
src/mem/slicc/ast/TypeFieldEnumAST.py
src/mem/slicc/ast/TypeFieldStateAST.py
src/mem/slicc/ast/VarExprAST.py

index b9597935452848a05fc9b8986e5b308744261658..d3e449d4e322458238457425099fbd2576163c29 100644 (file)
@@ -36,7 +36,7 @@ class AssignStatementAST(StatementAST):
     def __repr__(self):
         return "[AssignStatementAST: %r := %r]" % (self.lvalue, self.rvalue)
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         lcode = self.slicc.codeFormatter()
         rcode = self.slicc.codeFormatter()
 
index b96153b0a20b5edbfed1d17a5aad9a88d193665c..425e8053d71972e53c3c0e763722066d7877626d 100644 (file)
@@ -35,7 +35,7 @@ class CheckAllocateStatementAST(StatementAST):
     def __repr__(self):
         return "[CheckAllocateStatementAst: %r]" % self.variable
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         # FIXME - check the type of the variable
 
         # Make sure the variable is valid
index 5ca869d572fdf0ddb8c3bed4c417bee84a08c6b8..f3797755e8fc2b107e78053b2838cd0076bc1945 100644 (file)
@@ -35,6 +35,6 @@ class CheckNextCycleAST(StatementAST):
     def __repr__(self):
         return "[CheckNextCycleAST]"
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         code("scheduleEvent(Cycles(1));")
         return "CheckNextCycle"
index 53454635a50cab46bc4ac33a64a6ab0a83728357..0d84bbce43a650fd36300041cbb8397304a89612 100644 (file)
@@ -37,7 +37,7 @@ class CheckProbeStatementAST(StatementAST):
     def __repr__(self):
         return "[CheckProbeStatementAst: %r]" % self.in_port
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         self.in_port.assertType("InPort")
         self.address.assertType("Addr")
 
index 40b9a4c52712cfd3ea8c9946324fa4ae897a29b5..970483627324fc24d37feb38b38fff0b64269c85 100644 (file)
@@ -48,7 +48,7 @@ class DeferEnqueueingStatementAST(StatementAST):
         return "[DeferEnqueueingStatementAst: %s %s %s]" % \
                (self.queue_name, self.type_ast.ident, self.statements)
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         code("{")
         code.indent()
         self.symtab.pushFrame()
index 556643e4eba22f31bd5fb28b7a663456c630d233..a8c157e426855234964dd8c51d0bf93e46767c4d 100644 (file)
@@ -42,7 +42,7 @@ class EnqueueStatementAST(StatementAST):
         return "[EnqueueStatementAst: %s %s %s]" % \
                (self.queue_name, self.type_ast.ident, self.statements)
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         code("{")
         code.indent()
         self.symtab.pushFrame()
index 9cb76a8a19480f200ff0bb5c048e6660225065e6..27da269e904d860ac81129c0ce3f63878fa4ab7d 100644 (file)
@@ -40,7 +40,7 @@ class EnumExprAST(ExprAST):
     def __repr__(self):
         return "[EnumExpr: %s:%s]" % (self.type_ast, self.value)
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         fix = code.nofix()
         code('${{self.type_ast.type.c_ident}}_${{self.value}}')
         code.fix(fix)
index 393101112d3745950e764ec36e6a1d5584f6ee22..75554b2d3f94eacda0a51ed8072bfdfb58b08533 100644 (file)
@@ -34,9 +34,9 @@ class ExprAST(AST):
         # The default is no resources
         pass
 
-    def inline(self, get_type=False):
+    def inline(self, get_type=False, **kwargs):
         code = self.slicc.codeFormatter(fix_newlines=False)
-        return_type = self.generate(code)
+        return_type = self.generate(code, **kwargs)
         if get_type:
             return return_type, code
         else:
index 6c77522c78f8c2e637767febc62a46ceb2ed6b7f..7189df04010a7afe730caa49d01e46d1344facc2 100644 (file)
@@ -38,8 +38,8 @@ class ExprStatementAST(StatementAST):
     def __repr__(self):
         return "[ExprStatementAST: %s]" % (self.expr)
 
-    def generate(self, code, return_type):
-        actual_type,rcode = self.expr.inline(True)
+    def generate(self, code, return_type, **kwargs):
+        actual_type,rcode = self.expr.inline(True, **kwargs)
         code("$rcode;")
 
         # The return type must be void, except for local var decls
index b3cc9f1ec872ba0797e3de5a61deb8e5664c317a..d93ee04e9620c4789e1e20a248e756b9213e40f8 100644 (file)
@@ -1,3 +1,15 @@
+# Copyright (c) 2020 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 # Copyright (c) 2009 The Hewlett-Packard Development Company
 # Copyright (c) 2013 Advanced Micro Devices, Inc.
@@ -38,7 +50,9 @@ class FuncCallExprAST(ExprAST):
     def __repr__(self):
         return "[FuncCallExpr: %s %s]" % (self.proc_name, self.exprs)
 
-    def generate(self, code):
+    # When calling generate for statements in a in_port, the reference to
+    # the port must be provided as the in_port kwarg (see InPortDeclAST)
+    def generate(self, code, **kwargs):
         machine = self.state_machine
 
         if self.proc_name == "DPRINTF":
@@ -148,18 +162,53 @@ class FuncCallExprAST(ExprAST):
     TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[1]}});
 ''')
 
+            assert('in_port' in kwargs)
+            in_port = kwargs['in_port']
+
             code('''
     if (result == TransitionResult_Valid) {
         counter++;
         continue; // Check the first port again
-    }
-
-    if (result == TransitionResult_ResourceStall ||
-        result == TransitionResult_ProtocolStall) {
+    } else if (result == TransitionResult_ResourceStall) {
+''')
+            if 'rsc_stall_handler' in in_port.pairs:
+                stall_func_name = in_port.pairs['rsc_stall_handler']
+                code('''
+        if (${{stall_func_name}}()) {
+            counter++;
+            continue; // Check the first port again
+        } else {
+            scheduleEvent(Cycles(1));
+            // Cannot do anything with this transition, go check next doable transition (mostly likely of next port)
+        }
+''')
+            else:
+                code('''
         scheduleEvent(Cycles(1));
-
         // Cannot do anything with this transition, go check next doable transition (mostly likely of next port)
+''')
+            code('''
+    } else if (result == TransitionResult_ProtocolStall) {
+''')
+            if 'prot_stall_handler' in in_port.pairs:
+                stall_func_name = in_port.pairs['prot_stall_handler']
+                code('''
+        if (${{stall_func_name}}()) {
+            counter++;
+            continue; // Check the first port again
+        } else {
+            scheduleEvent(Cycles(1));
+            // Cannot do anything with this transition, go check next doable transition (mostly likely of next port)
+        }
+''')
+            else:
+                code('''
+        scheduleEvent(Cycles(1));
+        // Cannot do anything with this transition, go check next doable transition (mostly likely of next port)
+''')
+            code('''
     }
+
 }
 ''')
         elif self.proc_name == "error":
index 47ae7076ef3ce74f8b6463854d152f7a1dcb6bad..675c4081345e3021040bee0f7ac705882f72507e 100644 (file)
@@ -43,7 +43,7 @@ class FuncDeclAST(DeclAST):
     def files(self, parent=None):
         return set()
 
-    def generate(self, parent = None):
+    def generate(self, parent = None, **kwargs):
         types = []
         params = []
         void_type = self.symtab.find("void", Type)
index 3ad3d182d7abd40cbb2d32c1e83ef76999ff81db..2ddd7c052523a5bb343fff0140a648e6340b7d06 100644 (file)
@@ -42,7 +42,7 @@ class IfStatementAST(StatementAST):
     def __repr__(self):
         return "[IfStatement: %r%r%r]" % (self.cond, self.then, self.else_)
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         cond_code = self.slicc.codeFormatter()
         cond_type = self.cond.generate(cond_code)
 
@@ -56,7 +56,7 @@ class IfStatementAST(StatementAST):
         # Then part
         code.indent()
         self.symtab.pushFrame()
-        self.then.generate(code, return_type)
+        self.then.generate(code, return_type, **kwargs)
         self.symtab.popFrame()
         code.dedent()
         # Else part
@@ -64,7 +64,7 @@ class IfStatementAST(StatementAST):
             code('} else {')
             code.indent()
             self.symtab.pushFrame()
-            self.else_.generate(code, return_type)
+            self.else_.generate(code, return_type, **kwargs)
             self.symtab.popFrame()
             code.dedent()
         code('}') # End scope
index e0aa25236ea1a96dff280e73095a4822e8d7114c..8e80b6ad1c74e53489abdb63d8a77fb25ce6f113 100644 (file)
@@ -1,3 +1,15 @@
+# Copyright (c) 2020 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 # Copyright (c) 2009 The Hewlett-Packard Development Company
 # All rights reserved.
@@ -118,7 +130,7 @@ class InPortDeclAST(DeclAST):
             rcode = self.slicc.codeFormatter()
             rcode.indent()
             rcode.indent()
-            self.statements.generate(rcode, None)
+            self.statements.generate(rcode, None, in_port=in_port)
             in_port["c_code_in_port"] = str(rcode)
 
         symtab.popFrame()
index e68e084c051b6c1aeb274aa0e000fdd705df9f0b..a7d89a9b836cf3a7b58005663bfe66f7fbae003e 100644 (file)
@@ -38,7 +38,7 @@ class IsValidPtrExprAST(ExprAST):
     def __repr__(self):
         return "[IsValidPtrExprAST: %r]" % self.variable
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         # Make sure the variable is valid
         fix = code.nofix()
         code("(")
index 6d259c17f93d2cf389caa35aab4a9b6df345bd07..59756b173fc183ed919defda0b4f5ea0da48d413 100644 (file)
@@ -37,7 +37,7 @@ class LiteralExprAST(ExprAST):
     def __repr__(self):
         return "[Literal: %s]" % self.literal
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         fix = code.nofix()
         if self.type == "std::string":
             code('("${{self.literal}}")')
index c1a5fdbd968d9cfd94aa768bdd179291451316e6..da75477c897c47312abe3f60e01aed90d95843af 100644 (file)
@@ -52,7 +52,7 @@ class LocalVariableAST(StatementAST):
         else:
             return code
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         type = self.type_ast.type;
         ident = "%s" % self.ident;
 
index 102ab6e4c99006d9e5a5d61727af7ce2f25a4598..9908fc815c641d88d9e36cd3f1a86cd9c0fb9c88 100644 (file)
@@ -33,7 +33,7 @@ class MethodCallExprAST(ExprAST):
         self.proc_name = proc_name
         self.expr_ast_vec = expr_ast_vec
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         tmp = self.slicc.codeFormatter()
         paramTypes = []
         for expr_ast in self.expr_ast_vec:
index a423507683e4dd6d68c3c5f449192d2b8c807995..2f33bfac35dd4ea1a0081f5ddc417896237d2228 100644 (file)
@@ -39,7 +39,7 @@ class NewExprAST(ExprAST):
     def name(self):
         return str(self.type_ast)
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         type = self.type_ast.type
         fix = code.nofix()
         code("new ${{type.c_ident}}")
index efc7ef928099c51339173d1df9bc4f3b975a7c32..523a491abcc24e49f57dec8f76a8994842914b4e 100644 (file)
@@ -40,7 +40,7 @@ class ObjDeclAST(DeclAST):
     def __repr__(self):
         return "[ObjDecl: %r]" % self.ident
 
-    def generate(self, parent = None):
+    def generate(self, parent = None, **kwargs):
         if "network" in self and not ("virtual_network" in self or
                                       "physical_network" in self) :
             self.error("Network queues require a 'virtual_network' attribute")
index 0f4cf141c47439aad085b847b4d8338c5d9a8c96..173a1566e2e0a53b04ccce3b9a85c1b9746950fc 100644 (file)
@@ -35,6 +35,6 @@ class OodAST(ExprAST):
     def __repr__(self):
         return "[Ood:]"
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         code += "NULL"
         return "OOD"
index cab13692c03d2bbafca90df666e0a74be5450f7b..5c5ea834f083e7762975885e7136cecbdd552e2e 100644 (file)
@@ -39,7 +39,7 @@ class InfixOperatorExprAST(ExprAST):
     def __repr__(self):
         return "[InfixExpr: %r %s %r]" % (self.left, self.op, self.right)
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         lcode = self.slicc.codeFormatter()
         rcode = self.slicc.codeFormatter()
 
@@ -104,7 +104,7 @@ class PrefixOperatorExprAST(ExprAST):
     def __repr__(self):
         return "[PrefixExpr: %s %r]" % (self.op, self.operand)
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         opcode = self.slicc.codeFormatter()
         optype = self.operand.generate(opcode)
 
index 20e514010272c9c6fafe6ee59d96eb3bae3c3231..2ad182ff4f2585ed64e62fc96b56405962ab9f55 100644 (file)
@@ -42,7 +42,7 @@ class PeekStatementAST(StatementAST):
         return "[PeekStatementAST: %r queue_name: %r type: %r %r]" % \
                (self.method, self.queue_name, self.type_ast, self.statements)
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         self.symtab.pushFrame()
 
         msg_type = self.type_ast.type
@@ -91,7 +91,7 @@ class PeekStatementAST(StatementAST):
             ''')
 
         # The other statements
-        self.statements.generate(code, return_type)
+        self.statements.generate(code, return_type, **kwargs)
         self.symtab.popFrame()
         code("}")
 
index 754bb4c9fd7b24a6d44ffa2e8341d66a342426ae..415d442c7d69b9c4b2ef47e01d40156171d7b405 100644 (file)
@@ -36,7 +36,7 @@ class ReturnStatementAST(StatementAST):
     def __repr__(self):
         return "[ReturnStatementAST: %r]" % self.expr_ast
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         actual_type, ecode = self.expr_ast.inline(True)
         code('return $ecode;')
 
index ad261e26f34e8fcc2d0b610bba1d2eed32eea99a..04d9e20ed02eb39d40dff2e9fd648d3080c2ca37 100644 (file)
@@ -37,7 +37,7 @@ class StallAndWaitStatementAST(StatementAST):
     def __repr__(self):
         return "[StallAndWaitStatementAst: %r]" % self.in_port
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         self.in_port.assertType("InPort")
         self.address.assertType("Addr")
 
index 1475c5c977a7501229f3d96b345d7f802d608bf7..9d74e66dc337d70d3adb03c3200fb93240d62d8e 100644 (file)
@@ -37,9 +37,9 @@ class StatementListAST(AST):
     def __repr__(self):
         return "[StatementListAST: %r]" % self.statements
 
-    def generate(self, code, return_type):
+    def generate(self, code, return_type, **kwargs):
         for statement in self.statements:
-            statement.generate(code, return_type)
+            statement.generate(code, return_type, **kwargs)
 
     def findResources(self, resources):
         for statement in self.statements:
index 71280ba67adda51604f9e9f14d9b58fa6e2276b0..4c664865a1ebc4bf036bb74eb3aedeb7a062e8ae 100644 (file)
@@ -37,7 +37,7 @@ class StaticCastAST(ExprAST):
     def __repr__(self):
         return "[StaticCastAST: %r]" % self.expr_ast
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         actual_type, ecode = self.expr_ast.inline(True)
         if self.type_modifier == "pointer":
             code('static_cast<${{self.type_ast.type.c_ident}} *>($ecode)')
index b9a8ae80fc9e4c62c0b43528f9e38a113b67665b..f554990579224943c9a46d21398553cf757cd313 100644 (file)
@@ -38,7 +38,7 @@ class TypeFieldEnumAST(TypeFieldAST):
     def __repr__(self):
         return "[TypeFieldEnum: %r]" % self.field_id
 
-    def generate(self, type):
+    def generate(self, type, **kwargs):
         if str(type) == "State":
             self.error("States must in a State Declaration, not a normal enum.")
 
index deac143bb93a01193cdb8bf3e080c9c0805d7f14..ff1ae9720a22b5859c3ddb1c41877a22177e0923 100644 (file)
@@ -40,7 +40,7 @@ class TypeFieldStateAST(TypeFieldAST):
     def __repr__(self):
         return "[TypeFieldState: %r]" % self.field_id
 
-    def generate(self, type):
+    def generate(self, type, **kwargs):
         if not str(type) == "State":
             self.error("State Declaration must be of type State.")
 
index 19a619b370851604a2ccd84c767316e021104419..f555c72d14298ca2ef1233583afd0d1587c6ade2 100644 (file)
@@ -60,7 +60,7 @@ class VarExprAST(ExprAST):
                        "'%s' is expected to be type '%s' not '%s'",
                        self.var.ident, expected_type, self.var.type)
 
-    def generate(self, code):
+    def generate(self, code, **kwargs):
         fix = code.nofix()
         code("${{self.var.code}}")
         code.fix(fix)