StateMachine.py revision 9102
111666Stushar@ece.gatech.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
211666Stushar@ece.gatech.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
311666Stushar@ece.gatech.edu# All rights reserved.
411666Stushar@ece.gatech.edu#
511666Stushar@ece.gatech.edu# Redistribution and use in source and binary forms, with or without
611666Stushar@ece.gatech.edu# modification, are permitted provided that the following conditions are
711666Stushar@ece.gatech.edu# met: redistributions of source code must retain the above copyright
811666Stushar@ece.gatech.edu# notice, this list of conditions and the following disclaimer;
911666Stushar@ece.gatech.edu# redistributions in binary form must reproduce the above copyright
1011666Stushar@ece.gatech.edu# notice, this list of conditions and the following disclaimer in the
1111666Stushar@ece.gatech.edu# documentation and/or other materials provided with the distribution;
1211666Stushar@ece.gatech.edu# neither the name of the copyright holders nor the names of its
1311666Stushar@ece.gatech.edu# contributors may be used to endorse or promote products derived from
1411666Stushar@ece.gatech.edu# this software without specific prior written permission.
1511666Stushar@ece.gatech.edu#
1611666Stushar@ece.gatech.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711666Stushar@ece.gatech.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811666Stushar@ece.gatech.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911666Stushar@ece.gatech.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011666Stushar@ece.gatech.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111666Stushar@ece.gatech.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211666Stushar@ece.gatech.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311666Stushar@ece.gatech.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411666Stushar@ece.gatech.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511666Stushar@ece.gatech.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611666Stushar@ece.gatech.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711666Stushar@ece.gatech.edu
2811666Stushar@ece.gatech.edufrom m5.util import orderdict
2911666Stushar@ece.gatech.edu
3011666Stushar@ece.gatech.edufrom slicc.symbols.Symbol import Symbol
3111666Stushar@ece.gatech.edufrom slicc.symbols.Var import Var
3211666Stushar@ece.gatech.eduimport slicc.generate.html as html
3311666Stushar@ece.gatech.eduimport re
3411666Stushar@ece.gatech.edu
3511666Stushar@ece.gatech.edupython_class_map = {"int": "Int",
3611666Stushar@ece.gatech.edu                    "std::string": "String",
3711666Stushar@ece.gatech.edu                    "bool": "Bool",
3811666Stushar@ece.gatech.edu                    "CacheMemory": "RubyCache",
3911666Stushar@ece.gatech.edu                    "WireBuffer": "RubyWireBuffer",
4011666Stushar@ece.gatech.edu                    "Sequencer": "RubySequencer",
4111666Stushar@ece.gatech.edu                    "DirectoryMemory": "RubyDirectoryMemory",
4211666Stushar@ece.gatech.edu                    "MemoryControl": "MemoryControl",
4311666Stushar@ece.gatech.edu                    "DMASequencer": "DMASequencer"
4411666Stushar@ece.gatech.edu                    }
4511666Stushar@ece.gatech.edu
4611666Stushar@ece.gatech.educlass StateMachine(Symbol):
4711666Stushar@ece.gatech.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
4811666Stushar@ece.gatech.edu        super(StateMachine, self).__init__(symtab, ident, location, pairs)
4911666Stushar@ece.gatech.edu        self.table = None
5011666Stushar@ece.gatech.edu        self.config_parameters = config_parameters
5111666Stushar@ece.gatech.edu
5211666Stushar@ece.gatech.edu        for param in config_parameters:
5311666Stushar@ece.gatech.edu            if param.pointer:
5411666Stushar@ece.gatech.edu                var = Var(symtab, param.name, location, param.type_ast.type,
5511666Stushar@ece.gatech.edu                          "(*m_%s_ptr)" % param.name, {}, self)
5611666Stushar@ece.gatech.edu            else:
5711666Stushar@ece.gatech.edu                var = Var(symtab, param.name, location, param.type_ast.type,
5811666Stushar@ece.gatech.edu                          "m_%s" % param.name, {}, self)
5911666Stushar@ece.gatech.edu            self.symtab.registerSym(param.name, var)
6011666Stushar@ece.gatech.edu
6111666Stushar@ece.gatech.edu        self.states = orderdict()
6211666Stushar@ece.gatech.edu        self.events = orderdict()
6311666Stushar@ece.gatech.edu        self.actions = orderdict()
6411666Stushar@ece.gatech.edu        self.transitions = []
6511666Stushar@ece.gatech.edu        self.in_ports = []
6611666Stushar@ece.gatech.edu        self.functions = []
6711666Stushar@ece.gatech.edu        self.objects = []
6811666Stushar@ece.gatech.edu        self.TBEType   = None
6911666Stushar@ece.gatech.edu        self.EntryType = None
7011666Stushar@ece.gatech.edu
7111666Stushar@ece.gatech.edu        self.message_buffer_names = []
7211666Stushar@ece.gatech.edu
7311666Stushar@ece.gatech.edu    def __repr__(self):
7411666Stushar@ece.gatech.edu        return "[StateMachine: %s]" % self.ident
7511666Stushar@ece.gatech.edu
7611666Stushar@ece.gatech.edu    def addState(self, state):
7711666Stushar@ece.gatech.edu        assert self.table is None
7811666Stushar@ece.gatech.edu        self.states[state.ident] = state
7911666Stushar@ece.gatech.edu
8011666Stushar@ece.gatech.edu    def addEvent(self, event):
8111666Stushar@ece.gatech.edu        assert self.table is None
8211666Stushar@ece.gatech.edu        self.events[event.ident] = event
8311666Stushar@ece.gatech.edu
8411666Stushar@ece.gatech.edu    def addAction(self, action):
8511666Stushar@ece.gatech.edu        assert self.table is None
8611666Stushar@ece.gatech.edu
8711666Stushar@ece.gatech.edu        # Check for duplicate action
8811666Stushar@ece.gatech.edu        for other in self.actions.itervalues():
8911666Stushar@ece.gatech.edu            if action.ident == other.ident:
9011666Stushar@ece.gatech.edu                action.warning("Duplicate action definition: %s" % action.ident)
9111666Stushar@ece.gatech.edu                action.error("Duplicate action definition: %s" % action.ident)
9211666Stushar@ece.gatech.edu            if action.short == other.short:
9311666Stushar@ece.gatech.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
9411666Stushar@ece.gatech.edu                other.warning("    shorthand = %s" % other.short)
9511666Stushar@ece.gatech.edu                action.warning("Duplicate action shorthand: %s" % action.ident)
9611666Stushar@ece.gatech.edu                action.error("    shorthand = %s" % action.short)
9711666Stushar@ece.gatech.edu
9811666Stushar@ece.gatech.edu        self.actions[action.ident] = action
9911666Stushar@ece.gatech.edu
10011666Stushar@ece.gatech.edu    def addTransition(self, trans):
10111666Stushar@ece.gatech.edu        assert self.table is None
10211666Stushar@ece.gatech.edu        self.transitions.append(trans)
10311666Stushar@ece.gatech.edu
10411666Stushar@ece.gatech.edu    def addInPort(self, var):
10511666Stushar@ece.gatech.edu        self.in_ports.append(var)
10611666Stushar@ece.gatech.edu
10711666Stushar@ece.gatech.edu    def addFunc(self, func):
10811666Stushar@ece.gatech.edu        # register func in the symbol table
10911666Stushar@ece.gatech.edu        self.symtab.registerSym(str(func), func)
11011666Stushar@ece.gatech.edu        self.functions.append(func)
11111666Stushar@ece.gatech.edu
11211666Stushar@ece.gatech.edu    def addObject(self, obj):
11311666Stushar@ece.gatech.edu        self.objects.append(obj)
11411666Stushar@ece.gatech.edu
11511666Stushar@ece.gatech.edu    def addType(self, type):
11611666Stushar@ece.gatech.edu        type_ident = '%s' % type.c_ident
11711666Stushar@ece.gatech.edu
11811666Stushar@ece.gatech.edu        if type_ident == "%s_TBE" %self.ident:
11911666Stushar@ece.gatech.edu            if self.TBEType != None:
12011666Stushar@ece.gatech.edu                self.error("Multiple Transaction Buffer types in a " \
12111666Stushar@ece.gatech.edu                           "single machine.");
12211666Stushar@ece.gatech.edu            self.TBEType = type
12311666Stushar@ece.gatech.edu
12411666Stushar@ece.gatech.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
12511666Stushar@ece.gatech.edu            if self.EntryType != None:
12611666Stushar@ece.gatech.edu                self.error("Multiple AbstractCacheEntry types in a " \
12711666Stushar@ece.gatech.edu                           "single machine.");
12811666Stushar@ece.gatech.edu            self.EntryType = type
12911666Stushar@ece.gatech.edu
13011666Stushar@ece.gatech.edu    # Needs to be called before accessing the table
13111666Stushar@ece.gatech.edu    def buildTable(self):
13211666Stushar@ece.gatech.edu        assert self.table is None
13311666Stushar@ece.gatech.edu
13411666Stushar@ece.gatech.edu        table = {}
13511666Stushar@ece.gatech.edu
13611666Stushar@ece.gatech.edu        for trans in self.transitions:
13711666Stushar@ece.gatech.edu            # Track which actions we touch so we know if we use them
13811666Stushar@ece.gatech.edu            # all -- really this should be done for all symbols as
13911666Stushar@ece.gatech.edu            # part of the symbol table, then only trigger it for
14011666Stushar@ece.gatech.edu            # Actions, States, Events, etc.
14111666Stushar@ece.gatech.edu
14211666Stushar@ece.gatech.edu            for action in trans.actions:
14311666Stushar@ece.gatech.edu                action.used = True
14411666Stushar@ece.gatech.edu
14511666Stushar@ece.gatech.edu            index = (trans.state, trans.event)
14611666Stushar@ece.gatech.edu            if index in table:
14711666Stushar@ece.gatech.edu                table[index].warning("Duplicate transition: %s" % table[index])
14811666Stushar@ece.gatech.edu                trans.error("Duplicate transition: %s" % trans)
14911666Stushar@ece.gatech.edu            table[index] = trans
15011666Stushar@ece.gatech.edu
15111666Stushar@ece.gatech.edu        # Look at all actions to make sure we used them all
15211666Stushar@ece.gatech.edu        for action in self.actions.itervalues():
15311666Stushar@ece.gatech.edu            if not action.used:
15411666Stushar@ece.gatech.edu                error_msg = "Unused action: %s" % action.ident
15511666Stushar@ece.gatech.edu                if "desc" in action:
15611666Stushar@ece.gatech.edu                    error_msg += ", "  + action.desc
15711666Stushar@ece.gatech.edu                action.warning(error_msg)
15811666Stushar@ece.gatech.edu        self.table = table
15911666Stushar@ece.gatech.edu
16011666Stushar@ece.gatech.edu    def writeCodeFiles(self, path):
16111666Stushar@ece.gatech.edu        self.printControllerPython(path)
16211666Stushar@ece.gatech.edu        self.printControllerHH(path)
16311666Stushar@ece.gatech.edu        self.printControllerCC(path)
16411666Stushar@ece.gatech.edu        self.printCSwitch(path)
16511666Stushar@ece.gatech.edu        self.printCWakeup(path)
16611666Stushar@ece.gatech.edu        self.printProfilerCC(path)
16711666Stushar@ece.gatech.edu        self.printProfilerHH(path)
16811666Stushar@ece.gatech.edu        self.printProfileDumperCC(path)
16911666Stushar@ece.gatech.edu        self.printProfileDumperHH(path)
17011666Stushar@ece.gatech.edu
17111666Stushar@ece.gatech.edu    def printControllerPython(self, path):
17211666Stushar@ece.gatech.edu        code = self.symtab.codeFormatter()
17311666Stushar@ece.gatech.edu        ident = self.ident
17411666Stushar@ece.gatech.edu        py_ident = "%s_Controller" % ident
17511666Stushar@ece.gatech.edu        c_ident = "%s_Controller" % self.ident
17611666Stushar@ece.gatech.edu        code('''
17711666Stushar@ece.gatech.edufrom m5.params import *
17811666Stushar@ece.gatech.edufrom m5.SimObject import SimObject
17911666Stushar@ece.gatech.edufrom Controller import RubyController
18011666Stushar@ece.gatech.edu
18111666Stushar@ece.gatech.educlass $py_ident(RubyController):
18211666Stushar@ece.gatech.edu    type = '$py_ident'
18311666Stushar@ece.gatech.edu''')
18411666Stushar@ece.gatech.edu        code.indent()
18511666Stushar@ece.gatech.edu        for param in self.config_parameters:
18611666Stushar@ece.gatech.edu            dflt_str = ''
18711666Stushar@ece.gatech.edu            if param.default is not None:
18811666Stushar@ece.gatech.edu                dflt_str = str(param.default) + ', '
18911666Stushar@ece.gatech.edu            if python_class_map.has_key(param.type_ast.type.c_ident):
19011666Stushar@ece.gatech.edu                python_type = python_class_map[param.type_ast.type.c_ident]
19111666Stushar@ece.gatech.edu                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
19211666Stushar@ece.gatech.edu            else:
19311666Stushar@ece.gatech.edu                self.error("Unknown c++ to python class conversion for c++ " \
19411666Stushar@ece.gatech.edu                           "type: '%s'. Please update the python_class_map " \
19511666Stushar@ece.gatech.edu                           "in StateMachine.py", param.type_ast.type.c_ident)
19611666Stushar@ece.gatech.edu        code.dedent()
19711666Stushar@ece.gatech.edu        code.write(path, '%s.py' % py_ident)
19811666Stushar@ece.gatech.edu
19911666Stushar@ece.gatech.edu
20011666Stushar@ece.gatech.edu    def printControllerHH(self, path):
20111666Stushar@ece.gatech.edu        '''Output the method declarations for the class declaration'''
20211666Stushar@ece.gatech.edu        code = self.symtab.codeFormatter()
20311666Stushar@ece.gatech.edu        ident = self.ident
20411666Stushar@ece.gatech.edu        c_ident = "%s_Controller" % self.ident
20511666Stushar@ece.gatech.edu
20611666Stushar@ece.gatech.edu        self.message_buffer_names = []
20711666Stushar@ece.gatech.edu
20811666Stushar@ece.gatech.edu        code('''
20911666Stushar@ece.gatech.edu/** \\file $c_ident.hh
21011666Stushar@ece.gatech.edu *
21111666Stushar@ece.gatech.edu * Auto generated C++ code started by $__file__:$__line__
21211666Stushar@ece.gatech.edu * Created by slicc definition of Module "${{self.short}}"
21311666Stushar@ece.gatech.edu */
21411666Stushar@ece.gatech.edu
21511666Stushar@ece.gatech.edu#ifndef __${ident}_CONTROLLER_HH__
21611666Stushar@ece.gatech.edu#define __${ident}_CONTROLLER_HH__
21711666Stushar@ece.gatech.edu
21811666Stushar@ece.gatech.edu#include <iostream>
21911666Stushar@ece.gatech.edu#include <sstream>
22011666Stushar@ece.gatech.edu#include <string>
22111666Stushar@ece.gatech.edu
22211666Stushar@ece.gatech.edu#include "mem/protocol/${ident}_ProfileDumper.hh"
22311666Stushar@ece.gatech.edu#include "mem/protocol/${ident}_Profiler.hh"
22411666Stushar@ece.gatech.edu#include "mem/protocol/TransitionResult.hh"
22511666Stushar@ece.gatech.edu#include "mem/protocol/Types.hh"
22611666Stushar@ece.gatech.edu#include "mem/ruby/common/Consumer.hh"
22711666Stushar@ece.gatech.edu#include "mem/ruby/common/Global.hh"
22811666Stushar@ece.gatech.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
22911666Stushar@ece.gatech.edu#include "params/$c_ident.hh"
23011666Stushar@ece.gatech.edu''')
23111666Stushar@ece.gatech.edu
23211666Stushar@ece.gatech.edu        seen_types = set()
23311666Stushar@ece.gatech.edu        for var in self.objects:
23411666Stushar@ece.gatech.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
23511666Stushar@ece.gatech.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
23611666Stushar@ece.gatech.edu            seen_types.add(var.type.ident)
23711666Stushar@ece.gatech.edu
23811666Stushar@ece.gatech.edu        # for adding information to the protocol debug trace
23911666Stushar@ece.gatech.edu        code('''
24011666Stushar@ece.gatech.eduextern std::stringstream ${ident}_transitionComment;
24111666Stushar@ece.gatech.edu
242class $c_ident : public AbstractController
243{
244// the coherence checker needs to call isBlockExclusive() and isBlockShared()
245// making the Chip a friend class is an easy way to do this for now
246
247public:
248    typedef ${c_ident}Params Params;
249    $c_ident(const Params *p);
250    static int getNumControllers();
251    void init();
252    MessageBuffer* getMandatoryQueue() const;
253    const int & getVersion() const;
254    const std::string toString() const;
255    const std::string getName() const;
256    void stallBuffer(MessageBuffer* buf, Address addr);
257    void wakeUpBuffers(Address addr);
258    void wakeUpAllBuffers();
259    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
260    void print(std::ostream& out) const;
261    void printConfig(std::ostream& out) const;
262    void wakeup();
263    void printStats(std::ostream& out) const;
264    void clearStats();
265    void blockOnQueue(Address addr, MessageBuffer* port);
266    void unblock(Address addr);
267    void recordCacheTrace(int cntrl, CacheRecorder* tr);
268    Sequencer* getSequencer() const;
269
270private:
271''')
272
273        code.indent()
274        # added by SS
275        for param in self.config_parameters:
276            if param.pointer:
277                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
278            else:
279                code('${{param.type_ast.type}} m_${{param.ident}};')
280
281        code('''
282int m_number_of_TBEs;
283
284TransitionResult doTransition(${ident}_Event event,
285''')
286
287        if self.EntryType != None:
288            code('''
289                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
290''')
291        if self.TBEType != None:
292            code('''
293                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
294''')
295
296        code('''
297                              const Address& addr);
298
299TransitionResult doTransitionWorker(${ident}_Event event,
300                                    ${ident}_State state,
301                                    ${ident}_State& next_state,
302''')
303
304        if self.TBEType != None:
305            code('''
306                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
307''')
308        if self.EntryType != None:
309            code('''
310                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
311''')
312
313        code('''
314                                    const Address& addr);
315
316std::string m_name;
317int m_transitions_per_cycle;
318int m_buffer_size;
319int m_recycle_latency;
320std::map<std::string, std::string> m_cfg;
321NodeID m_version;
322Network* m_net_ptr;
323MachineID m_machineID;
324bool m_is_blocking;
325std::map<Address, MessageBuffer*> m_block_map;
326typedef std::vector<MessageBuffer*> MsgVecType;
327typedef std::map< Address, MsgVecType* > WaitingBufType;
328WaitingBufType m_waiting_buffers;
329int m_max_in_port_rank;
330int m_cur_in_port_rank;
331static ${ident}_ProfileDumper s_profileDumper;
332${ident}_Profiler m_profiler;
333static int m_num_controllers;
334
335// Internal functions
336''')
337
338        for func in self.functions:
339            proto = func.prototype
340            if proto:
341                code('$proto')
342
343        if self.EntryType != None:
344            code('''
345
346// Set and Reset for cache_entry variable
347void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
348void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
349''')
350
351        if self.TBEType != None:
352            code('''
353
354// Set and Reset for tbe variable
355void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
356void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
357''')
358
359        code('''
360
361// Actions
362''')
363        if self.TBEType != None and self.EntryType != None:
364            for action in self.actions.itervalues():
365                code('/** \\brief ${{action.desc}} */')
366                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
367        elif self.TBEType != None:
368            for action in self.actions.itervalues():
369                code('/** \\brief ${{action.desc}} */')
370                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
371        elif self.EntryType != None:
372            for action in self.actions.itervalues():
373                code('/** \\brief ${{action.desc}} */')
374                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
375        else:
376            for action in self.actions.itervalues():
377                code('/** \\brief ${{action.desc}} */')
378                code('void ${{action.ident}}(const Address& addr);')
379
380        # the controller internal variables
381        code('''
382
383// Objects
384''')
385        for var in self.objects:
386            th = var.get("template_hack", "")
387            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
388
389            if var.type.ident == "MessageBuffer":
390                self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
391
392        code.dedent()
393        code('};')
394        code('#endif // __${ident}_CONTROLLER_H__')
395        code.write(path, '%s.hh' % c_ident)
396
397    def printControllerCC(self, path):
398        '''Output the actions for performing the actions'''
399
400        code = self.symtab.codeFormatter()
401        ident = self.ident
402        c_ident = "%s_Controller" % self.ident
403
404        code('''
405/** \\file $c_ident.cc
406 *
407 * Auto generated C++ code started by $__file__:$__line__
408 * Created by slicc definition of Module "${{self.short}}"
409 */
410
411#include <sys/types.h>
412#include <unistd.h>
413
414#include <cassert>
415#include <sstream>
416#include <string>
417
418#include "base/compiler.hh"
419#include "base/cprintf.hh"
420#include "debug/RubyGenerated.hh"
421#include "debug/RubySlicc.hh"
422#include "mem/protocol/${ident}_Controller.hh"
423#include "mem/protocol/${ident}_Event.hh"
424#include "mem/protocol/${ident}_State.hh"
425#include "mem/protocol/Types.hh"
426#include "mem/ruby/common/Global.hh"
427#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
428#include "mem/ruby/system/System.hh"
429
430using namespace std;
431''')
432
433        # include object classes
434        seen_types = set()
435        for var in self.objects:
436            if var.type.ident not in seen_types and not var.type.isPrimitive:
437                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
438            seen_types.add(var.type.ident)
439
440        code('''
441$c_ident *
442${c_ident}Params::create()
443{
444    return new $c_ident(this);
445}
446
447int $c_ident::m_num_controllers = 0;
448${ident}_ProfileDumper $c_ident::s_profileDumper;
449
450// for adding information to the protocol debug trace
451stringstream ${ident}_transitionComment;
452#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
453
454/** \\brief constructor */
455$c_ident::$c_ident(const Params *p)
456    : AbstractController(p)
457{
458    m_version = p->version;
459    m_transitions_per_cycle = p->transitions_per_cycle;
460    m_buffer_size = p->buffer_size;
461    m_recycle_latency = p->recycle_latency;
462    m_number_of_TBEs = p->number_of_TBEs;
463    m_is_blocking = false;
464    m_name = "${ident}";
465''')
466        #
467        # max_port_rank is used to size vectors and thus should be one plus the
468        # largest port rank
469        #
470        max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
471        code('    m_max_in_port_rank = $max_port_rank;')
472        code.indent()
473
474        #
475        # After initializing the universal machine parameters, initialize the
476        # this machines config parameters.  Also detemine if these configuration
477        # params include a sequencer.  This information will be used later for
478        # contecting the sequencer back to the L1 cache controller.
479        #
480        contains_dma_sequencer = False
481        sequencers = []
482        for param in self.config_parameters:
483            if param.name == "dma_sequencer":
484                contains_dma_sequencer = True
485            elif re.compile("sequencer").search(param.name):
486                sequencers.append(param.name)
487            if param.pointer:
488                code('m_${{param.name}}_ptr = p->${{param.name}};')
489            else:
490                code('m_${{param.name}} = p->${{param.name}};')
491
492        #
493        # For the l1 cache controller, add the special atomic support which
494        # includes passing the sequencer a pointer to the controller.
495        #
496        if self.ident == "L1Cache":
497            if not sequencers:
498                self.error("The L1Cache controller must include the sequencer " \
499                           "configuration parameter")
500
501            for seq in sequencers:
502                code('''
503m_${{seq}}_ptr->setController(this);
504    ''')
505
506        else:
507            for seq in sequencers:
508                code('''
509m_${{seq}}_ptr->setController(this);
510    ''')
511
512        #
513        # For the DMA controller, pass the sequencer a pointer to the
514        # controller.
515        #
516        if self.ident == "DMA":
517            if not contains_dma_sequencer:
518                self.error("The DMA controller must include the sequencer " \
519                           "configuration parameter")
520
521            code('''
522m_dma_sequencer_ptr->setController(this);
523''')
524
525        code('m_num_controllers++;')
526        for var in self.objects:
527            if var.ident.find("mandatoryQueue") >= 0:
528                code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
529
530        code.dedent()
531        code('''
532}
533
534void
535$c_ident::init()
536{
537    MachineType machine_type;
538    int base;
539
540    m_machineID.type = MachineType_${ident};
541    m_machineID.num = m_version;
542
543    // initialize objects
544    m_profiler.setVersion(m_version);
545    s_profileDumper.registerProfiler(&m_profiler);
546
547''')
548
549        code.indent()
550        for var in self.objects:
551            vtype = var.type
552            vid = "m_%s_ptr" % var.c_ident
553            if "network" not in var:
554                # Not a network port object
555                if "primitive" in vtype:
556                    code('$vid = new ${{vtype.c_ident}};')
557                    if "default" in var:
558                        code('(*$vid) = ${{var["default"]}};')
559                else:
560                    # Normal Object
561                    # added by SS
562                    if "factory" in var:
563                        code('$vid = ${{var["factory"]}};')
564                    elif var.ident.find("mandatoryQueue") < 0:
565                        th = var.get("template_hack", "")
566                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
567
568                        args = ""
569                        if "non_obj" not in vtype and not vtype.isEnumeration:
570                            if expr.find("TBETable") >= 0:
571                                args = "m_number_of_TBEs"
572                            else:
573                                args = var.get("constructor_hack", "")
574
575                        code('$expr($args);')
576
577                    code('assert($vid != NULL);')
578
579                    if "default" in var:
580                        code('*$vid = ${{var["default"]}}; // Object default')
581                    elif "default" in vtype:
582                        comment = "Type %s default" % vtype.ident
583                        code('*$vid = ${{vtype["default"]}}; // $comment')
584
585                    # Set ordering
586                    if "ordered" in var and "trigger_queue" not in var:
587                        # A buffer
588                        code('$vid->setOrdering(${{var["ordered"]}});')
589
590                    # Set randomization
591                    if "random" in var:
592                        # A buffer
593                        code('$vid->setRandomization(${{var["random"]}});')
594
595                    # Set Priority
596                    if vtype.isBuffer and \
597                           "rank" in var and "trigger_queue" not in var:
598                        code('$vid->setPriority(${{var["rank"]}});')
599
600            else:
601                # Network port object
602                network = var["network"]
603                ordered =  var["ordered"]
604                vnet = var["virtual_network"]
605                vnet_type = var["vnet_type"]
606
607                assert var.machine is not None
608                code('''
609machine_type = string_to_MachineType("${{var.machine.ident}}");
610base = MachineType_base_number(machine_type);
611$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
612''')
613
614                code('assert($vid != NULL);')
615
616                # Set ordering
617                if "ordered" in var:
618                    # A buffer
619                    code('$vid->setOrdering(${{var["ordered"]}});')
620
621                # Set randomization
622                if "random" in var:
623                    # A buffer
624                    code('$vid->setRandomization(${{var["random"]}});')
625
626                # Set Priority
627                if "rank" in var:
628                    code('$vid->setPriority(${{var["rank"]}})')
629
630                # Set buffer size
631                if vtype.isBuffer:
632                    code('''
633if (m_buffer_size > 0) {
634    $vid->resize(m_buffer_size);
635}
636''')
637
638                # set description (may be overriden later by port def)
639                code('''
640$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
641
642''')
643
644            if vtype.isBuffer:
645                if "recycle_latency" in var:
646                    code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
647                else:
648                    code('$vid->setRecycleLatency(m_recycle_latency);')
649
650
651        # Set the queue consumers
652        code()
653        for port in self.in_ports:
654            code('${{port.code}}.setConsumer(this);')
655
656        # Set the queue descriptions
657        code()
658        for port in self.in_ports:
659            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
660
661        # Initialize the transition profiling
662        code()
663        for trans in self.transitions:
664            # Figure out if we stall
665            stall = False
666            for action in trans.actions:
667                if action.ident == "z_stall":
668                    stall = True
669
670            # Only possible if it is not a 'z' case
671            if not stall:
672                state = "%s_State_%s" % (self.ident, trans.state.ident)
673                event = "%s_Event_%s" % (self.ident, trans.event.ident)
674                code('m_profiler.possibleTransition($state, $event);')
675
676        code.dedent()
677        code('}')
678
679        has_mandatory_q = False
680        for port in self.in_ports:
681            if port.code.find("mandatoryQueue_ptr") >= 0:
682                has_mandatory_q = True
683
684        if has_mandatory_q:
685            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
686        else:
687            mq_ident = "NULL"
688
689        seq_ident = "NULL"
690        for param in self.config_parameters:
691            if param.name == "sequencer":
692                assert(param.pointer)
693                seq_ident = "m_%s_ptr" % param.name
694
695        code('''
696int
697$c_ident::getNumControllers()
698{
699    return m_num_controllers;
700}
701
702MessageBuffer*
703$c_ident::getMandatoryQueue() const
704{
705    return $mq_ident;
706}
707
708Sequencer*
709$c_ident::getSequencer() const
710{
711    return $seq_ident;
712}
713
714const int &
715$c_ident::getVersion() const
716{
717    return m_version;
718}
719
720const string
721$c_ident::toString() const
722{
723    return "$c_ident";
724}
725
726const string
727$c_ident::getName() const
728{
729    return m_name;
730}
731
732void
733$c_ident::stallBuffer(MessageBuffer* buf, Address addr)
734{
735    if (m_waiting_buffers.count(addr) == 0) {
736        MsgVecType* msgVec = new MsgVecType;
737        msgVec->resize(m_max_in_port_rank, NULL);
738        m_waiting_buffers[addr] = msgVec;
739    }
740    (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
741}
742
743void
744$c_ident::wakeUpBuffers(Address addr)
745{
746    if (m_waiting_buffers.count(addr) > 0) {
747        //
748        // Wake up all possible lower rank (i.e. lower priority) buffers that could
749        // be waiting on this message.
750        //
751        for (int in_port_rank = m_cur_in_port_rank - 1;
752             in_port_rank >= 0;
753             in_port_rank--) {
754            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
755                (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
756            }
757        }
758        delete m_waiting_buffers[addr];
759        m_waiting_buffers.erase(addr);
760    }
761}
762
763void
764$c_ident::wakeUpAllBuffers()
765{
766    //
767    // Wake up all possible buffers that could be waiting on any message.
768    //
769
770    std::vector<MsgVecType*> wokeUpMsgVecs;
771
772    if(m_waiting_buffers.size() > 0) {
773        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
774             buf_iter != m_waiting_buffers.end();
775             ++buf_iter) {
776             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
777                  vec_iter != buf_iter->second->end();
778                  ++vec_iter) {
779                  if (*vec_iter != NULL) {
780                      (*vec_iter)->reanalyzeAllMessages();
781                  }
782             }
783             wokeUpMsgVecs.push_back(buf_iter->second);
784        }
785
786        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
787             wb_iter != wokeUpMsgVecs.end();
788             ++wb_iter) {
789             delete (*wb_iter);
790        }
791
792        m_waiting_buffers.clear();
793    }
794}
795
796void
797$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
798{
799    m_is_blocking = true;
800    m_block_map[addr] = port;
801}
802
803void
804$c_ident::unblock(Address addr)
805{
806    m_block_map.erase(addr);
807    if (m_block_map.size() == 0) {
808       m_is_blocking = false;
809    }
810}
811
812void
813$c_ident::print(ostream& out) const
814{
815    out << "[$c_ident " << m_version << "]";
816}
817
818void
819$c_ident::printConfig(ostream& out) const
820{
821    out << "$c_ident config: " << m_name << endl;
822    out << "  version: " << m_version << endl;
823    map<string, string>::const_iterator it;
824    for (it = m_cfg.begin(); it != m_cfg.end(); it++)
825        out << "  " << it->first << ": " << it->second << endl;
826}
827
828void
829$c_ident::printStats(ostream& out) const
830{
831''')
832        #
833        # Cache and Memory Controllers have specific profilers associated with
834        # them.  Print out these stats before dumping state transition stats.
835        #
836        for param in self.config_parameters:
837            if param.type_ast.type.ident == "CacheMemory" or \
838               param.type_ast.type.ident == "DirectoryMemory" or \
839                   param.type_ast.type.ident == "MemoryControl":
840                assert(param.pointer)
841                code('    m_${{param.ident}}_ptr->printStats(out);')
842
843        code('''
844    if (m_version == 0) {
845        s_profileDumper.dumpStats(out);
846    }
847}
848
849void $c_ident::clearStats() {
850''')
851        #
852        # Cache and Memory Controllers have specific profilers associated with
853        # them.  These stats must be cleared too.
854        #
855        for param in self.config_parameters:
856            if param.type_ast.type.ident == "CacheMemory" or \
857                   param.type_ast.type.ident == "MemoryControl":
858                assert(param.pointer)
859                code('    m_${{param.ident}}_ptr->clearStats();')
860
861        code('''
862    m_profiler.clearStats();
863}
864''')
865
866        if self.EntryType != None:
867            code('''
868
869// Set and Reset for cache_entry variable
870void
871$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
872{
873  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
874}
875
876void
877$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
878{
879  m_cache_entry_ptr = 0;
880}
881''')
882
883        if self.TBEType != None:
884            code('''
885
886// Set and Reset for tbe variable
887void
888$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
889{
890  m_tbe_ptr = m_new_tbe;
891}
892
893void
894$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
895{
896  m_tbe_ptr = NULL;
897}
898''')
899
900        code('''
901
902void
903$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
904{
905''')
906        #
907        # Record cache contents for all associated caches.
908        #
909        code.indent()
910        for param in self.config_parameters:
911            if param.type_ast.type.ident == "CacheMemory":
912                assert(param.pointer)
913                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
914
915        code.dedent()
916        code('''
917}
918
919// Actions
920''')
921        if self.TBEType != None and self.EntryType != None:
922            for action in self.actions.itervalues():
923                if "c_code" not in action:
924                 continue
925
926                code('''
927/** \\brief ${{action.desc}} */
928void
929$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
930{
931    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
932    ${{action["c_code"]}}
933}
934
935''')
936        elif self.TBEType != None:
937            for action in self.actions.itervalues():
938                if "c_code" not in action:
939                 continue
940
941                code('''
942/** \\brief ${{action.desc}} */
943void
944$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
945{
946    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
947    ${{action["c_code"]}}
948}
949
950''')
951        elif self.EntryType != None:
952            for action in self.actions.itervalues():
953                if "c_code" not in action:
954                 continue
955
956                code('''
957/** \\brief ${{action.desc}} */
958void
959$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
960{
961    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
962    ${{action["c_code"]}}
963}
964
965''')
966        else:
967            for action in self.actions.itervalues():
968                if "c_code" not in action:
969                 continue
970
971                code('''
972/** \\brief ${{action.desc}} */
973void
974$c_ident::${{action.ident}}(const Address& addr)
975{
976    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
977    ${{action["c_code"]}}
978}
979
980''')
981        for func in self.functions:
982            code(func.generateCode())
983
984        code.write(path, "%s.cc" % c_ident)
985
986    def printCWakeup(self, path):
987        '''Output the wakeup loop for the events'''
988
989        code = self.symtab.codeFormatter()
990        ident = self.ident
991
992        code('''
993// Auto generated C++ code started by $__file__:$__line__
994// ${ident}: ${{self.short}}
995
996#include <sys/types.h>
997#include <unistd.h>
998
999#include <cassert>
1000
1001#include "base/misc.hh"
1002#include "debug/RubySlicc.hh"
1003#include "mem/protocol/${ident}_Controller.hh"
1004#include "mem/protocol/${ident}_Event.hh"
1005#include "mem/protocol/${ident}_State.hh"
1006#include "mem/protocol/Types.hh"
1007#include "mem/ruby/common/Global.hh"
1008#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
1009#include "mem/ruby/system/System.hh"
1010
1011using namespace std;
1012
1013void
1014${ident}_Controller::wakeup()
1015{
1016    int counter = 0;
1017    while (true) {
1018        // Some cases will put us into an infinite loop without this limit
1019        assert(counter <= m_transitions_per_cycle);
1020        if (counter == m_transitions_per_cycle) {
1021            // Count how often we are fully utilized
1022            g_system_ptr->getProfiler()->controllerBusy(m_machineID);
1023
1024            // Wakeup in another cycle and try again
1025            g_eventQueue_ptr->scheduleEvent(this, 1);
1026            break;
1027        }
1028''')
1029
1030        code.indent()
1031        code.indent()
1032
1033        # InPorts
1034        #
1035        for port in self.in_ports:
1036            code.indent()
1037            code('// ${ident}InPort $port')
1038            if port.pairs.has_key("rank"):
1039                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1040            else:
1041                code('m_cur_in_port_rank = 0;')
1042            code('${{port["c_code_in_port"]}}')
1043            code.dedent()
1044
1045            code('')
1046
1047        code.dedent()
1048        code.dedent()
1049        code('''
1050        break;  // If we got this far, we have nothing left todo
1051    }
1052    // g_eventQueue_ptr->scheduleEvent(this, 1);
1053}
1054''')
1055
1056        code.write(path, "%s_Wakeup.cc" % self.ident)
1057
1058    def printCSwitch(self, path):
1059        '''Output switch statement for transition table'''
1060
1061        code = self.symtab.codeFormatter()
1062        ident = self.ident
1063
1064        code('''
1065// Auto generated C++ code started by $__file__:$__line__
1066// ${ident}: ${{self.short}}
1067
1068#include <cassert>
1069
1070#include "base/misc.hh"
1071#include "base/trace.hh"
1072#include "debug/ProtocolTrace.hh"
1073#include "debug/RubyGenerated.hh"
1074#include "mem/protocol/${ident}_Controller.hh"
1075#include "mem/protocol/${ident}_Event.hh"
1076#include "mem/protocol/${ident}_State.hh"
1077#include "mem/protocol/Types.hh"
1078#include "mem/ruby/common/Global.hh"
1079#include "mem/ruby/system/System.hh"
1080
1081#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1082
1083#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1084#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1085
1086TransitionResult
1087${ident}_Controller::doTransition(${ident}_Event event,
1088''')
1089        if self.EntryType != None:
1090            code('''
1091                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1092''')
1093        if self.TBEType != None:
1094            code('''
1095                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1096''')
1097        code('''
1098                                  const Address &addr)
1099{
1100''')
1101        if self.TBEType != None and self.EntryType != None:
1102            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1103        elif self.TBEType != None:
1104            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1105        elif self.EntryType != None:
1106            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1107        else:
1108            code('${ident}_State state = getState(addr);')
1109
1110        code('''
1111    ${ident}_State next_state = state;
1112
1113    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1114            *this,
1115            g_eventQueue_ptr->getTime(),
1116            ${ident}_State_to_string(state),
1117            ${ident}_Event_to_string(event),
1118            addr);
1119
1120    TransitionResult result =
1121''')
1122        if self.TBEType != None and self.EntryType != None:
1123            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1124        elif self.TBEType != None:
1125            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1126        elif self.EntryType != None:
1127            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1128        else:
1129            code('doTransitionWorker(event, state, next_state, addr);')
1130
1131        code('''
1132    if (result == TransitionResult_Valid) {
1133        DPRINTF(RubyGenerated, "next_state: %s\\n",
1134                ${ident}_State_to_string(next_state));
1135        m_profiler.countTransition(state, event);
1136        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1137                 curTick(), m_version, "${ident}",
1138                 ${ident}_Event_to_string(event),
1139                 ${ident}_State_to_string(state),
1140                 ${ident}_State_to_string(next_state),
1141                 addr, GET_TRANSITION_COMMENT());
1142
1143        CLEAR_TRANSITION_COMMENT();
1144''')
1145        if self.TBEType != None and self.EntryType != None:
1146            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1147            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1148        elif self.TBEType != None:
1149            code('setState(m_tbe_ptr, addr, next_state);')
1150            code('setAccessPermission(addr, next_state);')
1151        elif self.EntryType != None:
1152            code('setState(m_cache_entry_ptr, addr, next_state);')
1153            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1154        else:
1155            code('setState(addr, next_state);')
1156            code('setAccessPermission(addr, next_state);')
1157
1158        code('''
1159    } else if (result == TransitionResult_ResourceStall) {
1160        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1161                 curTick(), m_version, "${ident}",
1162                 ${ident}_Event_to_string(event),
1163                 ${ident}_State_to_string(state),
1164                 ${ident}_State_to_string(next_state),
1165                 addr, "Resource Stall");
1166    } else if (result == TransitionResult_ProtocolStall) {
1167        DPRINTF(RubyGenerated, "stalling\\n");
1168        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1169                 curTick(), m_version, "${ident}",
1170                 ${ident}_Event_to_string(event),
1171                 ${ident}_State_to_string(state),
1172                 ${ident}_State_to_string(next_state),
1173                 addr, "Protocol Stall");
1174    }
1175
1176    return result;
1177}
1178
1179TransitionResult
1180${ident}_Controller::doTransitionWorker(${ident}_Event event,
1181                                        ${ident}_State state,
1182                                        ${ident}_State& next_state,
1183''')
1184
1185        if self.TBEType != None:
1186            code('''
1187                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1188''')
1189        if self.EntryType != None:
1190                  code('''
1191                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1192''')
1193        code('''
1194                                        const Address& addr)
1195{
1196    switch(HASH_FUN(state, event)) {
1197''')
1198
1199        # This map will allow suppress generating duplicate code
1200        cases = orderdict()
1201
1202        for trans in self.transitions:
1203            case_string = "%s_State_%s, %s_Event_%s" % \
1204                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1205
1206            case = self.symtab.codeFormatter()
1207            # Only set next_state if it changes
1208            if trans.state != trans.nextState:
1209                ns_ident = trans.nextState.ident
1210                case('next_state = ${ident}_State_${ns_ident};')
1211
1212            actions = trans.actions
1213
1214            # Check for resources
1215            case_sorter = []
1216            res = trans.resources
1217            for key,val in res.iteritems():
1218                if key.type.ident != "DNUCAStopTable":
1219                    val = '''
1220if (!%s.areNSlotsAvailable(%s))
1221    return TransitionResult_ResourceStall;
1222''' % (key.code, val)
1223                case_sorter.append(val)
1224
1225
1226            # Emit the code sequences in a sorted order.  This makes the
1227            # output deterministic (without this the output order can vary
1228            # since Map's keys() on a vector of pointers is not deterministic
1229            for c in sorted(case_sorter):
1230                case("$c")
1231
1232            # Figure out if we stall
1233            stall = False
1234            for action in actions:
1235                if action.ident == "z_stall":
1236                    stall = True
1237                    break
1238
1239            if stall:
1240                case('return TransitionResult_ProtocolStall;')
1241            else:
1242                if self.TBEType != None and self.EntryType != None:
1243                    for action in actions:
1244                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1245                elif self.TBEType != None:
1246                    for action in actions:
1247                        case('${{action.ident}}(m_tbe_ptr, addr);')
1248                elif self.EntryType != None:
1249                    for action in actions:
1250                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1251                else:
1252                    for action in actions:
1253                        case('${{action.ident}}(addr);')
1254                case('return TransitionResult_Valid;')
1255
1256            case = str(case)
1257
1258            # Look to see if this transition code is unique.
1259            if case not in cases:
1260                cases[case] = []
1261
1262            cases[case].append(case_string)
1263
1264        # Walk through all of the unique code blocks and spit out the
1265        # corresponding case statement elements
1266        for case,transitions in cases.iteritems():
1267            # Iterative over all the multiple transitions that share
1268            # the same code
1269            for trans in transitions:
1270                code('  case HASH_FUN($trans):')
1271            code('    $case')
1272
1273        code('''
1274      default:
1275        fatal("Invalid transition\\n"
1276              "%s time: %d addr: %s event: %s state: %s\\n",
1277              name(), g_eventQueue_ptr->getTime(), addr, event, state);
1278    }
1279    return TransitionResult_Valid;
1280}
1281''')
1282        code.write(path, "%s_Transitions.cc" % self.ident)
1283
1284    def printProfileDumperHH(self, path):
1285        code = self.symtab.codeFormatter()
1286        ident = self.ident
1287
1288        code('''
1289// Auto generated C++ code started by $__file__:$__line__
1290// ${ident}: ${{self.short}}
1291
1292#ifndef __${ident}_PROFILE_DUMPER_HH__
1293#define __${ident}_PROFILE_DUMPER_HH__
1294
1295#include <cassert>
1296#include <iostream>
1297#include <vector>
1298
1299#include "${ident}_Event.hh"
1300#include "${ident}_Profiler.hh"
1301
1302typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1303
1304class ${ident}_ProfileDumper
1305{
1306  public:
1307    ${ident}_ProfileDumper();
1308    void registerProfiler(${ident}_Profiler* profiler);
1309    void dumpStats(std::ostream& out) const;
1310
1311  private:
1312    ${ident}_profilers m_profilers;
1313};
1314
1315#endif // __${ident}_PROFILE_DUMPER_HH__
1316''')
1317        code.write(path, "%s_ProfileDumper.hh" % self.ident)
1318
1319    def printProfileDumperCC(self, path):
1320        code = self.symtab.codeFormatter()
1321        ident = self.ident
1322
1323        code('''
1324// Auto generated C++ code started by $__file__:$__line__
1325// ${ident}: ${{self.short}}
1326
1327#include "mem/protocol/${ident}_ProfileDumper.hh"
1328
1329${ident}_ProfileDumper::${ident}_ProfileDumper()
1330{
1331}
1332
1333void
1334${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1335{
1336    m_profilers.push_back(profiler);
1337}
1338
1339void
1340${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1341{
1342    out << " --- ${ident} ---\\n";
1343    out << " - Event Counts -\\n";
1344    for (${ident}_Event event = ${ident}_Event_FIRST;
1345         event < ${ident}_Event_NUM;
1346         ++event) {
1347        out << (${ident}_Event) event << " [";
1348        uint64 total = 0;
1349        for (int i = 0; i < m_profilers.size(); i++) {
1350             out << m_profilers[i]->getEventCount(event) << " ";
1351             total += m_profilers[i]->getEventCount(event);
1352        }
1353        out << "] " << total << "\\n";
1354    }
1355    out << "\\n";
1356    out << " - Transitions -\\n";
1357    for (${ident}_State state = ${ident}_State_FIRST;
1358         state < ${ident}_State_NUM;
1359         ++state) {
1360        for (${ident}_Event event = ${ident}_Event_FIRST;
1361             event < ${ident}_Event_NUM;
1362             ++event) {
1363            if (m_profilers[0]->isPossible(state, event)) {
1364                out << (${ident}_State) state << "  "
1365                    << (${ident}_Event) event << " [";
1366                uint64 total = 0;
1367                for (int i = 0; i < m_profilers.size(); i++) {
1368                     out << m_profilers[i]->getTransitionCount(state, event) << " ";
1369                     total += m_profilers[i]->getTransitionCount(state, event);
1370                }
1371                out << "] " << total << "\\n";
1372            }
1373        }
1374        out << "\\n";
1375    }
1376}
1377''')
1378        code.write(path, "%s_ProfileDumper.cc" % self.ident)
1379
1380    def printProfilerHH(self, path):
1381        code = self.symtab.codeFormatter()
1382        ident = self.ident
1383
1384        code('''
1385// Auto generated C++ code started by $__file__:$__line__
1386// ${ident}: ${{self.short}}
1387
1388#ifndef __${ident}_PROFILER_HH__
1389#define __${ident}_PROFILER_HH__
1390
1391#include <cassert>
1392#include <iostream>
1393
1394#include "mem/protocol/${ident}_Event.hh"
1395#include "mem/protocol/${ident}_State.hh"
1396#include "mem/ruby/common/TypeDefines.hh"
1397
1398class ${ident}_Profiler
1399{
1400  public:
1401    ${ident}_Profiler();
1402    void setVersion(int version);
1403    void countTransition(${ident}_State state, ${ident}_Event event);
1404    void possibleTransition(${ident}_State state, ${ident}_Event event);
1405    uint64 getEventCount(${ident}_Event event);
1406    bool isPossible(${ident}_State state, ${ident}_Event event);
1407    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1408    void clearStats();
1409
1410  private:
1411    int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1412    int m_event_counters[${ident}_Event_NUM];
1413    bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1414    int m_version;
1415};
1416
1417#endif // __${ident}_PROFILER_HH__
1418''')
1419        code.write(path, "%s_Profiler.hh" % self.ident)
1420
1421    def printProfilerCC(self, path):
1422        code = self.symtab.codeFormatter()
1423        ident = self.ident
1424
1425        code('''
1426// Auto generated C++ code started by $__file__:$__line__
1427// ${ident}: ${{self.short}}
1428
1429#include <cassert>
1430
1431#include "mem/protocol/${ident}_Profiler.hh"
1432
1433${ident}_Profiler::${ident}_Profiler()
1434{
1435    for (int state = 0; state < ${ident}_State_NUM; state++) {
1436        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1437            m_possible[state][event] = false;
1438            m_counters[state][event] = 0;
1439        }
1440    }
1441    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1442        m_event_counters[event] = 0;
1443    }
1444}
1445
1446void
1447${ident}_Profiler::setVersion(int version)
1448{
1449    m_version = version;
1450}
1451
1452void
1453${ident}_Profiler::clearStats()
1454{
1455    for (int state = 0; state < ${ident}_State_NUM; state++) {
1456        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1457            m_counters[state][event] = 0;
1458        }
1459    }
1460
1461    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1462        m_event_counters[event] = 0;
1463    }
1464}
1465void
1466${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1467{
1468    assert(m_possible[state][event]);
1469    m_counters[state][event]++;
1470    m_event_counters[event]++;
1471}
1472void
1473${ident}_Profiler::possibleTransition(${ident}_State state,
1474                                      ${ident}_Event event)
1475{
1476    m_possible[state][event] = true;
1477}
1478
1479uint64
1480${ident}_Profiler::getEventCount(${ident}_Event event)
1481{
1482    return m_event_counters[event];
1483}
1484
1485bool
1486${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1487{
1488    return m_possible[state][event];
1489}
1490
1491uint64
1492${ident}_Profiler::getTransitionCount(${ident}_State state,
1493                                      ${ident}_Event event)
1494{
1495    return m_counters[state][event];
1496}
1497
1498''')
1499        code.write(path, "%s_Profiler.cc" % self.ident)
1500
1501    # **************************
1502    # ******* HTML Files *******
1503    # **************************
1504    def frameRef(self, click_href, click_target, over_href, over_num, text):
1505        code = self.symtab.codeFormatter(fix_newlines=False)
1506        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1507    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1508        parent.frames[$over_num].location='$over_href'
1509    }\">
1510    ${{html.formatShorthand(text)}}
1511    </A>""")
1512        return str(code)
1513
1514    def writeHTMLFiles(self, path):
1515        # Create table with no row hilighted
1516        self.printHTMLTransitions(path, None)
1517
1518        # Generate transition tables
1519        for state in self.states.itervalues():
1520            self.printHTMLTransitions(path, state)
1521
1522        # Generate action descriptions
1523        for action in self.actions.itervalues():
1524            name = "%s_action_%s.html" % (self.ident, action.ident)
1525            code = html.createSymbol(action, "Action")
1526            code.write(path, name)
1527
1528        # Generate state descriptions
1529        for state in self.states.itervalues():
1530            name = "%s_State_%s.html" % (self.ident, state.ident)
1531            code = html.createSymbol(state, "State")
1532            code.write(path, name)
1533
1534        # Generate event descriptions
1535        for event in self.events.itervalues():
1536            name = "%s_Event_%s.html" % (self.ident, event.ident)
1537            code = html.createSymbol(event, "Event")
1538            code.write(path, name)
1539
1540    def printHTMLTransitions(self, path, active_state):
1541        code = self.symtab.codeFormatter()
1542
1543        code('''
1544<HTML>
1545<BODY link="blue" vlink="blue">
1546
1547<H1 align="center">${{html.formatShorthand(self.short)}}:
1548''')
1549        code.indent()
1550        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1551            mid = machine.ident
1552            if i != 0:
1553                extra = " - "
1554            else:
1555                extra = ""
1556            if machine == self:
1557                code('$extra$mid')
1558            else:
1559                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1560        code.dedent()
1561
1562        code("""
1563</H1>
1564
1565<TABLE border=1>
1566<TR>
1567  <TH> </TH>
1568""")
1569
1570        for event in self.events.itervalues():
1571            href = "%s_Event_%s.html" % (self.ident, event.ident)
1572            ref = self.frameRef(href, "Status", href, "1", event.short)
1573            code('<TH bgcolor=white>$ref</TH>')
1574
1575        code('</TR>')
1576        # -- Body of table
1577        for state in self.states.itervalues():
1578            # -- Each row
1579            if state == active_state:
1580                color = "yellow"
1581            else:
1582                color = "white"
1583
1584            click = "%s_table_%s.html" % (self.ident, state.ident)
1585            over = "%s_State_%s.html" % (self.ident, state.ident)
1586            text = html.formatShorthand(state.short)
1587            ref = self.frameRef(click, "Table", over, "1", state.short)
1588            code('''
1589<TR>
1590  <TH bgcolor=$color>$ref</TH>
1591''')
1592
1593            # -- One column for each event
1594            for event in self.events.itervalues():
1595                trans = self.table.get((state,event), None)
1596                if trans is None:
1597                    # This is the no transition case
1598                    if state == active_state:
1599                        color = "#C0C000"
1600                    else:
1601                        color = "lightgrey"
1602
1603                    code('<TD bgcolor=$color>&nbsp;</TD>')
1604                    continue
1605
1606                next = trans.nextState
1607                stall_action = False
1608
1609                # -- Get the actions
1610                for action in trans.actions:
1611                    if action.ident == "z_stall" or \
1612                       action.ident == "zz_recycleMandatoryQueue":
1613                        stall_action = True
1614
1615                # -- Print out "actions/next-state"
1616                if stall_action:
1617                    if state == active_state:
1618                        color = "#C0C000"
1619                    else:
1620                        color = "lightgrey"
1621
1622                elif active_state and next.ident == active_state.ident:
1623                    color = "aqua"
1624                elif state == active_state:
1625                    color = "yellow"
1626                else:
1627                    color = "white"
1628
1629                code('<TD bgcolor=$color>')
1630                for action in trans.actions:
1631                    href = "%s_action_%s.html" % (self.ident, action.ident)
1632                    ref = self.frameRef(href, "Status", href, "1",
1633                                        action.short)
1634                    code('  $ref')
1635                if next != state:
1636                    if trans.actions:
1637                        code('/')
1638                    click = "%s_table_%s.html" % (self.ident, next.ident)
1639                    over = "%s_State_%s.html" % (self.ident, next.ident)
1640                    ref = self.frameRef(click, "Table", over, "1", next.short)
1641                    code("$ref")
1642                code("</TD>")
1643
1644            # -- Each row
1645            if state == active_state:
1646                color = "yellow"
1647            else:
1648                color = "white"
1649
1650            click = "%s_table_%s.html" % (self.ident, state.ident)
1651            over = "%s_State_%s.html" % (self.ident, state.ident)
1652            ref = self.frameRef(click, "Table", over, "1", state.short)
1653            code('''
1654  <TH bgcolor=$color>$ref</TH>
1655</TR>
1656''')
1657        code('''
1658<!- Column footer->
1659<TR>
1660  <TH> </TH>
1661''')
1662
1663        for event in self.events.itervalues():
1664            href = "%s_Event_%s.html" % (self.ident, event.ident)
1665            ref = self.frameRef(href, "Status", href, "1", event.short)
1666            code('<TH bgcolor=white>$ref</TH>')
1667        code('''
1668</TR>
1669</TABLE>
1670</BODY></HTML>
1671''')
1672
1673
1674        if active_state:
1675            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1676        else:
1677            name = "%s_table.html" % self.ident
1678        code.write(path, name)
1679
1680__all__ = [ "StateMachine" ]
1681