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) { ... }
This commit is contained in:
parent
b609b032aa
commit
6a288d9de3
6 changed files with 78 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"):
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue