mem-ruby: able to define resource stalls handlers

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>
This commit is contained in:
Tiago Mück
2020-02-28 15:32:00 -06:00
parent ca29eef37e
commit 4e2216d68b
29 changed files with 102 additions and 41 deletions

View 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()

View 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

View 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"

View 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")

View 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()

View 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()

View 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)

View 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:

View 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

View 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":

View 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)

View 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

View 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()

View 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("(")

View 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}}")')

View 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;

View 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:

View 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}}")

View 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")

View 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"

View 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)

View 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("}")

View 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;')

View 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")

View 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:

View 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)')

View 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.")

View 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.")

View 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)