From 6a288d9de3422024b9e99caa8b3717d98e467314 Mon Sep 17 00:00:00 2001 From: David Hashe Date: Mon, 20 Jul 2015 09:15:18 -0500 Subject: [PATCH] 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) { ... } --- src/mem/protocol/RubySlicc_Exports.sm | 1 + .../slicc_interface/AbstractController.hh | 8 +++ src/mem/slicc/ast/InPortDeclAST.py | 2 +- src/mem/slicc/ast/PeekStatementAST.py | 7 ++- src/mem/slicc/symbols/StateMachine.py | 63 ++++++++++++++++++- src/mem/slicc/symbols/Var.py | 3 +- 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 #include #include @@ -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(($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 +#include #include #include @@ -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 +#include #include #include @@ -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 -- 2.30.2