summaryrefslogtreecommitdiff
path: root/src/mem/slicc
diff options
context:
space:
mode:
authorNilay Vaish <nilay@cs.wisc.edu>2011-01-17 18:46:16 -0600
committerNilay Vaish <nilay@cs.wisc.edu>2011-01-17 18:46:16 -0600
commitc82a8979a3909037a1654fc66cb215b5bacadb08 (patch)
treeb0b51c589c665812df1ec8eb1c40adfc98877f08 /src/mem/slicc
parent6fb521faba37a47ebce2aebb08ac34bd69d29f13 (diff)
downloadgem5-c82a8979a3909037a1654fc66cb215b5bacadb08.tar.xz
Change interface between coherence protocols and CacheMemory
The purpose of this patch is to change the way CacheMemory interfaces with coherence protocols. Currently, whenever a cache controller (defined in the protocol under consideration) needs to carry out any operation on a cache block, it looks up the tag hash map and figures out whether or not the block exists in the cache. In case it does exist, the operation is carried out (which requires another lookup). As observed through profiling of different protocols, multiple such lookups take place for a given cache block. It was noted that the tag lookup takes anything from 10% to 20% of the simulation time. In order to reduce this time, this patch is being posted. I have to acknowledge that the many of the thoughts that went in to this patch belong to Brad. Changes to CacheMemory, TBETable and AbstractCacheEntry classes: 1. The lookup function belonging to CacheMemory class now returns a pointer to a cache block entry, instead of a reference. The pointer is NULL in case the block being looked up is not present in the cache. Similar change has been carried out in the lookup function of the TBETable class. 2. Function for setting and getting access permission of a cache block have been moved from CacheMemory class to AbstractCacheEntry class. 3. The allocate function in CacheMemory class now returns pointer to the allocated cache entry. Changes to SLICC: 1. Each action now has implicit variables - cache_entry and tbe. cache_entry, if != NULL, must point to the cache entry for the address on which the action is being carried out. Similarly, tbe should also point to the transaction buffer entry of the address on which the action is being carried out. 2. If a cache entry or a transaction buffer entry is passed on as an argument to a function, it is presumed that a pointer is being passed on. 3. The cache entry and the tbe pointers received __implicitly__ by the actions, are passed __explicitly__ to the trigger function. 4. While performing an action, set/unset_cache_entry, set/unset_tbe are to be used for setting / unsetting cache entry and tbe pointers respectively. 5. is_valid() and is_invalid() has been made available for testing whether a given pointer 'is not NULL' and 'is NULL' respectively. 6. Local variables are now available, but they are assumed to be pointers always. 7. It is now possible for an object of the derieved class to make calls to a function defined in the interface. 8. An OOD token has been introduced in SLICC. It is same as the NULL token used in C/C++. If you are wondering, OOD stands for Out Of Domain. 9. static_cast can now taken an optional parameter that asks for casting the given variable to a pointer of the given type. 10. Functions can be annotated with 'return_by_pointer=yes' to return a pointer. 11. StateMachine has two new variables, EntryType and TBEType. EntryType is set to the type which inherits from 'AbstractCacheEntry'. There can only be one such type in the machine. TBEType is set to the type for which 'TBE' is used as the name. All the protocols have been modified to conform with the new interface.
Diffstat (limited to 'src/mem/slicc')
-rw-r--r--src/mem/slicc/ast/ActionDeclAST.py19
-rw-r--r--src/mem/slicc/ast/FormalParamAST.py16
-rw-r--r--src/mem/slicc/ast/FuncCallExprAST.py53
-rw-r--r--src/mem/slicc/ast/IfStatementAST.py4
-rw-r--r--src/mem/slicc/ast/InPortDeclAST.py14
-rw-r--r--src/mem/slicc/ast/IsValidPtrExprAST.py53
-rw-r--r--src/mem/slicc/ast/LocalVariableAST.py54
-rw-r--r--src/mem/slicc/ast/MethodCallExprAST.py95
-rw-r--r--src/mem/slicc/ast/OodAST.py40
-rw-r--r--src/mem/slicc/ast/ReturnStatementAST.py2
-rw-r--r--src/mem/slicc/ast/StaticCastAST.py8
-rw-r--r--src/mem/slicc/ast/TypeDeclAST.py5
-rw-r--r--src/mem/slicc/ast/__init__.py3
-rw-r--r--src/mem/slicc/parser.py25
-rw-r--r--src/mem/slicc/symbols/Func.py4
-rw-r--r--src/mem/slicc/symbols/StateMachine.py241
16 files changed, 565 insertions, 71 deletions
diff --git a/src/mem/slicc/ast/ActionDeclAST.py b/src/mem/slicc/ast/ActionDeclAST.py
index e85aa25b8..2a8fb0639 100644
--- a/src/mem/slicc/ast/ActionDeclAST.py
+++ b/src/mem/slicc/ast/ActionDeclAST.py
@@ -39,6 +39,11 @@ class ActionDeclAST(DeclAST):
def generate(self):
resources = {}
+
+ machine = self.symtab.state_machine
+ if machine is None:
+ self.error("Action declaration not part of a machine.")
+
if self.statement_list:
# Add new local vars
self.symtab.pushFrame()
@@ -52,6 +57,16 @@ class ActionDeclAST(DeclAST):
"addr", self.pairs)
self.symtab.newSymbol(var)
+ if machine.TBEType != None:
+ var = Var(self.symtab, "tbe", self.location, machine.TBEType,
+ "(*m_tbe_ptr)", self.pairs)
+ self.symtab.newSymbol(var)
+
+ if machine.EntryType != None:
+ var = Var(self.symtab, "cache_entry", self.location,
+ machine.EntryType, "(*m_cache_entry_ptr)", self.pairs)
+ self.symtab.newSymbol(var)
+
# Do not allows returns in actions
code = self.slicc.codeFormatter()
self.statement_list.generate(code, None)
@@ -61,10 +76,6 @@ class ActionDeclAST(DeclAST):
self.symtab.popFrame()
- machine = self.symtab.state_machine
- if machine is None:
- self.error("Action declaration not part of a machine.")
-
action = Action(self.symtab, self.ident, resources, self.location,
self.pairs)
machine.addAction(action)
diff --git a/src/mem/slicc/ast/FormalParamAST.py b/src/mem/slicc/ast/FormalParamAST.py
index c64731196..142e837cc 100644
--- a/src/mem/slicc/ast/FormalParamAST.py
+++ b/src/mem/slicc/ast/FormalParamAST.py
@@ -48,7 +48,17 @@ class FormalParamAST(AST):
param = "param_%s" % self.ident
# Add to symbol table
- v = Var(self.symtab, self.ident, self.location, type, param,
- self.pairs)
- self.symtab.newSymbol(v)
+ if self.pointer or str(type) == "TBE" or (
+ "interface" in type and type["interface"] == "AbstractCacheEntry"):
+
+ v = Var(self.symtab, self.ident, self.location, type,
+ "(*%s)" % param, self.pairs)
+ self.symtab.newSymbol(v)
+ return type, "%s* %s" % (type.c_ident, param)
+
+ else:
+ v = Var(self.symtab, self.ident, self.location, type, param,
+ self.pairs)
+ self.symtab.newSymbol(v)
+
return type, "%s %s" % (type.c_ident, param)
diff --git a/src/mem/slicc/ast/FuncCallExprAST.py b/src/mem/slicc/ast/FuncCallExprAST.py
index 829203d53..2c5e9ea4d 100644
--- a/src/mem/slicc/ast/FuncCallExprAST.py
+++ b/src/mem/slicc/ast/FuncCallExprAST.py
@@ -89,6 +89,7 @@ class FuncCallExprAST(ExprAST):
len(func.param_types), len(self.exprs))
cvec = []
+ type_vec = []
for expr,expected_type in zip(self.exprs, func.param_types):
# Check the types of the parameter
actual_type,param_code = expr.inline(True)
@@ -96,6 +97,7 @@ class FuncCallExprAST(ExprAST):
expr.error("Type mismatch: expected: %s actual: %s" % \
(expected_type, actual_type))
cvec.append(param_code)
+ type_vec.append(expected_type)
# OK, the semantics of "trigger" here is that, ports in the
# machine have different priorities. We always check the first
@@ -115,8 +117,25 @@ class FuncCallExprAST(ExprAST):
code('''
{
Address addr = ${{cvec[1]}};
- TransitionResult result = doTransition(${{cvec[0]}}, ${machine}_getState(addr), addr);
+''')
+ if machine.TBEType != None and machine.EntryType != None:
+ code('''
+ TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, ${{cvec[3]}}, addr);
+''')
+ elif machine.TBEType != None:
+ code('''
+ TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr);
+''')
+ elif machine.EntryType != None:
+ code('''
+ TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr);
+''')
+ else:
+ code('''
+ TransitionResult result = doTransition(${{cvec[0]}}, addr);
+''')
+ code('''
if (result == TransitionResult_Valid) {
counter++;
continue; // Check the first port again
@@ -175,6 +194,16 @@ if (!(${{cvec[0]}})) {
elif self.proc_name == "continueProcessing":
code("counter++;")
code("continue; // Check the first port again")
+
+ elif self.proc_name == "set_cache_entry":
+ code("set_cache_entry(m_cache_entry_ptr, %s);" %(cvec[0]));
+ elif self.proc_name == "unset_cache_entry":
+ code("unset_cache_entry(m_cache_entry_ptr);");
+ elif self.proc_name == "set_tbe":
+ code("set_tbe(m_tbe_ptr, %s);" %(cvec[0]));
+ elif self.proc_name == "unset_tbe":
+ code("unset_tbe(m_tbe_ptr);");
+
else:
# Normal function
@@ -184,7 +213,27 @@ if (!(${{cvec[0]}})) {
if "external" not in func and not func.isInternalMachineFunc:
internal = "m_chip_ptr->"
- params = ', '.join(str(c) for c in cvec)
+ params = ""
+ first_param = True
+
+ for (param_code, type) in zip(cvec, type_vec):
+ if str(type) == "TBE" or ("interface" in type and
+ type["interface"] == "AbstractCacheEntry"):
+
+ if first_param:
+ params = str(param_code).replace('*','')
+ first_param = False
+ else:
+ params += ', '
+ params += str(param_code).replace('*','');
+ else:
+ if first_param:
+ params = str(param_code)
+ first_param = False
+ else:
+ params += ', '
+ params += str(param_code);
+
fix = code.nofix()
code('(${internal}${{func.c_ident}}($params))')
code.fix(fix)
diff --git a/src/mem/slicc/ast/IfStatementAST.py b/src/mem/slicc/ast/IfStatementAST.py
index 359173203..0e023195c 100644
--- a/src/mem/slicc/ast/IfStatementAST.py
+++ b/src/mem/slicc/ast/IfStatementAST.py
@@ -55,13 +55,17 @@ class IfStatementAST(StatementAST):
code('if ($cond_code) {')
# Then part
code.indent()
+ self.symtab.pushFrame()
self.then.generate(code, return_type)
+ self.symtab.popFrame()
code.dedent()
# Else part
if self.else_:
code('} else {')
code.indent()
+ self.symtab.pushFrame()
self.else_.generate(code, return_type)
+ self.symtab.popFrame()
code.dedent()
code('}') # End scope
diff --git a/src/mem/slicc/ast/InPortDeclAST.py b/src/mem/slicc/ast/InPortDeclAST.py
index 5aa27bae8..c6fadb9e7 100644
--- a/src/mem/slicc/ast/InPortDeclAST.py
+++ b/src/mem/slicc/ast/InPortDeclAST.py
@@ -51,6 +51,10 @@ class InPortDeclAST(DeclAST):
symtab = self.symtab
void_type = symtab.find("void", Type)
+ machine = symtab.state_machine
+ if machine is None:
+ self.error("InPort declaration not part of a machine.")
+
code = self.slicc.codeFormatter()
queue_type = self.var_expr.generate(code)
if not queue_type.isInPort:
@@ -79,6 +83,11 @@ class InPortDeclAST(DeclAST):
param_types.append(type)
+ if machine.EntryType != None:
+ param_types.append(machine.EntryType)
+ if machine.TBEType != None:
+ param_types.append(machine.TBEType)
+
# Add the trigger method - FIXME, this is a bit dirty
pairs = { "external" : "yes" }
func = Func(self.symtab, "trigger", self.location, void_type,
@@ -123,13 +132,10 @@ class InPortDeclAST(DeclAST):
rcode.indent()
self.statements.generate(rcode, None)
in_port["c_code_in_port"] = str(rcode)
+
symtab.popFrame()
# Add port to state machine
- machine = symtab.state_machine
- if machine is None:
- self.error("InPort declaration not part of a machine.")
-
machine.addInPort(in_port)
# Include max_rank to be used by StateMachine.py
diff --git a/src/mem/slicc/ast/IsValidPtrExprAST.py b/src/mem/slicc/ast/IsValidPtrExprAST.py
new file mode 100644
index 000000000..850f45e96
--- /dev/null
+++ b/src/mem/slicc/ast/IsValidPtrExprAST.py
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2011 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.
+#
+
+from slicc.ast.ExprAST import ExprAST
+from slicc.symbols import Type
+
+class IsValidPtrExprAST(ExprAST):
+ def __init__(self, slicc, variable, flag):
+ super(IsValidPtrExprAST, self).__init__(slicc)
+ self.variable = variable
+ self.flag = flag
+
+ def __repr__(self):
+ return "[IsValidPtrExprAST: %r]" % self.variable
+
+ def generate(self, code):
+ # Make sure the variable is valid
+ fix = code.nofix()
+ code("(")
+ var_type, var_code = self.variable.inline(True);
+ var_code_str = str(var_code).replace('*','')
+ if self.flag:
+ code("${var_code_str} != NULL)")
+ else:
+ code("${var_code_str} == NULL)")
+ code.fix(fix)
+ type = self.symtab.find("bool", Type)
+ return type
diff --git a/src/mem/slicc/ast/LocalVariableAST.py b/src/mem/slicc/ast/LocalVariableAST.py
new file mode 100644
index 000000000..82e73ba7a
--- /dev/null
+++ b/src/mem/slicc/ast/LocalVariableAST.py
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2011 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.
+#
+
+from slicc.ast.StatementAST import StatementAST
+from slicc.symbols import Var
+
+class LocalVariableAST(StatementAST):
+ def __init__(self, slicc, type_ast, ident):
+ super(LocalVariableAST, self).__init__(slicc)
+ self.type_ast = type_ast
+ self.ident = ident
+
+ def __repr__(self):
+ return "[LocalVariableAST: %r %r]" % (self.type_ast, self.ident)
+
+ @property
+ def name(self):
+ return self.var_name
+
+ def generate(self, code):
+ type = self.type_ast.type;
+ ident = "%s" % self.ident;
+
+ # Add to symbol table
+ v = Var(self.symtab, self.ident, self.location, type, ident,
+ self.pairs)
+ self.symtab.newSymbol(v)
+ code += "%s* %s" % (type.c_ident, ident)
+ return type
diff --git a/src/mem/slicc/ast/MethodCallExprAST.py b/src/mem/slicc/ast/MethodCallExprAST.py
index 84009c076..6a2977533 100644
--- a/src/mem/slicc/ast/MethodCallExprAST.py
+++ b/src/mem/slicc/ast/MethodCallExprAST.py
@@ -97,48 +97,67 @@ class MemberMethodCallExprAST(MethodCallExprAST):
prefix = ""
implements_interface = False
- if methodId not in obj_type.methods:
- #
- # The initial method check has failed, but before generating an
- # error we must check whether any of the paramTypes implement
- # an interface. If so, we must check if the method ids using
- # the inherited types exist.
- #
- # This code is a temporary fix and only checks for the methodId
- # where all paramTypes are converted to their inherited type. The
- # right way to do this is to replace slicc's simple string
- # comparison for determining the correct overloaded method, with a
- # more robust param by param check.
+
+ if methodId in obj_type.methods:
+ return_type = obj_type.methods[methodId].return_type
+
+ else:
#
- implemented_paramTypes = []
- for paramType in paramTypes:
- implemented_paramType = paramType
- if paramType.isInterface:
- implements_interface = True
- implemented_paramType.abstract_ident = paramType["interface"]
+ # Check whether the method is implemented by the super class
+ if "interface" in obj_type:
+ interface_type = self.symtab.find(obj_type["interface"]);
+
+ if methodId in interface_type.methods:
+ return_type = interface_type.methods[methodId].return_type
+ obj_type = interface_type
+
else:
- implemented_paramType.abstract_ident = paramType.c_ident
-
- implemented_paramTypes.append(implemented_paramType)
+ self.error("Invalid method call: " \
+ "Type '%s' does not have a method %s, '%s'",
+ obj_type, self.proc_name, methodId)
- if implements_interface:
- implementedMethodId = obj_type.methodIdAbstract(self.proc_name,
- implemented_paramTypes)
else:
- implementedMethodId = ""
-
- if implementedMethodId not in obj_type.methods:
- self.error("Invalid method call: " \
- "Type '%s' does not have a method '%s' nor '%s'",
- obj_type, methodId, implementedMethodId)
- else:
- #
- # Replace the methodId with the implementedMethodId found in
- # the method list.
- #
- methodId = implementedMethodId
-
- return_type = obj_type.methods[methodId].return_type
+ #
+ # The initial method check has failed, but before generating an
+ # error we must check whether any of the paramTypes implement
+ # an interface. If so, we must check if the method ids using
+ # the inherited types exist.
+ #
+ # This code is a temporary fix and only checks for the methodId
+ # where all paramTypes are converted to their inherited type. The
+ # right way to do this is to replace slicc's simple string
+ # comparison for determining the correct overloaded method, with a
+ # more robust param by param check.
+ #
+ implemented_paramTypes = []
+ for paramType in paramTypes:
+ implemented_paramType = paramType
+ if paramType.isInterface:
+ implements_interface = True
+ implemented_paramType.abstract_ident = paramType["interface"]
+ else:
+ implemented_paramType.abstract_ident = paramType.c_ident
+
+ implemented_paramTypes.append(implemented_paramType)
+
+ if implements_interface:
+ implementedMethodId = obj_type.methodIdAbstract(self.proc_name,
+ implemented_paramTypes)
+ else:
+ implementedMethodId = ""
+
+ if implementedMethodId not in obj_type.methods:
+ self.error("Invalid method call: " \
+ "Type '%s' does not have a method %s, '%s' nor '%s'",
+ obj_type, self.proc_name, methodId, implementedMethodId)
+ else:
+ #
+ # Replace the methodId with the implementedMethodId found in
+ # the method list.
+ #
+ methodId = implementedMethodId
+ return_type = obj_type.methods[methodId].return_type
+
if return_type.isInterface:
prefix = "static_cast<%s &>" % return_type.c_ident
prefix = "%s((%s)." % (prefix, code)
diff --git a/src/mem/slicc/ast/OodAST.py b/src/mem/slicc/ast/OodAST.py
new file mode 100644
index 000000000..0f4cf141c
--- /dev/null
+++ b/src/mem/slicc/ast/OodAST.py
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2011 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.
+#
+
+from slicc.ast.ExprAST import ExprAST
+
+class OodAST(ExprAST):
+ def __init__(self, slicc):
+ super(OodAST, self).__init__(slicc)
+
+ def __repr__(self):
+ return "[Ood:]"
+
+ def generate(self, code):
+ code += "NULL"
+ return "OOD"
diff --git a/src/mem/slicc/ast/ReturnStatementAST.py b/src/mem/slicc/ast/ReturnStatementAST.py
index f1aff1c32..754bb4c9f 100644
--- a/src/mem/slicc/ast/ReturnStatementAST.py
+++ b/src/mem/slicc/ast/ReturnStatementAST.py
@@ -45,7 +45,7 @@ class ReturnStatementAST(StatementAST):
self.error("Invalid 'return' statement")
# The return type must match
- if return_type != actual_type:
+ if actual_type != "OOD" and return_type != actual_type:
self.expr_ast.error("Return type miss-match, expected return " +
"type is '%s', actual is '%s'",
return_type, actual_type)
diff --git a/src/mem/slicc/ast/StaticCastAST.py b/src/mem/slicc/ast/StaticCastAST.py
index 3a48f398e..71280ba67 100644
--- a/src/mem/slicc/ast/StaticCastAST.py
+++ b/src/mem/slicc/ast/StaticCastAST.py
@@ -27,18 +27,22 @@
from slicc.ast.ExprAST import ExprAST
class StaticCastAST(ExprAST):
- def __init__(self, slicc, type_ast, expr_ast):
+ def __init__(self, slicc, type_ast, type_modifier, expr_ast):
super(StaticCastAST, self).__init__(slicc)
self.type_ast = type_ast
self.expr_ast = expr_ast
+ self.type_modifier = type_modifier
def __repr__(self):
return "[StaticCastAST: %r]" % self.expr_ast
def generate(self, code):
actual_type, ecode = self.expr_ast.inline(True)
- code('static_cast<${{self.type_ast.type.c_ident}} &>($ecode)')
+ if self.type_modifier == "pointer":
+ code('static_cast<${{self.type_ast.type.c_ident}} *>($ecode)')
+ else:
+ code('static_cast<${{self.type_ast.type.c_ident}} &>($ecode)')
if not "interface" in self.type_ast.type:
self.expr_ast.error("static cast only premitted for those types " \
diff --git a/src/mem/slicc/ast/TypeDeclAST.py b/src/mem/slicc/ast/TypeDeclAST.py
index ecdb5949b..983e86882 100644
--- a/src/mem/slicc/ast/TypeDeclAST.py
+++ b/src/mem/slicc/ast/TypeDeclAST.py
@@ -50,10 +50,15 @@ class TypeDeclAST(DeclAST):
def generate(self):
ident = str(self.type_ast)
+ machine = self.symtab.state_machine
# Make the new type
new_type = Type(self.symtab, ident, self.location, self.pairs,
self.state_machine)
+
+ if machine:
+ machine.addType(new_type)
+
self.symtab.newSymbol(new_type)
# Add all of the fields of the type to it
diff --git a/src/mem/slicc/ast/__init__.py b/src/mem/slicc/ast/__init__.py
index b854612be..ae797ecd3 100644
--- a/src/mem/slicc/ast/__init__.py
+++ b/src/mem/slicc/ast/__init__.py
@@ -46,11 +46,14 @@ from slicc.ast.FuncDeclAST import *
from slicc.ast.IfStatementAST import *
from slicc.ast.InPortDeclAST import *
from slicc.ast.InfixOperatorExprAST import *
+from slicc.ast.IsValidPtrExprAST import *
from slicc.ast.LiteralExprAST import *
+from slicc.ast.LocalVariableAST import *
from slicc.ast.MachineAST import *
from slicc.ast.MemberExprAST import *
from slicc.ast.MethodCallExprAST import *
from slicc.ast.NewExprAST import *
+from slicc.ast.OodAST import *
from slicc.ast.ObjDeclAST import *
from slicc.ast.OutPortDeclAST import *
from slicc.ast.PairAST import *
diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py
index ce665465f..bb958f746 100644
--- a/src/mem/slicc/parser.py
+++ b/src/mem/slicc/parser.py
@@ -165,12 +165,15 @@ class SLICC(Grammar):
'check_stop_slots' : 'CHECK_STOP_SLOTS',
'static_cast' : 'STATIC_CAST',
'if' : 'IF',
+ 'is_valid' : 'IS_VALID',
+ 'is_invalid' : 'IS_INVALID',
'else' : 'ELSE',
'return' : 'RETURN',
'THIS' : 'THIS',
'CHIP' : 'CHIP',
'void' : 'VOID',
'new' : 'NEW',
+ 'OOD' : 'OOD',
}
literals = ':[]{}(),='
@@ -576,7 +579,11 @@ class SLICC(Grammar):
def p_statement__static_cast(self, p):
"aexpr : STATIC_CAST '(' type ',' expr ')'"
- p[0] = ast.StaticCastAST(self, p[3], p[5])
+ p[0] = ast.StaticCastAST(self, p[3], "ref", p[5])
+
+ def p_statement__static_cast_ptr(self, p):
+ "aexpr : STATIC_CAST '(' type ',' STRING ',' expr ')'"
+ p[0] = ast.StaticCastAST(self, p[3], p[5], p[7])
def p_statement__return(self, p):
"statement : RETURN expr SEMI"
@@ -603,6 +610,10 @@ class SLICC(Grammar):
"aexpr : var"
p[0] = p[1]
+ def p_expr__localvar(self, p):
+ "aexpr : type ident"
+ p[0] = ast.LocalVariableAST(self, p[1], p[2])
+
def p_expr__literal(self, p):
"aexpr : literal"
p[0] = p[1]
@@ -619,6 +630,10 @@ class SLICC(Grammar):
"aexpr : NEW type"
p[0] = ast.NewExprAST(self, p[2])
+ def p_expr__null(self, p):
+ "aexpr : OOD"
+ p[0] = ast.OodAST(self)
+
# globally access a local chip component and call a method
def p_expr__local_chip_method(self, p):
"aexpr : THIS DOT var '[' expr ']' DOT var DOT ident '(' exprs ')'"
@@ -687,6 +702,14 @@ class SLICC(Grammar):
"aexpr : '(' expr ')'"
p[0] = p[2]
+ def p_expr__is_valid_ptr(self, p):
+ "aexpr : IS_VALID '(' var ')'"
+ p[0] = ast.IsValidPtrExprAST(self, p[3], True)
+
+ def p_expr__is_invalid_ptr(self, p):
+ "aexpr : IS_INVALID '(' var ')'"
+ p[0] = ast.IsValidPtrExprAST(self, p[3], False)
+
def p_literal__string(self, p):
"literal : STRING"
p[0] = ast.LiteralExprAST(self, p[1], "std::string")
diff --git a/src/mem/slicc/symbols/Func.py b/src/mem/slicc/symbols/Func.py
index a5751344a..e1670e3ed 100644
--- a/src/mem/slicc/symbols/Func.py
+++ b/src/mem/slicc/symbols/Func.py
@@ -60,6 +60,8 @@ class Func(Symbol):
void_type = self.symtab.find("void", Type)
if "return_by_ref" in self and self.return_type != void_type:
return_type += "&"
+ elif "return_by_pointer" in self and self.return_type != void_type:
+ return_type += "*"
return "%s %s(%s);" % (return_type, self.c_ident,
", ".join(self.param_strings))
@@ -87,6 +89,8 @@ class Func(Symbol):
return_type = self.return_type.c_ident
if "return_by_ref" in self and self.return_type != void_type:
return_type += "&"
+ if "return_by_pointer" in self and self.return_type != void_type:
+ return_type += "*"
if self.isInternalMachineFunc:
klass = "%s_Controller" % self.machineStr
diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py
index 145284726..b0d663c43 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -46,6 +46,7 @@ class StateMachine(Symbol):
super(StateMachine, self).__init__(symtab, ident, location, pairs)
self.table = None
self.config_parameters = config_parameters
+
for param in config_parameters:
if param.pointer:
var = Var(symtab, param.name, location, param.type_ast.type,
@@ -62,6 +63,8 @@ class StateMachine(Symbol):
self.in_ports = []
self.functions = []
self.objects = []
+ self.TBEType = None
+ self.EntryType = None
self.message_buffer_names = []
@@ -107,6 +110,21 @@ class StateMachine(Symbol):
def addObject(self, obj):
self.objects.append(obj)
+ def addType(self, type):
+ type_ident = '%s' % type.c_ident
+
+ if type_ident == "%s_TBE" %self.ident:
+ if self.TBEType != None:
+ self.error("Multiple Transaction Buffer types in a " \
+ "single machine.");
+ self.TBEType = type
+
+ elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
+ if self.EntryType != None:
+ self.error("Multiple AbstractCacheEntry types in a " \
+ "single machine.");
+ self.EntryType = type
+
# Needs to be called before accessing the table
def buildTable(self):
assert self.table is None
@@ -264,12 +282,35 @@ private:
int m_number_of_TBEs;
TransitionResult doTransition(${ident}_Event event,
- ${ident}_State state,
+''')
+
+ if self.EntryType != None:
+ code('''
+ ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
+''')
+ if self.TBEType != None:
+ code('''
+ ${{self.TBEType.c_ident}}* m_tbe_ptr,
+''')
+
+ code('''
const Address& addr);
TransitionResult doTransitionWorker(${ident}_Event event,
${ident}_State state,
${ident}_State& next_state,
+''')
+
+ if self.TBEType != None:
+ code('''
+ ${{self.TBEType.c_ident}}*& m_tbe_ptr,
+''')
+ if self.EntryType != None:
+ code('''
+ ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
+''')
+
+ code('''
const Address& addr);
std::string m_name;
@@ -299,13 +340,42 @@ static int m_num_controllers;
if proto:
code('$proto')
+ if self.EntryType != None:
+ code('''
+
+// Set and Reset for cache_entry variable
+void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
+void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
+''')
+
+ if self.TBEType != None:
+ code('''
+
+// Set and Reset for tbe variable
+void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
+void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
+''')
+
code('''
// Actions
''')
- for action in self.actions.itervalues():
- code('/** \\brief ${{action.desc}} */')
- code('void ${{action.ident}}(const Address& addr);')
+ if self.TBEType != None and self.EntryType != None:
+ for action in self.actions.itervalues():
+ code('/** \\brief ${{action.desc}} */')
+ code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
+ elif self.TBEType != None:
+ for action in self.actions.itervalues():
+ code('/** \\brief ${{action.desc}} */')
+ code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
+ elif self.EntryType != None:
+ for action in self.actions.itervalues():
+ code('/** \\brief ${{action.desc}} */')
+ code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
+ else:
+ for action in self.actions.itervalues():
+ code('/** \\brief ${{action.desc}} */')
+ code('void ${{action.ident}}(const Address& addr);')
# the controller internal variables
code('''
@@ -731,15 +801,97 @@ void $c_ident::clearStats() {
code('''
m_profiler.clearStats();
}
+''')
+
+ if self.EntryType != None:
+ code('''
+
+// Set and Reset for cache_entry variable
+void
+$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
+{
+ m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
+}
+
+void
+$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
+{
+ m_cache_entry_ptr = 0;
+}
+''')
+
+ if self.TBEType != None:
+ code('''
+
+// Set and Reset for tbe variable
+void
+$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
+{
+ m_tbe_ptr = m_new_tbe;
+}
+
+void
+$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
+{
+ m_tbe_ptr = NULL;
+}
+''')
+
+ code('''
// Actions
''')
+ if self.TBEType != None and self.EntryType != None:
+ for action in self.actions.itervalues():
+ if "c_code" not in action:
+ continue
- for action in self.actions.itervalues():
- if "c_code" not in action:
- continue
+ code('''
+/** \\brief ${{action.desc}} */
+void
+$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
+{
+ DPRINTF(RubyGenerated, "executing\\n");
+ ${{action["c_code"]}}
+}
- code('''
+''')
+ elif self.TBEType != None:
+ for action in self.actions.itervalues():
+ if "c_code" not in action:
+ continue
+
+ code('''
+/** \\brief ${{action.desc}} */
+void
+$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
+{
+ DPRINTF(RubyGenerated, "executing\\n");
+ ${{action["c_code"]}}
+}
+
+''')
+ elif self.EntryType != None:
+ for action in self.actions.itervalues():
+ if "c_code" not in action:
+ continue
+
+ code('''
+/** \\brief ${{action.desc}} */
+void
+$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
+{
+ DPRINTF(RubyGenerated, "executing\\n");
+ ${{action["c_code"]}}
+}
+
+''')
+ else:
+ for action in self.actions.itervalues():
+ if "c_code" not in action:
+ continue
+
+ code('''
/** \\brief ${{action.desc}} */
void
$c_ident::${{action.ident}}(const Address& addr)
@@ -777,9 +929,6 @@ using namespace std;
void
${ident}_Controller::wakeup()
{
- // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this);
- // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
-
int counter = 0;
while (true) {
// Some cases will put us into an infinite loop without this limit
@@ -850,9 +999,29 @@ ${ident}_Controller::wakeup()
TransitionResult
${ident}_Controller::doTransition(${ident}_Event event,
- ${ident}_State state,
+''')
+ if self.EntryType != None:
+ code('''
+ ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
+''')
+ if self.TBEType != None:
+ code('''
+ ${{self.TBEType.c_ident}}* m_tbe_ptr,
+''')
+ code('''
const Address &addr)
{
+''')
+ if self.TBEType != None and self.EntryType != None:
+ code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
+ elif self.TBEType != None:
+ code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);')
+ elif self.EntryType != None:
+ code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);')
+ else:
+ code('${ident}_State state = ${ident}_getState(addr);')
+
+ code('''
${ident}_State next_state = state;
DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
@@ -863,8 +1032,17 @@ ${ident}_Controller::doTransition(${ident}_Event event,
addr);
TransitionResult result =
- doTransitionWorker(event, state, next_state, addr);
+''')
+ if self.TBEType != None and self.EntryType != None:
+ code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
+ elif self.TBEType != None:
+ code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
+ elif self.EntryType != None:
+ code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
+ else:
+ code('doTransitionWorker(event, state, next_state, addr);')
+ code('''
if (result == TransitionResult_Valid) {
DPRINTF(RubyGenerated, "next_state: %s\\n",
${ident}_State_to_string(next_state));
@@ -877,7 +1055,17 @@ ${ident}_Controller::doTransition(${ident}_Event event,
addr, GET_TRANSITION_COMMENT());
CLEAR_TRANSITION_COMMENT();
- ${ident}_setState(addr, next_state);
+''')
+ if self.TBEType != None and self.EntryType != None:
+ code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
+ elif self.TBEType != None:
+ code('${ident}_setState(m_tbe_ptr, addr, next_state);')
+ elif self.EntryType != None:
+ code('${ident}_setState(m_cache_entry_ptr, addr, next_state);')
+ else:
+ code('${ident}_setState(addr, next_state);')
+
+ code('''
} else if (result == TransitionResult_ResourceStall) {
DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
g_eventQueue_ptr->getTime(), m_version, "${ident}",
@@ -902,6 +1090,17 @@ TransitionResult
${ident}_Controller::doTransitionWorker(${ident}_Event event,
${ident}_State state,
${ident}_State& next_state,
+''')
+
+ if self.TBEType != None:
+ code('''
+ ${{self.TBEType.c_ident}}*& m_tbe_ptr,
+''')
+ if self.EntryType != None:
+ code('''
+ ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
+''')
+ code('''
const Address& addr)
{
switch(HASH_FUN(state, event)) {
@@ -950,8 +1149,18 @@ if (!%s.areNSlotsAvailable(%s))
if stall:
case('return TransitionResult_ProtocolStall;')
else:
- for action in actions:
- case('${{action.ident}}(addr);')
+ if self.TBEType != None and self.EntryType != None:
+ for action in actions:
+ case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
+ elif self.TBEType != None:
+ for action in actions:
+ case('${{action.ident}}(m_tbe_ptr, addr);')
+ elif self.EntryType != None:
+ for action in actions:
+ case('${{action.ident}}(m_cache_entry_ptr, addr);')
+ else:
+ for action in actions:
+ case('${{action.ident}}(addr);')
case('return TransitionResult_Valid;')
case = str(case)