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:
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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("(")
|
||||
|
||||
@@ -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}}")')
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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}}")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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("}")
|
||||
|
||||
|
||||
@@ -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;')
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)')
|
||||
|
||||
@@ -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.")
|
||||
|
||||
|
||||
@@ -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.")
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user