diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm --- a/src/mem/protocol/RubySlicc_Types.sm +++ b/src/mem/protocol/RubySlicc_Types.sm @@ -155,6 +155,11 @@ bool checkResourceAvailable(CacheResourceType, Address); } +structure (AtomicMsgInterface, inport="yes", outport="yes", external = "yes") { + +} + + structure (WireBuffer, inport="yes", outport="yes", external = "yes") { } diff --git a/src/mem/ruby/SConscript b/src/mem/ruby/SConscript --- a/src/mem/ruby/SConscript +++ b/src/mem/ruby/SConscript @@ -104,6 +104,7 @@ MakeInclude('common/Set.hh') MakeInclude('filters/GenericBloomFilter.hh') MakeInclude('structures/Prefetcher.hh') +MakeInclude('system/AtomicMsgInterface.hh') MakeInclude('system/CacheMemory.hh') MakeInclude('system/DMASequencer.hh') MakeInclude('system/DirectoryMemory.hh') diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -71,6 +71,9 @@ virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0; virtual Sequencer* getSequencer() const = 0; + virtual bool atomicInterfaceReady(const int interface_index, const Address& addr) = 0; + virtual void processAtomicMsg(const int interface_index) = 0; + //! These functions are used by ruby system to read/write the message //! queues that exist with in the controller. //! The boolean return value indicates if the read was performed diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -33,6 +33,7 @@ if env['PROTOCOL'] == 'None': Return() +SimObject('AtomicMsgInterface.py') SimObject('Cache.py') SimObject('Sequencer.py') SimObject('DirectoryMemory.py') @@ -56,3 +57,4 @@ Source('System.cc') Source('TimerTable.cc') Source('BankedArray.cc') +Source('AtomicMsgInterface.cc') diff --git a/src/mem/ruby/system/WireBuffer.hh b/src/mem/ruby/system/AtomicMsgInterface.hh --- a/src/mem/ruby/system/WireBuffer.hh +++ b/src/mem/ruby/system/AtomicMsgInterface.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Advanced Micro Devices, Inc. + * Copyright (c) 2012 Advanced Micro Devices, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,12 +25,12 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Lisa Hsu + * Author: Brad Beckmann * */ -#ifndef __MEM_RUBY_SYSTEM_WIREBUFFER_HH__ -#define __MEM_RUBY_SYSTEM_WIREBUFFER_HH__ +#ifndef __MEM_ATOMIC_MSG_INTERFACE_HH__ +#define __MEM_ATOMIC_MSG_INTERFACE_HH__ #include #include @@ -38,12 +38,12 @@ #include "mem/ruby/buffers/MessageBufferNode.hh" #include "mem/ruby/common/Consumer.hh" -#include "params/RubyWireBuffer.hh" +#include "params/AtomicMsgInterface.hh" #include "sim/sim_object.hh" ////////////////////////////////////////////////////////////////////////////// // This object was written to literally mimic a Wire in Ruby, in the sense -// that there is no way for messages to get reordered en route on the WireBuffer. +// that there is no way for messages to get reordered en route on the AtomicMsgInterface. // With Message Buffers, even if randomization is off and ordered is on, // messages can arrive in different orders than they were sent because of // network issues. This mimics a Wire, such that that is not possible. This can @@ -51,34 +51,34 @@ // separated by a network in real systems to simplify coherence. ///////////////////////////////////////////////////////////////////////////// -class Message; +class AbstractController; +class Message; -class WireBuffer : public SimObject +class AtomicMsgInterface : public SimObject { public: - typedef RubyWireBufferParams Params; - WireBuffer(const Params *p); + typedef AtomicMsgInterfaceParams Params; + AtomicMsgInterface(const Params *p); void init(); - ~WireBuffer(); + ~AtomicMsgInterface(); void wakeup(); - void setConsumer(Consumer* consumer_ptr) + void setConsumingController(AbstractController* cntrl_ptr, int index) { - m_consumer_ptr = consumer_ptr; + m_cntrl = cntrl_ptr; + m_cntrl_index = index; } - Consumer* getConsumer() { return m_consumer_ptr; }; void setDescription(const std::string& name) { m_description = name; }; std::string getDescription() { return m_description; }; - void enqueue(MsgPtr message, int latency ); + void enqueue(MsgPtr message); void dequeue(); const Message* peek(); - MessageBufferNode peekNode(); - void recycle(); bool isReady(); - bool areNSlotsAvailable(int n) { return true; }; // infinite queue length + bool checkResourceAvailable(const Address& addr); + void callConsumer(); void print(std::ostream& out) const; void clearStats() const; @@ -87,17 +87,36 @@ uint64_t m_msg_counter; private: + + enum State + { + // Interface available + Empty, + // Interface full, waiting for consumer call + Full, + // Interface called consumer, waiting to be dequeued + Called + }; + // Private copy constructor and assignment operator - WireBuffer (const WireBuffer& obj); - WireBuffer& operator=(const WireBuffer& obj); + AtomicMsgInterface (const AtomicMsgInterface& obj); + AtomicMsgInterface& operator=(const AtomicMsgInterface& obj); // data members - Consumer* m_consumer_ptr; // Consumer to signal a wakeup() + + // pointer to the consuming controller, including the index for this + // atomic inteface + AbstractController* m_cntrl; + int m_cntrl_index; + std::string m_description; - // queues where memory requests live - std::vector m_message_queue; - + // copy of active message + MsgPtr m_message; + // state of interface + State m_state; + // active message recieved cycle used for debugging purposes + Time m_active_msg_cycle; }; -#endif // __MEM_RUBY_SYSTEM_WireBuffer_HH__ +#endif // __MEM_ATOMIC_MSG_INTERFACE_HH__ diff --git a/src/mem/ruby/system/WireBuffer.cc b/src/mem/ruby/system/AtomicMsgInterface.cc --- a/src/mem/ruby/system/WireBuffer.cc +++ b/src/mem/ruby/system/AtomicMsgInterface.cc @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Author: Lisa Hsu + * Author: Brad Beckmann * */ @@ -34,14 +34,16 @@ #include "base/cprintf.hh" #include "base/stl_helpers.hh" -#include "mem/ruby/system/WireBuffer.hh" +#include "debug/RubyQueue.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/ruby/system/AtomicMsgInterface.hh" using namespace std; // Output operator definition ostream& -operator<<(ostream& out, const WireBuffer& obj) +operator<<(ostream& out, const AtomicMsgInterface& obj) { obj.print(out); out << flush; @@ -52,111 +54,98 @@ // **************************************************************** // CONSTRUCTOR -WireBuffer::WireBuffer(const Params *p) +AtomicMsgInterface::AtomicMsgInterface(const Params *p) : SimObject(p) { m_msg_counter = 0; } void -WireBuffer::init() +AtomicMsgInterface::init() { } -WireBuffer::~WireBuffer() +AtomicMsgInterface::~AtomicMsgInterface() { } void -WireBuffer::enqueue(MsgPtr message, int latency) +AtomicMsgInterface::enqueue(MsgPtr message) { + DPRINTF(RubyQueue, "Now full enqueuing msg: %s\n", *message); + assert(m_cntrl != NULL); + assert(m_state == AtomicMsgInterface::Empty); m_msg_counter++; - Time current_time = g_system_ptr->getTime(); - Time arrival_time = current_time + latency; - assert(arrival_time > current_time); - MessageBufferNode thisNode(arrival_time, m_msg_counter, message); - m_message_queue.push_back(thisNode); - if (m_consumer_ptr != NULL) { - m_consumer_ptr->scheduleEventAbsolute(arrival_time); - } else { - panic("No Consumer for WireBuffer! %s\n", *this); - } + m_message = message; + m_active_msg_cycle = g_system_ptr->getTime(); + m_state = AtomicMsgInterface::Full; } void -WireBuffer::dequeue() +AtomicMsgInterface::dequeue() { - assert(isReady()); - pop_heap(m_message_queue.begin(), m_message_queue.end(), - greater()); - m_message_queue.pop_back(); + DPRINTF(RubyQueue, "Now empty dequeuing msg: %s\n", *m_message); + assert(m_active_msg_cycle == g_system_ptr->getTime()); + m_active_msg_cycle = 0; + m_state = AtomicMsgInterface::Empty; + m_message = NULL; } const Message* -WireBuffer::peek() +AtomicMsgInterface::peek() { - MessageBufferNode node = peekNode(); - Message* msg_ptr = node.m_msgptr.get(); - assert(msg_ptr != NULL); + assert(m_active_msg_cycle == g_system_ptr->getTime()); + const Message* msg_ptr = m_message.get(); + assert(msg_ptr); return msg_ptr; } -MessageBufferNode -WireBuffer::peekNode() +bool +AtomicMsgInterface::isReady() { - assert(isReady()); - MessageBufferNode req = m_message_queue.front(); - return req; + return (m_active_msg_cycle == g_system_ptr->getTime()); +} + +bool +AtomicMsgInterface::checkResourceAvailable(const Address& addr) +{ + assert(m_cntrl != NULL); + DPRINTF(RubyQueue, "checking index: %d, address %s\n", m_cntrl_index, + addr); + return m_cntrl->atomicInterfaceReady(m_cntrl_index, addr); } void -WireBuffer::recycle() -{ - // Because you don't want anything reordered, make sure the recycle latency - // is just 1 cycle. As a result, you really want to use this only in - // Wire-like situations because you don't want to deadlock as a result of - // being stuck behind something if you're not actually supposed to. - assert(isReady()); - MessageBufferNode node = m_message_queue.front(); - pop_heap(m_message_queue.begin(), m_message_queue.end(), - greater()); - node.m_time = g_system_ptr->getTime() + 1; - m_message_queue.back() = node; - push_heap(m_message_queue.begin(), m_message_queue.end(), - greater()); - m_consumer_ptr->scheduleEventAbsolute(g_system_ptr->getTime() + 1); -} - -bool -WireBuffer::isReady() -{ - return ((!m_message_queue.empty()) && - (m_message_queue.front().m_time <= g_system_ptr->getTime())); -} - -void -WireBuffer::print(ostream& out) const +AtomicMsgInterface::print(ostream& out) const { } void -WireBuffer::clearStats() const +AtomicMsgInterface::clearStats() const { } void -WireBuffer::printStats(ostream& out) const +AtomicMsgInterface::printStats(ostream& out) const { } void -WireBuffer::wakeup() +AtomicMsgInterface::callConsumer() { + DPRINTF(RubyQueue, "Calling consumer for msg: %s\n", *m_message); + assert(m_cntrl != NULL); + assert(m_state == AtomicMsgInterface::Full); + m_state = AtomicMsgInterface::Called; + m_cntrl->processAtomicMsg(m_cntrl_index); + // note within the proceeding call, our consuming controller should have + // dequeued us and thus our state should be empty + assert(m_state == AtomicMsgInterface::Empty); } -WireBuffer * -RubyWireBufferParams::create() +AtomicMsgInterface * +AtomicMsgInterfaceParams::create() { - return new WireBuffer(this); + return new AtomicMsgInterface(this); } diff --git a/src/mem/ruby/system/WireBuffer.py b/src/mem/ruby/system/AtomicMsgInterface.py --- a/src/mem/ruby/system/WireBuffer.py +++ b/src/mem/ruby/system/AtomicMsgInterface.py @@ -29,7 +29,7 @@ from m5.params import * from m5.SimObject import SimObject -class RubyWireBuffer(SimObject): - type = 'RubyWireBuffer' - cxx_class = 'WireBuffer' +class AtomicMsgInterface(SimObject): + type = 'AtomicMsgInterface' + cxx_class = 'AtomicMsgInterface' cxx_header = "mem/ruby/system/WireBuffer.hh" diff --git a/src/mem/slicc/ast/ActionDeclAST.py b/src/mem/slicc/ast/ActionDeclAST.py --- a/src/mem/slicc/ast/ActionDeclAST.py +++ b/src/mem/slicc/ast/ActionDeclAST.py @@ -29,21 +29,40 @@ from slicc.symbols import Action, Type, Var class ActionDeclAST(DeclAST): - def __init__(self, slicc, ident, pairs, statement_list): + def __init__(self, slicc, ident, pairs, statement_list, check_list=None): super(ActionDeclAST, self).__init__(slicc, pairs) self.ident = ident self.statement_list = statement_list + self.check_list = check_list def __repr__(self): return "[ActionDecl: %r]" % (self.ident) def generate(self): resources = {} + atomic_msg_interfaces = {} machine = self.symtab.state_machine if machine is None: self.error("Action declaration not part of a machine.") + if self.check_list: + # Add check_address local var and create the specified code that + # will override the default setting of check_address to the + # triggered address (i.e. addr) + self.symtab.pushFrame() + + addr_type = self.symtab.find("Address", Type) + var = Var(self.symtab, "check_address", self.location, addr_type, + "check_address", self.pairs) + self.symtab.newSymbol(var) + + code = self.slicc.codeFormatter() + self.check_list.generate(code, None) + self.pairs["check_code"] = str(code) + + self.symtab.popFrame() + if self.statement_list: # Add new local vars self.symtab.pushFrame() @@ -73,9 +92,10 @@ self.pairs["c_code"] = str(code) self.statement_list.findResources(resources) + self.statement_list.findAtomicMsgInt(atomic_msg_interfaces) self.symtab.popFrame() action = Action(self.symtab, self.ident, resources, self.location, - self.pairs) + self.pairs, atomic_msg_interfaces) machine.addAction(action) diff --git a/src/mem/slicc/ast/EnqueueStatementAST.py b/src/mem/slicc/ast/EnqueueStatementAST.py --- a/src/mem/slicc/ast/EnqueueStatementAST.py +++ b/src/mem/slicc/ast/EnqueueStatementAST.py @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from slicc.ast.StatementAST import StatementAST -from slicc.symbols import Var +from slicc.symbols import Var, OutPort class EnqueueStatementAST(StatementAST): def __init__(self, slicc, queue_name, type_ast, pairs, statements): @@ -82,5 +82,17 @@ def findResources(self, resources): var = self.queue_name.var - res_count = int(resources.get(var, 0)) - resources[var] = str(res_count + 1) + # out_ports that are not atomic resource interfaces should be treated + # like all other generic resources, i.e. use areNSlotsAvailable + if not var.usesAtomicInt(): + res_count = int(resources.get(var, 0)) + resources[var] = str(res_count + 1) + + def findAtomicMsgInt(self, atomic_msg_int): + var = self.queue_name.var + self.queue_name.assertType("OutPort") + # out_ports that *ARE* atomic resource interfaces must use a special + # resource API that passes in the address + if var.usesAtomicInt(): + ami_count = int(atomic_msg_int.get(var, 0)) + atomic_msg_int[var] = str(ami_count + 1) diff --git a/src/mem/slicc/ast/ExprAST.py b/src/mem/slicc/ast/ExprAST.py --- a/src/mem/slicc/ast/ExprAST.py +++ b/src/mem/slicc/ast/ExprAST.py @@ -34,6 +34,10 @@ # The default is no resources pass + def findAtomicMsgInt(self, atomic_msg_int): + # The default is no atomic_msg_int + pass + def inline(self, get_type=False): code = self.slicc.codeFormatter(fix_newlines=False) return_type = self.generate(code) diff --git a/src/mem/slicc/ast/ExprStatementAST.py b/src/mem/slicc/ast/ExprStatementAST.py --- a/src/mem/slicc/ast/ExprStatementAST.py +++ b/src/mem/slicc/ast/ExprStatementAST.py @@ -48,3 +48,6 @@ def findResources(self, resources): self.expr.findResources(resources) + def findAtomicMsgInt(self, atomic_msg_int): + self.expr.findAtomicMsgInt(atomic_msg_int) + diff --git a/src/mem/slicc/ast/FuncCallExprAST.py b/src/mem/slicc/ast/FuncCallExprAST.py --- a/src/mem/slicc/ast/FuncCallExprAST.py +++ b/src/mem/slicc/ast/FuncCallExprAST.py @@ -26,7 +26,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from slicc.ast.ExprAST import ExprAST -from slicc.symbols import Func, Type +from slicc.symbols import Func, Type, Event class FuncCallExprAST(ExprAST): def __init__(self, slicc, proc_name, exprs): @@ -90,6 +90,7 @@ cvec = [] type_vec = [] + event_str = None for expr,expected_type in zip(self.exprs, func.param_types): # Check the types of the parameter actual_type,param_code = expr.inline(True) @@ -98,6 +99,13 @@ (expected_type, actual_type)) cvec.append(param_code) type_vec.append(expected_type) + if str(actual_type) == "Event": + try: + event_str = expr.value + except: + self.warning("Atomic message interface only works " + + "with explicit event triggers") + # OK, the semantics of "trigger" here is that, ports in the # machine have different priorities. We always check the first @@ -114,29 +122,31 @@ # port. So as most of current protocols. if self.proc_name == "trigger": + # used by atomic message interface to associate events with ports + if event_str is not None: + event = machine.events[event_str] + machine.current_in_port.addEvent(event) code(''' { Address addr = ${{cvec[1]}}; ''') if machine.TBEType != None and machine.EntryType != None: code(''' - TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, ${{cvec[3]}}, addr); + return doTransition(${{cvec[0]}}, ${{cvec[2]}}, ${{cvec[3]}}, addr); ''') elif machine.TBEType != None: code(''' - TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); + return doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); ''') elif machine.EntryType != None: code(''' - TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); + return doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); ''') else: code(''' - TransitionResult result = doTransition(${{cvec[0]}}, addr); + return doTransition(${{cvec[0]}}, addr); ''') - code(''' - return result; } ''') elif self.proc_name == "error": diff --git a/src/mem/slicc/ast/IfStatementAST.py b/src/mem/slicc/ast/IfStatementAST.py --- a/src/mem/slicc/ast/IfStatementAST.py +++ b/src/mem/slicc/ast/IfStatementAST.py @@ -74,3 +74,9 @@ self.then.findResources(resources) if self.else_ is not None: self.else_.findResources(resources) + + def findAtomicMsgInt(self, atomic_msg_int): + # Take a worse case look at both paths + self.then.findAtomicMsgInt(atomic_msg_int) + if self.else_ is not None: + self.else_.findAtomicMsgInt(atomic_msg_int) diff --git a/src/mem/slicc/ast/InPortDeclAST.py b/src/mem/slicc/ast/InPortDeclAST.py --- a/src/mem/slicc/ast/InPortDeclAST.py +++ b/src/mem/slicc/ast/InPortDeclAST.py @@ -27,12 +27,13 @@ from slicc.ast.DeclAST import DeclAST from slicc.ast.TypeAST import TypeAST -from slicc.symbols import Func, Type, Var +from slicc.symbols import Func, Type, Var, InPort class InPortDeclAST(DeclAST): max_port_rank = 0 - def __init__(self, slicc, ident, msg_type, var_expr, pairs, statements): + def __init__(self, slicc, ident, msg_type, var_expr, is_atomic, \ + pairs, statements, accepting_states=[]): super(InPortDeclAST, self).__init__(slicc, pairs) self.ident = ident @@ -43,6 +44,13 @@ if self.pairs.has_key("rank"): InPortDeclAST.max_port_rank = max(self.pairs["rank"], InPortDeclAST.max_port_rank) + self.is_atomic = is_atomic + self.accepting_states = accepting_states + if self.is_atomic and accepting_states == []: + # atomic in ports must specify what states they can process atomic + # messages. Any states not specified will stall the enqueuer. + self.error("AtomicInPort has no accepting states") + def __repr__(self): return "[InPortDecl: %s]" % self.ident @@ -62,11 +70,20 @@ "attribute. Type '%s' does not have this attribute.", queue_type) + # if this is an atomic port, create + a_states = [] + if self.is_atomic: + for state in self.accepting_states: + a_states.append(machine.states[state]) + type = self.queue_type.type - in_port = Var(self.symtab, self.ident, self.location, type, str(code), - self.pairs) + in_port = InPort(self.symtab, self.ident, self.location, type, str(code), + self.pairs, self.is_atomic, a_states) symtab.newSymbol(in_port) + # Add port to state machine + machine.addInPort(in_port) + symtab.pushFrame() param_types = [] @@ -122,8 +139,5 @@ symtab.popFrame() - # Add port to state machine - machine.addInPort(in_port) - # Include max_rank to be used by StateMachine.py in_port["max_port_rank"] = InPortDeclAST.max_port_rank diff --git a/src/mem/slicc/ast/MethodCallExprAST.py b/src/mem/slicc/ast/MethodCallExprAST.py --- a/src/mem/slicc/ast/MethodCallExprAST.py +++ b/src/mem/slicc/ast/MethodCallExprAST.py @@ -77,6 +77,9 @@ def findResources(self, resources): pass + def findAtomicMsgInt(self, atomic_msg_int): + pass + class MemberMethodCallExprAST(MethodCallExprAST): def __init__(self, slicc, obj_expr_ast, proc_name, expr_ast_vec): s = super(MemberMethodCallExprAST, self) diff --git a/src/mem/slicc/ast/OutPortDeclAST.py b/src/mem/slicc/ast/OutPortDeclAST.py --- a/src/mem/slicc/ast/OutPortDeclAST.py +++ b/src/mem/slicc/ast/OutPortDeclAST.py @@ -29,6 +29,7 @@ from slicc.ast.TypeAST import TypeAST from slicc.symbols import Var from slicc.symbols import Type +from slicc.symbols import OutPort class OutPortDeclAST(DeclAST): def __init__(self, slicc, ident, msg_type, var_expr, pairs): @@ -55,6 +56,7 @@ self.error("The message type '%s' does not exist.", self.msg_type.ident) - var = Var(self.symtab, self.ident, self.location, self.queue_type.type, - str(code), self.pairs) - self.symtab.newSymbol(var) + out_port = OutPort(self.symtab, self.ident, self.location, + self.queue_type.type, str(code), self.pairs, + self.var_expr.var) + self.symtab.newSymbol(out_port) diff --git a/src/mem/slicc/ast/PeekStatementAST.py b/src/mem/slicc/ast/PeekStatementAST.py --- a/src/mem/slicc/ast/PeekStatementAST.py +++ b/src/mem/slicc/ast/PeekStatementAST.py @@ -92,3 +92,6 @@ def findResources(self, resources): self.statements.findResources(resources) + + def findAtomicMsgInt(self, atomic_msg_int): + self.statements.findAtomicMsgInt(atomic_msg_int) diff --git a/src/mem/slicc/ast/StallAndWaitStatementAST.py b/src/mem/slicc/ast/StallAndWaitStatementAST.py --- a/src/mem/slicc/ast/StallAndWaitStatementAST.py +++ b/src/mem/slicc/ast/StallAndWaitStatementAST.py @@ -35,7 +35,7 @@ self.address = address def __repr__(self): - return "[StallAndWaitStatementAst: %r]" % self.variable + return "[StallAndWaitStatementAst]" def generate(self, code, return_type): self.in_port.assertType("InPort") diff --git a/src/mem/slicc/ast/StatementAST.py b/src/mem/slicc/ast/StatementAST.py --- a/src/mem/slicc/ast/StatementAST.py +++ b/src/mem/slicc/ast/StatementAST.py @@ -32,3 +32,6 @@ def findResources(self, resources): pass + + def findAtomicMsgInt(self, atomic_msg_int): + pass diff --git a/src/mem/slicc/ast/StatementListAST.py b/src/mem/slicc/ast/StatementListAST.py --- a/src/mem/slicc/ast/StatementListAST.py +++ b/src/mem/slicc/ast/StatementListAST.py @@ -44,3 +44,7 @@ def findResources(self, resources): for statement in self.statements: statement.findResources(resources) + + def findAtomicMsgInt(self, atomic_msg_int): + for statement in self.statements: + statement.findAtomicMsgInt(atomic_msg_int) diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py --- a/src/mem/slicc/parser.py +++ b/src/mem/slicc/parser.py @@ -102,6 +102,8 @@ 'global' : 'GLOBAL', 'machine' : 'MACHINE', 'in_port' : 'IN_PORT', + 'atomic_in_port' : 'ATOMIC_IN_PORT', + 'accepting_states': 'ACCEPTING_STATES', 'out_port' : 'OUT_PORT', 'action' : 'ACTION', 'transition' : 'TRANS', @@ -262,9 +264,19 @@ "decl : ACTION '(' ident pairs ')' statements" p[0] = ast.ActionDeclAST(self, p[3], p[4], p[6]) + def p_decl__action_checks(self, p): + "decl : ACTION '(' ident pairs ')' '[' statements ']' statements" + p[0] = ast.ActionDeclAST(self, p[3], p[4], p[9], p[7]) + def p_decl__in_port(self, p): "decl : IN_PORT '(' ident ',' type ',' var pairs ')' statements" - p[0] = ast.InPortDeclAST(self, p[3], p[5], p[7], p[8], p[10]) + p[0] = ast.InPortDeclAST(self, p[3], p[5], p[7], False, p[8], p[10]) + + def p_decl__atomic_in_port(self, p): + "decl : ATOMIC_IN_PORT '(' ident ',' type ',' var ',' " \ + "ACCEPTING_STATES '=' idents pairs ')' statements" + p[0] = ast.InPortDeclAST(self, p[3], p[5], p[7], True, p[12], p[14], \ + p[11]) def p_decl__out_port(self, p): "decl : OUT_PORT '(' ident ',' type ',' var pairs ')' SEMI" diff --git a/src/mem/slicc/symbols/Action.py b/src/mem/slicc/symbols/Action.py --- a/src/mem/slicc/symbols/Action.py +++ b/src/mem/slicc/symbols/Action.py @@ -28,9 +28,11 @@ from slicc.symbols.Symbol import Symbol class Action(Symbol): - def __init__(self, table, ident, resources, location, pairs): + def __init__(self, table, ident, resources, location, pairs, + atomic_msg_interfaces): super(Action, self).__init__(table, ident, location, pairs) self.resources = resources + self.atomic_msg_interfaces = atomic_msg_interfaces def __repr__(self): return "[Action: %s]" % self.ident diff --git a/src/mem/slicc/symbols/Event.py b/src/mem/slicc/symbols/Event.py --- a/src/mem/slicc/symbols/Event.py +++ b/src/mem/slicc/symbols/Event.py @@ -28,7 +28,28 @@ from slicc.symbols.Symbol import Symbol class Event(Symbol): + def __init__(self, symtab, ident, location, pairs=None): + super(Event, self).__init__(symtab, ident, location, pairs) + self.resources = {} + self.request_types = {} + self.atomic_msg_ints = [] + def __repr__(self): return "[Event: %s]" % self.ident + def addResource(self, res_key, res_val): + if res_key in self.resources: + self.resources[res_key] = max(res_val, self.resources[res_key]) + else: + self.resources[res_key] = res_val + + def addRequestType(self, req_type): + # Currently assume that only one request type is used per transition + if not req_type in self.request_types: + self.request_types[req_type] = 1 + + def addAtomicInterface(self, atomic_msg_int): + if not atomic_msg_int in self.atomic_msg_ints: + self.atomic_msg_ints.append(atomic_msg_int) + __all__ = [ "Event" ] diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -29,6 +29,7 @@ from slicc.symbols.Symbol import Symbol from slicc.symbols.Var import Var +from slicc.symbols.Event import Event import slicc.generate.html as html import re @@ -38,6 +39,7 @@ "bool": "Bool", "CacheMemory": "RubyCache", "WireBuffer": "RubyWireBuffer", + "AtomicMsgInterface": "AtomicMsgInterface", "Sequencer": "RubySequencer", "DirectoryMemory": "RubyDirectoryMemory", "MemoryControl": "MemoryControl", @@ -69,12 +71,13 @@ self.request_types = orderdict() self.transitions = [] self.in_ports = [] + self.atomic_in_ports = [] self.functions = [] self.objects = [] self.TBEType = None self.EntryType = None self.message_buffer_names = [] - + self.current_in_port = None def __repr__(self): return "[StateMachine: %s]" % self.ident @@ -111,8 +114,11 @@ assert self.table is None self.transitions.append(trans) - def addInPort(self, var): - self.in_ports.append(var) + def addInPort(self, in_port): + self.in_ports.append(in_port) + if in_port.is_atomic: + self.atomic_in_ports.append(in_port) + self.current_in_port = in_port def addFunc(self, func): # register func in the symbol table @@ -277,6 +283,9 @@ bool functionalReadBuffers(PacketPtr&); uint32_t functionalWriteBuffers(PacketPtr&); + bool atomicInterfaceReady(const int interface_index, const Address& addr); + void processAtomicMsg(const int interface_index); + private: ''') @@ -311,11 +320,11 @@ if self.TBEType != None: code(''' - ${{self.TBEType.c_ident}}*& m_tbe_ptr, + ${{self.TBEType.c_ident}}* m_tbe_ptr, ''') if self.EntryType != None: code(''' - ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, + ${{self.EntryType.c_ident}}* m_cache_entry_ptr, ''') code(''' @@ -642,9 +651,12 @@ code('${{prefetcher.code}}.setController(this);') # Set the queue consumers - code() for port in self.in_ports: - code('${{port.code}}.setConsumer(this);') + if not port.is_atomic: + code('${{port.code}}.setConsumer(this);') + + for i, atomic_port in enumerate(self.atomic_in_ports): + code('${{atomic_port.code}}.setConsumingController(this, $i);') # Set the queue descriptions code() @@ -686,6 +698,102 @@ seq_ident = "m_%s_ptr" % param.name code(''' +bool +$c_ident::atomicInterfaceReady(const int interface_index, const Address& addr) +{ + assert(interface_index < ${{len(self.atomic_in_ports)}}); + switch(interface_index) { +''') + for i,atomic_port in enumerate(self.atomic_in_ports): + resources, request_types, atomic_msg_ints = \ + atomic_port.getAllResources() + code(''' + case $i: + { +''') + for res_key,res_val in resources.iteritems(): + code(''' + if (!${{res_key.code}}.areNSlotsAvailable(${{res_val}})) { + DPRINTF(RubyGenerated, + "atomic message interface not ready due to resource\\n"); + return false; + } +''') + + # Check all of the request_types for resource constraints + for req_key,req_val in request_types.iteritems(): + code(''' + if (!checkResourceAvailable(${{self.ident}}_RequestType_${{req_key.ident}}, addr)) { + DPRINTF(RubyGenerated, + "atomic message interface not ready due to request type-bank\\n"); + return false; + } +''') + # Check all of the atomic_msg_ints for resource constraints + for atomic_msg_int in atomic_msg_ints: + code(''' + if (!${{atomic_msg_int.code}}.checkResourceAvailable(addr)) { + DPRINTF(RubyGenerated, + "atomic message interface not ready due to another atomic msg int\\n"); + return false; + } +''') + code(''' + ${ident}_State cur_state = getStateFromAddr(addr); + switch(cur_state) { +''') + for state in atomic_port.getAcceptingStates(): + code(''' + case ${ident}_State_${{state}}: + { + DPRINTF(RubyGenerated, + "atomic msg ready in state %s addr %s\\n", + ${ident}_State_to_string(cur_state), addr); + return true; + } +''') + code(''' + default: + DPRINTF(RubyGenerated, + "atomic msg not ready due to state %s addr %s\\n", + ${ident}_State_to_string(cur_state), addr); + return false; + } + } +''') + code(''' + default: + panic("SLICC generated invalid code"); + return false; + } +} + +void +$c_ident::processAtomicMsg(const int interface_index) +{ + assert(interface_index < ${{len(self.atomic_in_ports)}}); + TransitionResult result; + + switch(interface_index) { +''') + for i, atomic_port in enumerate(self.atomic_in_ports): + code(''' + case $i: + result = ${{atomic_port}}(); + break; +''') + code(''' + default: + panic("SLICC generated invalid code"); + } + + if (result != TransitionResult_Valid) { + panic("SLICC atomic msg processing failed"); + } +} +''') + + code(''' int $c_ident::getNumControllers() { @@ -1072,7 +1180,7 @@ continue; // Check the first port again } if (result == TransitionResult_ResourceStall) { - g_system_ptr->scheduleEvent(this, 1); + scheduleEvent(1); // Cannot do anything with this transition, go check next doable transition (mostly likely of next port) } @@ -1084,7 +1192,7 @@ code(''' break; // If we got this far, we have nothing left todo } - // g_system_ptr->scheduleEvent(this, 1); + // scheduleEvent(1); } ''') for port in self.in_ports: @@ -1169,42 +1277,37 @@ TransitionResult result = ''') if self.TBEType != None and self.EntryType != None: - code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') + 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);') + 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);') + code(''' + doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr); +''') else: - code('doTransitionWorker(event, state, next_state, addr);') + code(''' + doTransitionWorker(event, state, next_state, addr); +''') + # Note: valid transition profiling done at the end of the perform + # action function code(''' if (result == TransitionResult_Valid) { DPRINTF(RubyGenerated, "next_state: %s\\n", ${ident}_State_to_string(next_state)); - m_profiler.countTransition(state, event); DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", - curTick(), m_version, "${ident}", + curTick(), m_version, "${{ident}}", ${ident}_Event_to_string(event), ${ident}_State_to_string(state), - ${ident}_State_to_string(next_state), + ${{ident}}_State_to_string(next_state), addr, GET_TRANSITION_COMMENT()); - CLEAR_TRANSITION_COMMENT(); -''') - if self.TBEType != None and self.EntryType != None: - code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') - code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') - elif self.TBEType != None: - code('setState(m_tbe_ptr, addr, next_state);') - code('setAccessPermission(addr, next_state);') - elif self.EntryType != None: - code('setState(m_cache_entry_ptr, addr, next_state);') - code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') - else: - code('setState(addr, next_state);') - code('setAccessPermission(addr, next_state);') - - code(''' + m_profiler.countTransition(state, event); } else if (result == TransitionResult_ResourceStall) { DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", curTick(), m_version, "${ident}", @@ -1233,11 +1336,11 @@ if self.TBEType != None: code(''' - ${{self.TBEType.c_ident}}*& m_tbe_ptr, + ${{self.TBEType.c_ident}}* m_tbe_ptr, ''') if self.EntryType != None: code(''' - ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, + ${{self.EntryType.c_ident}}* m_cache_entry_ptr, ''') code(''' const Address& addr) @@ -1251,23 +1354,25 @@ for trans in self.transitions: case_string = "%s_State_%s, %s_Event_%s" % \ (self.ident, trans.state.ident, self.ident, trans.event.ident) + state = trans.state.ident + event = trans.event.ident - case = self.symtab.codeFormatter() - # Only set next_state if it changes - if trans.state != trans.nextState: - ns_ident = trans.nextState.ident - case('next_state = ${ident}_State_${ns_ident};') + check_list = self.symtab.codeFormatter() + action_list = self.symtab.codeFormatter() + post_process_list = self.symtab.codeFormatter() + ns_ident = trans.nextState.ident + action_list('next_state = ${ident}_State_${ns_ident};') actions = trans.actions request_types = trans.request_types + atomic_msg_int = trans.atomic_msg_interface # Check for resources case_sorter = [] res = trans.resources for key,val in res.iteritems(): - if key.type.ident != "DNUCAStopTable": - val = ''' -if (!%s.areNSlotsAvailable(%s)) + val = ''' +if (!%s.areNSlotsAvailable(%d)) return TransitionResult_ResourceStall; ''' % (key.code, val) case_sorter.append(val) @@ -1285,11 +1390,29 @@ # output deterministic (without this the output order can vary # since Map's keys() on a vector of pointers is not deterministic for c in sorted(case_sorter): - case("$c") + check_list("$c") + + if atomic_msg_int: + check_list(''' +Address check_address = addr; +''') + # By default, the check_addr used for the atomic msg interface + # is the address used to trigger the event. However, this + # address can be overridden by the programer using a specified + # check list + for action in actions: + if action.pairs.has_key("check_code"): + check_list('${{action.pairs["check_code"]}}') + check_list(''' +if (!%s.checkResourceAvailable(check_address)) { + return TransitionResult_ResourceStall; +} +''' % (atomic_msg_int.code)) + #case_sorter.append(val) # Record access types for this transition for request_type in request_types: - case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') + check_list('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') # Figure out if we stall stall = False @@ -1299,38 +1422,66 @@ break if stall: - case('return TransitionResult_ProtocolStall;') + check_list('// no op - stall') + check_list('return TransitionResult_ProtocolStall;') else: + #check_list('${ident}_State next_state = ${ident}_State_${ns_ident};') if self.TBEType != None and self.EntryType != None: for action in actions: - case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') + action_list('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') + action_list('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') + action_list('setAccessPermission(m_cache_entry_ptr, addr, next_state);') elif self.TBEType != None: for action in actions: - case('${{action.ident}}(m_tbe_ptr, addr);') + action_list('${{action.ident}}(m_tbe_ptr, addr);') + action_list('setState(m_tbe_ptr, addr, next_state);') + action_list('setAccessPermission(addr, next_state);') elif self.EntryType != None: for action in actions: - case('${{action.ident}}(m_cache_entry_ptr, addr);') + action_list('${{action.ident}}(m_cache_entry_ptr, addr);') + action_list('setState(m_cache_entry_ptr, addr, next_state);') + action_list('setAccessPermission(m_cache_entry_ptr, addr, next_state);') else: for action in actions: - case('${{action.ident}}(addr);') - case('return TransitionResult_Valid;') + action_list('${{action.ident}}(addr);') + action_list('setState(addr, next_state);') + action_list('setAccessPermission(addr, next_state);') - case = str(case) + if atomic_msg_int: + post_process_list(''' +${{atomic_msg_int.queue.code}}.callConsumer(); +''') - # Look to see if this transition code is unique. - if case not in cases: - cases[case] = [] + action_str = "%s" % action_list - cases[case].append(case_string) + # Look to see if this transition code is unique. Note that *only* + # the first state event combination will be added to the case + # entry. The associated perform action function for all equivalent + # transitions will be named using this combination of strings + if action_str not in cases: + cases[action_str] = [check_list, post_process_list, \ + [case_string], state, event] + else: + cases[action_str][2].append(case_string) # Walk through all of the unique code blocks and spit out the # corresponding case statement elements - for case,transitions in cases.iteritems(): + for action_str, properties in cases.iteritems(): + check_list = properties[0] + post_process_list = properties[1] + transitions = properties[2] + state = properties[3] + event = properties[4] # Iterative over all the multiple transitions that share # the same code for trans in transitions: code(' case HASH_FUN($trans):') - code(' $case') + code(' {') + code(' $check_list') + code(' $action_str') + code(' $post_process_list') + code(' return TransitionResult_Valid;') + code(' }') code(''' default: diff --git a/src/mem/slicc/symbols/SymbolTable.py b/src/mem/slicc/symbols/SymbolTable.py --- a/src/mem/slicc/symbols/SymbolTable.py +++ b/src/mem/slicc/symbols/SymbolTable.py @@ -105,6 +105,10 @@ def state_machine(self): return self.find("current_machine", StateMachine) + @property + def in_port(self): + return self.find("current_in_port", ) + def pushFrame(self): self.sym_map_vec.append({}) diff --git a/src/mem/slicc/symbols/Transition.py b/src/mem/slicc/symbols/Transition.py --- a/src/mem/slicc/symbols/Transition.py +++ b/src/mem/slicc/symbols/Transition.py @@ -39,16 +39,34 @@ self.actions = [ machine.actions[a] for a in actions ] self.request_types = [ machine.request_types[s] for s in request_types ] self.resources = {} + atomic_msg_interfaces = {} + self.atomic_msg_interface = None for action in self.actions: for var,value in action.resources.iteritems(): - if var.type.ident != "DNUCAStopTable": - num = int(value) - if var in self.resources: - num += int(value) - self.resources[var] = str(num) - else: - self.resources[var] = value + num = int(value) + if var in self.resources: + num += int(value) + self.resources[var] = num + for var,value in action.atomic_msg_interfaces.iteritems(): + num = int(value) + if var in atomic_msg_interfaces: + num += int(value) + atomic_msg_interfaces[var] = num + + first_ami_found = False + for var,value in atomic_msg_interfaces.iteritems(): + if value > 1 and not first_ami_found: + fatal("only one Atomic Msg Interface per transition") + first_ami_found = True + self.atomic_msg_interface = var + self.event.addAtomicInterface(var) + + for request_type in self.request_types: + self.event.addRequestType(request_type) + + for res_key,res_val in self.resources.iteritems(): + self.event.addResource(res_key,res_val) def __repr__(self): return "[Transition: (%r, %r) -> %r, %r]" % \ diff --git a/src/mem/slicc/symbols/Type.py b/src/mem/slicc/symbols/Type.py --- a/src/mem/slicc/symbols/Type.py +++ b/src/mem/slicc/symbols/Type.py @@ -99,6 +99,9 @@ if self.ident == "DNUCA_Movement": self["mover"] = "yes" + if self.ident == "AtomicMsgInterface": + self["atomic_msg_interface"] = "yes" + self.isMachineType = (ident == "MachineType") self.isStateDecl = ("state_decl" in self) @@ -143,6 +146,9 @@ @property def isInterface(self): return "interface" in self + @property + def isAtomicMsgInterface(self): + return "atomic_msg_interface" in self # Return false on error def addDataMember(self, ident, type, pairs, init_code): @@ -549,7 +555,6 @@ ConvertGenericMachToMach(GenericMachineType genMachType) { ''') - print self.symtab.find("GenericMachineType") for (ident, enum) in self.symtab.find("GenericMachineType").enums.iteritems(): if ident in self.symtab.find("MachineType").enums: code(''' diff --git a/src/mem/slicc/symbols/Var.py b/src/mem/slicc/symbols/InPort.py --- a/src/mem/slicc/symbols/Var.py +++ b/src/mem/slicc/symbols/InPort.py @@ -1,5 +1,6 @@ # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood # Copyright (c) 2009 The Hewlett-Packard Development Company +# Copyright (c) 2012 Advanced Micro Devices, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,26 +26,53 @@ # (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.symbols.Symbol import Symbol +from slicc.symbols.Var import Var +from slicc.symbols.Event import Event -class Var(Symbol): - def __init__(self, symtab, ident, location, type, code, pairs, - machine=None): - super(Var, self).__init__(symtab, ident, location, pairs) +class InPort(Var): + def __init__(self, symtab, ident, location, type, code, pairs, is_atomic, + a_states, machine=None): + super(InPort, self).__init__(symtab, ident, location, type, code, + pairs, machine) + self.is_atomic = is_atomic + self.events = [] + self.a_states = a_states - if machine: - self.c_ident = "%s_%s" % (machine, ident) - else: - self.c_ident = ident - - self.machine = machine - self.type = type - self.code = code + def addEvent(self, event): + self.events.append(event) def __repr__(self): - return "[Var id: %s]" % (self.c_ident) + return "[InPort id: %s]" % (self.c_ident) + + def getAcceptingStates(self): + return self.a_states + + def getAllResources(self): + resources = {} + request_types = {} + atomic_msg_ints = [] + + # Loop through all of the events associated with this inport and create + # the superset of resources required to execute any particular event. + # Currently, this is use by the atomic_in_port to guarantee the + # completion of a sequence of transitions when the specific triggered + # event is not known ahead of time + for event in self.events: + for res_key,res_val in event.resources.iteritems(): + if res_key in resources: + resources[res_key] = max(res_val, resources[res_key]) + else: + resources[res_key] = res_val + for req_type,req_val in event.request_types.iteritems(): + if not req_type in request_types: + request_types[req_type] = 1 + for atomic_msg_int in event.atomic_msg_ints: + if not atomic_msg_int in atomic_msg_ints: + atomic_msg_ints.append(atomic_msg_int) + + return resources, request_types, atomic_msg_ints def writeCodeFiles(self, path, includes): - pass + super(InPort, self).writeCodeFiles(path, includes) -__all__ = [ "Var" ] +__all__ = [ "InPort" ] diff --git a/src/mem/slicc/symbols/Var.py b/src/mem/slicc/symbols/OutPort.py --- a/src/mem/slicc/symbols/Var.py +++ b/src/mem/slicc/symbols/OutPort.py @@ -1,5 +1,6 @@ # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood # Copyright (c) 2009 The Hewlett-Packard Development Company +# Copyright (c) 2012 Advanced Micro Devices, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -25,26 +26,21 @@ # (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.symbols.Symbol import Symbol +from slicc.symbols.Var import Var +from slicc.symbols.Event import Event -class Var(Symbol): - def __init__(self, symtab, ident, location, type, code, pairs, +class OutPort(Var): + def __init__(self, symtab, ident, location, type, code, pairs, queue, machine=None): - super(Var, self).__init__(symtab, ident, location, pairs) - - if machine: - self.c_ident = "%s_%s" % (machine, ident) - else: - self.c_ident = ident - - self.machine = machine - self.type = type - self.code = code + super(OutPort, self).__init__(symtab, ident, location, type, code, + pairs, machine) + self.queue = queue + self.uses_atomic_int = queue.type.isAtomicMsgInterface def __repr__(self): - return "[Var id: %s]" % (self.c_ident) + return "[OutPort id: %s]" % (self.c_ident) def writeCodeFiles(self, path, includes): - pass + super(OutPort, self).writeCodeFiles(path, includes) -__all__ = [ "Var" ] +__all__ = [ "OutPort" ] diff --git a/src/mem/slicc/symbols/Var.py b/src/mem/slicc/symbols/Var.py --- a/src/mem/slicc/symbols/Var.py +++ b/src/mem/slicc/symbols/Var.py @@ -44,6 +44,9 @@ def __repr__(self): return "[Var id: %s]" % (self.c_ident) + def usesAtomicInt(self): + pass + def writeCodeFiles(self, path, includes): pass diff --git a/src/mem/slicc/symbols/__init__.py b/src/mem/slicc/symbols/__init__.py --- a/src/mem/slicc/symbols/__init__.py +++ b/src/mem/slicc/symbols/__init__.py @@ -29,8 +29,10 @@ from slicc.symbols.Action import Action from slicc.symbols.Event import Event from slicc.symbols.Func import Func +from slicc.symbols.InPort import InPort +from slicc.symbols.OutPort import OutPort +from slicc.symbols.RequestType import RequestType from slicc.symbols.State import State -from slicc.symbols.RequestType import RequestType from slicc.symbols.StateMachine import StateMachine from slicc.symbols.Symbol import Symbol from slicc.symbols.SymbolTable import SymbolTable