summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hashe <david.hashe@amd.com>2015-07-20 09:15:18 -0500
committerDavid Hashe <david.hashe@amd.com>2015-07-20 09:15:18 -0500
commit6a288d9de3422024b9e99caa8b3717d98e467314 (patch)
treecf47855e262bccc800de1da1325c4be3f3e1dd9a
parentb609b032aaa02348884bd66396b39a3ad1a056cc (diff)
downloadgem5-6a288d9de3422024b9e99caa8b3717d98e467314.tar.xz
slicc: support for multiple message types on the same buffer
This patch allows SLICC protocols to use more than one message type with a message buffer. For example, you can declare two in ports as such: in_port(ResponseQueue_in, ResponseMsg, responseFromDir, rank=3) { ... } in_port(tgtResponseQueue_in, TgtResponseMsg, responseFromDir, rank=2) { ... }
-rw-r--r--src/mem/protocol/RubySlicc_Exports.sm1
-rw-r--r--src/mem/ruby/slicc_interface/AbstractController.hh8
-rw-r--r--src/mem/slicc/ast/InPortDeclAST.py2
-rw-r--r--src/mem/slicc/ast/PeekStatementAST.py7
-rw-r--r--src/mem/slicc/symbols/StateMachine.py63
-rw-r--r--src/mem/slicc/symbols/Var.py3
6 files changed, 78 insertions, 6 deletions
diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm
index b2a8bcb00..20ef697c5 100644
--- a/src/mem/protocol/RubySlicc_Exports.sm
+++ b/src/mem/protocol/RubySlicc_Exports.sm
@@ -116,6 +116,7 @@ enumeration(TransitionResult, desc="...") {
Valid, desc="Valid transition";
ResourceStall, desc="Stalled due to insufficient resources";
ProtocolStall, desc="Protocol specified stall";
+ Reject, desc="Rejected because of a type mismatch";
}
// RubyRequestType
diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh
index f8970fb59..e01a2a824 100644
--- a/src/mem/ruby/slicc_interface/AbstractController.hh
+++ b/src/mem/ruby/slicc_interface/AbstractController.hh
@@ -29,6 +29,7 @@
#ifndef __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
#define __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
+#include <exception>
#include <iostream>
#include <string>
@@ -49,6 +50,13 @@
class Network;
+// used to communicate that an in_port peeked the wrong message type
+class RejectException: public std::exception
+{
+ virtual const char* what() const throw()
+ { return "Port rejected message based on type"; }
+};
+
class AbstractController : public MemObject, public Consumer
{
public:
diff --git a/src/mem/slicc/ast/InPortDeclAST.py b/src/mem/slicc/ast/InPortDeclAST.py
index 75f917f9a..c5539fe52 100644
--- a/src/mem/slicc/ast/InPortDeclAST.py
+++ b/src/mem/slicc/ast/InPortDeclAST.py
@@ -59,7 +59,7 @@ class InPortDeclAST(DeclAST):
type = self.queue_type.type
in_port = Var(self.symtab, self.ident, self.location, type, str(code),
- self.pairs)
+ self.pairs, machine, self.var_expr)
symtab.newSymbol(in_port)
symtab.pushFrame()
diff --git a/src/mem/slicc/ast/PeekStatementAST.py b/src/mem/slicc/ast/PeekStatementAST.py
index d267df26e..cecb9aa9f 100644
--- a/src/mem/slicc/ast/PeekStatementAST.py
+++ b/src/mem/slicc/ast/PeekStatementAST.py
@@ -62,7 +62,12 @@ class PeekStatementAST(StatementAST):
// Declare message
const $mtid* in_msg_ptr M5_VAR_USED;
in_msg_ptr = dynamic_cast<const $mtid *>(($qcode).${{self.method}}());
- assert(in_msg_ptr != NULL); // Check the cast result
+ if (in_msg_ptr == NULL) {
+ // If the cast fails, this is the wrong inport (wrong message type).
+ // Throw an exception, and the caller will decide to either try a
+ // different inport or punt.
+ throw RejectException();
+ }
''')
if self.pairs.has_key("block_on"):
diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py
index fc1e0792a..174d66e0f 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -179,6 +179,21 @@ class StateMachine(Symbol):
action.warning(error_msg)
self.table = table
+ # determine the port->msg buffer mappings
+ def getBufferMaps(self, ident):
+ msg_bufs = []
+ port_to_buf_map = {}
+ in_msg_bufs = {}
+ for port in self.in_ports:
+ buf_name = "m_%s_ptr" % port.buffer_expr.name
+ msg_bufs.append(buf_name)
+ port_to_buf_map[port] = msg_bufs.index(buf_name)
+ if buf_name not in in_msg_bufs:
+ in_msg_bufs[buf_name] = [port]
+ else:
+ in_msg_bufs[buf_name].append(port)
+ return port_to_buf_map, in_msg_bufs, msg_bufs
+
def writeCodeFiles(self, path, includes):
self.printControllerPython(path)
self.printControllerHH(path)
@@ -423,6 +438,7 @@ void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
*/
#include <sys/types.h>
+#include <typeinfo>
#include <unistd.h>
#include <cassert>
@@ -935,7 +951,13 @@ 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 ${{action.ident}}\\n");
- ${{action["c_code"]}}
+ try {
+ ${{action["c_code"]}}
+ } catch (const RejectException & e) {
+ fatal("Error in action ${{ident}}:${{action.ident}}: "
+ "executed a peek statement with the wrong message "
+ "type specified. ");
+ }
}
''')
@@ -1028,6 +1050,7 @@ $c_ident::functionalWriteBuffers(PacketPtr& pkt)
// ${ident}: ${{self.short}}
#include <sys/types.h>
+#include <typeinfo>
#include <unistd.h>
#include <cassert>
@@ -1051,6 +1074,8 @@ $c_ident::functionalWriteBuffers(PacketPtr& pkt)
for include_path in includes:
code('#include "${{include_path}}"')
+ port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
+
code('''
using namespace std;
@@ -1060,6 +1085,8 @@ ${ident}_Controller::wakeup()
{
int counter = 0;
while (true) {
+ unsigned char rejected[${{len(msg_bufs)}}];
+ memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
// Some cases will put us into an infinite loop without this limit
assert(counter <= m_transitions_per_cycle);
if (counter == m_transitions_per_cycle) {
@@ -1084,15 +1111,43 @@ ${ident}_Controller::wakeup()
code('m_cur_in_port = ${{port.pairs["rank"]}};')
else:
code('m_cur_in_port = 0;')
+ if port in port_to_buf_map:
+ code('try {')
+ code.indent()
code('${{port["c_code_in_port"]}}')
- code.dedent()
+ if port in port_to_buf_map:
+ code.dedent()
+ code('''
+ } catch (const RejectException & e) {
+ rejected[${{port_to_buf_map[port]}}]++;
+ }
+''')
+ code.dedent()
code('')
code.dedent()
code.dedent()
code('''
- break; // If we got this far, we have nothing left todo
+ // If we got this far, we have nothing left todo or something went
+ // wrong''')
+ for buf_name, ports in in_msg_bufs.items():
+ if len(ports) > 1:
+ # only produce checks when a buffer is shared by multiple ports
+ code('''
+ if (${{buf_name}}->isReady() && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
+ {
+ // no port claimed the message on the top of this buffer
+ panic("Runtime Error at Ruby Time: %d. "
+ "All ports rejected a message. "
+ "You are probably sending a message type to this controller "
+ "over a virtual network that do not define an in_port for "
+ "the incoming message type.\\n",
+ Cycles(1));
+ }
+''')
+ code('''
+ break;
}
}
''')
@@ -1170,6 +1225,8 @@ TransitionResult result =
else:
code('doTransitionWorker(event, state, next_state, addr);')
+ port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
+
code('''
if (result == TransitionResult_Valid) {
diff --git a/src/mem/slicc/symbols/Var.py b/src/mem/slicc/symbols/Var.py
index 2a4ef23db..85b9e67cd 100644
--- a/src/mem/slicc/symbols/Var.py
+++ b/src/mem/slicc/symbols/Var.py
@@ -29,9 +29,10 @@ from slicc.symbols.Symbol import Symbol
class Var(Symbol):
def __init__(self, symtab, ident, location, type, code, pairs,
- machine=None):
+ machine=None, buffer_expr=""):
super(Var, self).__init__(symtab, ident, location, pairs)
+ self.buffer_expr = buffer_expr
self.machine = machine
self.type = type
self.code = code