StateMachine.py revision 8055
113606Sciro.santilli@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
27586SAli.Saidi@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company
37586SAli.Saidi@arm.com# All rights reserved.
47586SAli.Saidi@arm.com#
57586SAli.Saidi@arm.com# Redistribution and use in source and binary forms, with or without
67586SAli.Saidi@arm.com# modification, are permitted provided that the following conditions are
77586SAli.Saidi@arm.com# met: redistributions of source code must retain the above copyright
87586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer;
97586SAli.Saidi@arm.com# redistributions in binary form must reproduce the above copyright
107586SAli.Saidi@arm.com# notice, this list of conditions and the following disclaimer in the
117586SAli.Saidi@arm.com# documentation and/or other materials provided with the distribution;
127586SAli.Saidi@arm.com# neither the name of the copyright holders nor the names of its
1310118Snilay@cs.wisc.edu# contributors may be used to endorse or promote products derived from
1410118Snilay@cs.wisc.edu# this software without specific prior written permission.
153970Sgblack@eecs.umich.edu#
163005Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu
283005Sstever@eecs.umich.edufrom m5.util import orderdict
293005Sstever@eecs.umich.edu
303005Sstever@eecs.umich.edufrom slicc.symbols.Symbol import Symbol
313005Sstever@eecs.umich.edufrom slicc.symbols.Var import Var
323005Sstever@eecs.umich.eduimport slicc.generate.html as html
333005Sstever@eecs.umich.edu
343005Sstever@eecs.umich.edupython_class_map = {"int": "Int",
353005Sstever@eecs.umich.edu                    "std::string": "String",
363005Sstever@eecs.umich.edu                    "bool": "Bool",
373005Sstever@eecs.umich.edu                    "CacheMemory": "RubyCache",
383005Sstever@eecs.umich.edu                    "Sequencer": "RubySequencer",
393005Sstever@eecs.umich.edu                    "DirectoryMemory": "RubyDirectoryMemory",
403005Sstever@eecs.umich.edu                    "MemoryControl": "RubyMemoryControl",
413005Sstever@eecs.umich.edu                    "DMASequencer": "DMASequencer"
4210118Snilay@cs.wisc.edu                    }
433005Sstever@eecs.umich.edu
4412564Sgabeblack@google.comclass StateMachine(Symbol):
4513774Sandreas.sandberg@arm.com    def __init__(self, symtab, ident, location, pairs, config_parameters):
4612564Sgabeblack@google.com        super(StateMachine, self).__init__(symtab, ident, location, pairs)
476654Snate@binkert.org        self.table = None
486654Snate@binkert.org        self.config_parameters = config_parameters
492889SN/A
502710SN/A        for param in config_parameters:
516654Snate@binkert.org            if param.pointer:
526654Snate@binkert.org                var = Var(symtab, param.name, location, param.type_ast.type,
5312395Sswapnilster@gmail.com                          "(*m_%s_ptr)" % param.name, {}, self)
5412475Sglenn.bergmans@arm.com            else:
555457Ssaidi@eecs.umich.edu                var = Var(symtab, param.name, location, param.type_ast.type,
5611670Sandreas.hansson@arm.com                          "m_%s" % param.name, {}, self)
5710118Snilay@cs.wisc.edu            self.symtab.registerSym(param.name, var)
5811670Sandreas.hansson@arm.com
596654Snate@binkert.org        self.states = orderdict()
6011682Sandreas.hansson@arm.com        self.events = orderdict()
6111682Sandreas.hansson@arm.com        self.actions = orderdict()
6211682Sandreas.hansson@arm.com        self.transitions = []
6311682Sandreas.hansson@arm.com        self.in_ports = []
6411682Sandreas.hansson@arm.com        self.functions = []
6511682Sandreas.hansson@arm.com        self.objects = []
6611790Sjungma@eit.uni-kl.de        self.TBEType   = None
6713432Spau.cabre@metempsy.com        self.EntryType = None
6811682Sandreas.hansson@arm.com
6911682Sandreas.hansson@arm.com        self.message_buffer_names = []
703444Sktlim@umich.edu
7110594Sgabeblack@google.com    def __repr__(self):
7210594Sgabeblack@google.com        return "[StateMachine: %s]" % self.ident
7312564Sgabeblack@google.com
7412564Sgabeblack@google.com    def addState(self, state):
7510594Sgabeblack@google.com        assert self.table is None
7610594Sgabeblack@google.com        self.states[state.ident] = state
7710594Sgabeblack@google.com
7810594Sgabeblack@google.com    def addEvent(self, event):
7910594Sgabeblack@google.com        assert self.table is None
8010594Sgabeblack@google.com        self.events[event.ident] = event
8110594Sgabeblack@google.com
8210119Snilay@cs.wisc.edu    def addAction(self, action):
8310594Sgabeblack@google.com        assert self.table is None
8410119Snilay@cs.wisc.edu
8510594Sgabeblack@google.com        # Check for duplicate action
8610594Sgabeblack@google.com        for other in self.actions.itervalues():
8710119Snilay@cs.wisc.edu            if action.ident == other.ident:
8810594Sgabeblack@google.com                action.warning("Duplicate action definition: %s" % action.ident)
8910119Snilay@cs.wisc.edu                action.error("Duplicate action definition: %s" % action.ident)
9010594Sgabeblack@google.com            if action.short == other.short:
9110119Snilay@cs.wisc.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
9210119Snilay@cs.wisc.edu                other.warning("    shorthand = %s" % other.short)
9310594Sgabeblack@google.com                action.warning("Duplicate action shorthand: %s" % action.ident)
9410119Snilay@cs.wisc.edu                action.error("    shorthand = %s" % action.short)
9510512SAli.Saidi@ARM.com
9610512SAli.Saidi@ARM.com        self.actions[action.ident] = action
9710594Sgabeblack@google.com
9810780SCurtis.Dunham@arm.com    def addTransition(self, trans):
9912475Sglenn.bergmans@arm.com        assert self.table is None
10012475Sglenn.bergmans@arm.com        self.transitions.append(trans)
10112079Sgedare@rtems.org
10212079Sgedare@rtems.org    def addInPort(self, var):
10310119Snilay@cs.wisc.edu        self.in_ports.append(var)
10410119Snilay@cs.wisc.edu
10510119Snilay@cs.wisc.edu    def addFunc(self, func):
10610119Snilay@cs.wisc.edu        # register func in the symbol table
1072566SN/A        self.symtab.registerSym(str(func), func)
10810119Snilay@cs.wisc.edu        self.functions.append(func)
10910119Snilay@cs.wisc.edu
1109665Sandreas.hansson@arm.com    def addObject(self, obj):
11110119Snilay@cs.wisc.edu        self.objects.append(obj)
11210119Snilay@cs.wisc.edu
11310119Snilay@cs.wisc.edu    def addType(self, type):
11410119Snilay@cs.wisc.edu        type_ident = '%s' % type.c_ident
11510119Snilay@cs.wisc.edu
11610119Snilay@cs.wisc.edu        if type_ident == "%s_TBE" %self.ident:
11710119Snilay@cs.wisc.edu            if self.TBEType != None:
11810119Snilay@cs.wisc.edu                self.error("Multiple Transaction Buffer types in a " \
11910119Snilay@cs.wisc.edu                           "single machine.");
12010119Snilay@cs.wisc.edu            self.TBEType = type
12110119Snilay@cs.wisc.edu
12210119Snilay@cs.wisc.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
12310119Snilay@cs.wisc.edu            if self.EntryType != None:
12410119Snilay@cs.wisc.edu                self.error("Multiple AbstractCacheEntry types in a " \
12510119Snilay@cs.wisc.edu                           "single machine.");
12610119Snilay@cs.wisc.edu            self.EntryType = type
12710119Snilay@cs.wisc.edu
12813803Sodanrc@yahoo.com.br    # Needs to be called before accessing the table
12913803Sodanrc@yahoo.com.br    def buildTable(self):
13013803Sodanrc@yahoo.com.br        assert self.table is None
13110119Snilay@cs.wisc.edu
13210119Snilay@cs.wisc.edu        table = {}
13310119Snilay@cs.wisc.edu
13410119Snilay@cs.wisc.edu        for trans in self.transitions:
13510119Snilay@cs.wisc.edu            # Track which actions we touch so we know if we use them
13610119Snilay@cs.wisc.edu            # all -- really this should be done for all symbols as
13710119Snilay@cs.wisc.edu            # part of the symbol table, then only trigger it for
13810119Snilay@cs.wisc.edu            # Actions, States, Events, etc.
13910119Snilay@cs.wisc.edu
14010119Snilay@cs.wisc.edu            for action in trans.actions:
14110119Snilay@cs.wisc.edu                action.used = True
14210119Snilay@cs.wisc.edu
14310119Snilay@cs.wisc.edu            index = (trans.state, trans.event)
14410119Snilay@cs.wisc.edu            if index in table:
14513731Sandreas.sandberg@arm.com                table[index].warning("Duplicate transition: %s" % table[index])
14610119Snilay@cs.wisc.edu                trans.error("Duplicate transition: %s" % trans)
14712941Sandreas.sandberg@arm.com            table[index] = trans
14811839SCurtis.Dunham@arm.com
14910119Snilay@cs.wisc.edu        # Look at all actions to make sure we used them all
15010119Snilay@cs.wisc.edu        for action in self.actions.itervalues():
15112598Snikos.nikoleris@arm.com            if not action.used:
15210519Snilay@cs.wisc.edu                error_msg = "Unused action: %s" % action.ident
15312598Snikos.nikoleris@arm.com                if "desc" in action:
15410119Snilay@cs.wisc.edu                    error_msg += ", "  + action.desc
15510119Snilay@cs.wisc.edu                action.warning(error_msg)
15610119Snilay@cs.wisc.edu        self.table = table
15710119Snilay@cs.wisc.edu
15810119Snilay@cs.wisc.edu    def writeCodeFiles(self, path):
15910547Snilay@cs.wisc.edu        self.printControllerPython(path)
16010547Snilay@cs.wisc.edu        self.printControllerHH(path)
16110547Snilay@cs.wisc.edu        self.printControllerCC(path)
16210547Snilay@cs.wisc.edu        self.printCSwitch(path)
16310119Snilay@cs.wisc.edu        self.printCWakeup(path)
16410119Snilay@cs.wisc.edu        self.printProfilerCC(path)
16510119Snilay@cs.wisc.edu        self.printProfilerHH(path)
16610119Snilay@cs.wisc.edu        self.printProfileDumperCC(path)
16710119Snilay@cs.wisc.edu        self.printProfileDumperHH(path)
16810119Snilay@cs.wisc.edu
16910119Snilay@cs.wisc.edu        for func in self.functions:
17010119Snilay@cs.wisc.edu            func.writeCodeFiles(path)
17110120Snilay@cs.wisc.edu
17210120Snilay@cs.wisc.edu    def printControllerPython(self, path):
17310119Snilay@cs.wisc.edu        code = self.symtab.codeFormatter()
17411598Sandreas.sandberg@arm.com        ident = self.ident
17510120Snilay@cs.wisc.edu        py_ident = "%s_Controller" % ident
17610120Snilay@cs.wisc.edu        c_ident = "%s_Controller" % self.ident
17710119Snilay@cs.wisc.edu        code('''
17811598Sandreas.sandberg@arm.comfrom m5.params import *
17911150Smitch.hayenga@arm.comfrom m5.SimObject import SimObject
18011150Smitch.hayenga@arm.comfrom Controller import RubyController
18111150Smitch.hayenga@arm.com
18210119Snilay@cs.wisc.educlass $py_ident(RubyController):
1832995SN/A    type = '$py_ident'
18410119Snilay@cs.wisc.edu''')
18510119Snilay@cs.wisc.edu        code.indent()
18610119Snilay@cs.wisc.edu        for param in self.config_parameters:
18710119Snilay@cs.wisc.edu            dflt_str = ''
18810119Snilay@cs.wisc.edu            if param.default is not None:
18910780SCurtis.Dunham@arm.com                dflt_str = str(param.default) + ', '
19010119Snilay@cs.wisc.edu            if python_class_map.has_key(param.type_ast.type.c_ident):
19110119Snilay@cs.wisc.edu                python_type = python_class_map[param.type_ast.type.c_ident]
19210119Snilay@cs.wisc.edu                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
1933304Sstever@eecs.umich.edu            else:
19410119Snilay@cs.wisc.edu                self.error("Unknown c++ to python class conversion for c++ " \
19510608Sdam.sunwoo@arm.com                           "type: '%s'. Please update the python_class_map " \
19613684Sgiacomo.travaglini@arm.com                           "in StateMachine.py", param.type_ast.type.c_ident)
19713012Sandreas.sandberg@arm.com        code.dedent()
19810608Sdam.sunwoo@arm.com        code.write(path, '%s.py' % py_ident)
19910608Sdam.sunwoo@arm.com
20010608Sdam.sunwoo@arm.com
20113731Sandreas.sandberg@arm.com    def printControllerHH(self, path):
20210608Sdam.sunwoo@arm.com        '''Output the method declarations for the class declaration'''
20310608Sdam.sunwoo@arm.com        code = self.symtab.codeFormatter()
20410119Snilay@cs.wisc.edu        ident = self.ident
20510119Snilay@cs.wisc.edu        c_ident = "%s_Controller" % self.ident
20613432Spau.cabre@metempsy.com
20713432Spau.cabre@metempsy.com        self.message_buffer_names = []
20813432Spau.cabre@metempsy.com
20910119Snilay@cs.wisc.edu        code('''
2103819Shsul@eecs.umich.edu/** \\file $c_ident.hh
21111251Sradhika.jagtap@ARM.com *
21211251Sradhika.jagtap@ARM.com * Auto generated C++ code started by $__file__:$__line__
21311251Sradhika.jagtap@ARM.com * Created by slicc definition of Module "${{self.short}}"
21411251Sradhika.jagtap@ARM.com */
21511251Sradhika.jagtap@ARM.com
21611251Sradhika.jagtap@ARM.com#ifndef __${ident}_CONTROLLER_HH__
21711251Sradhika.jagtap@ARM.com#define __${ident}_CONTROLLER_HH__
21811251Sradhika.jagtap@ARM.com
21911251Sradhika.jagtap@ARM.com#include <iostream>
22011251Sradhika.jagtap@ARM.com#include <sstream>
22111251Sradhika.jagtap@ARM.com#include <string>
22210119Snilay@cs.wisc.edu
22311183Serfan.azarkhish@unibo.it#include "params/$c_ident.hh"
22410119Snilay@cs.wisc.edu
22510118Snilay@cs.wisc.edu#include "mem/ruby/common/Global.hh"
22610119Snilay@cs.wisc.edu#include "mem/ruby/common/Consumer.hh"
2279827Sakash.bagdia@arm.com#include "mem/ruby/slicc_interface/AbstractController.hh"
22810119Snilay@cs.wisc.edu#include "mem/protocol/TransitionResult.hh"
22910119Snilay@cs.wisc.edu#include "mem/protocol/Types.hh"
23010119Snilay@cs.wisc.edu#include "mem/protocol/${ident}_Profiler.hh"
23110119Snilay@cs.wisc.edu#include "mem/protocol/${ident}_ProfileDumper.hh"
23210119Snilay@cs.wisc.edu''')
23310119Snilay@cs.wisc.edu
2349827Sakash.bagdia@arm.com        seen_types = set()
23510594Sgabeblack@google.com        for var in self.objects:
2366654Snate@binkert.org            if var.type.ident not in seen_types and not var.type.isPrimitive:
23713803Sodanrc@yahoo.com.br                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
23813803Sodanrc@yahoo.com.br            seen_types.add(var.type.ident)
2396654Snate@binkert.org
24010594Sgabeblack@google.com        # for adding information to the protocol debug trace
2416654Snate@binkert.org        code('''
24210594Sgabeblack@google.comextern std::stringstream ${ident}_transitionComment;
2436654Snate@binkert.org
24410594Sgabeblack@google.comclass $c_ident : public AbstractController
24510594Sgabeblack@google.com{
2467586SAli.Saidi@arm.com// the coherence checker needs to call isBlockExclusive() and isBlockShared()
24710635Satgutier@umich.edu// making the Chip a friend class is an easy way to do this for now
24813606Sciro.santilli@arm.com
2498661SAli.Saidi@ARM.compublic:
2509827Sakash.bagdia@arm.com    typedef ${c_ident}Params Params;
2519827Sakash.bagdia@arm.com    $c_ident(const Params *p);
2529827Sakash.bagdia@arm.com    static int getNumControllers();
2539793Sakash.bagdia@arm.com    void init();
25410119Snilay@cs.wisc.edu    MessageBuffer* getMandatoryQueue() const;
25510119Snilay@cs.wisc.edu    const int & getVersion() const;
2569790Sakash.bagdia@arm.com    const std::string toString() const;
2579827Sakash.bagdia@arm.com    const std::string getName() const;
2589827Sakash.bagdia@arm.com    const MachineType getMachineType() const;
2599827Sakash.bagdia@arm.com    void stallBuffer(MessageBuffer* buf, Address addr);
2609793Sakash.bagdia@arm.com    void wakeUpBuffers(Address addr);
2619827Sakash.bagdia@arm.com    void wakeUpAllBuffers();
2629827Sakash.bagdia@arm.com    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
2639827Sakash.bagdia@arm.com    void print(std::ostream& out) const;
2649793Sakash.bagdia@arm.com    void printConfig(std::ostream& out) const;
2659793Sakash.bagdia@arm.com    void wakeup();
2669793Sakash.bagdia@arm.com    void printStats(std::ostream& out) const;
2679384SAndreas.Sandberg@arm.com    void clearStats();
2688863Snilay@cs.wisc.edu    void blockOnQueue(Address addr, MessageBuffer* port);
2697876Sgblack@eecs.umich.edu    void unblock(Address addr);
2704837Ssaidi@eecs.umich.edu
2714837Ssaidi@eecs.umich.eduprivate:
27213803Sodanrc@yahoo.com.br''')
27313803Sodanrc@yahoo.com.br
27413803Sodanrc@yahoo.com.br        code.indent()
2759408Sandreas.hansson@arm.com        # added by SS
27612941Sandreas.sandberg@arm.com        for param in self.config_parameters:
27711839SCurtis.Dunham@arm.com            if param.pointer:
2789653SAndreas.Sandberg@ARM.com                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
2799164Sandreas.hansson@arm.com            else:
2809408Sandreas.hansson@arm.com                code('${{param.type_ast.type}} m_${{param.ident}};')
2818845Sandreas.hansson@arm.com
2828845Sandreas.hansson@arm.com        code('''
2834837Ssaidi@eecs.umich.eduint m_number_of_TBEs;
2849826Sandreas.hansson@arm.com
2859826Sandreas.hansson@arm.comTransitionResult doTransition(${ident}_Event event,
2869835Sandreas.hansson@arm.com''')
2879826Sandreas.hansson@arm.com
28813731Sandreas.sandberg@arm.com        if self.EntryType != None:
2899826Sandreas.hansson@arm.com            code('''
2909826Sandreas.hansson@arm.com                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
2918659SAli.Saidi@ARM.com''')
29210119Snilay@cs.wisc.edu        if self.TBEType != None:
29310119Snilay@cs.wisc.edu            code('''
29410119Snilay@cs.wisc.edu                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
29510119Snilay@cs.wisc.edu''')
29610119Snilay@cs.wisc.edu
29710119Snilay@cs.wisc.edu        code('''
29810119Snilay@cs.wisc.edu                              const Address& addr);
29910119Snilay@cs.wisc.edu
30010119Snilay@cs.wisc.eduTransitionResult doTransitionWorker(${ident}_Event event,
30110119Snilay@cs.wisc.edu                                    ${ident}_State state,
30210119Snilay@cs.wisc.edu                                    ${ident}_State& next_state,
30310119Snilay@cs.wisc.edu''')
30410119Snilay@cs.wisc.edu
30510119Snilay@cs.wisc.edu        if self.TBEType != None:
30610119Snilay@cs.wisc.edu            code('''
30712564Sgabeblack@google.com                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
30810119Snilay@cs.wisc.edu''')
30910119Snilay@cs.wisc.edu        if self.EntryType != None:
31010119Snilay@cs.wisc.edu            code('''
31110119Snilay@cs.wisc.edu                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
31210119Snilay@cs.wisc.edu''')
31310119Snilay@cs.wisc.edu
31410119Snilay@cs.wisc.edu        code('''
31510119Snilay@cs.wisc.edu                                    const Address& addr);
31610119Snilay@cs.wisc.edu
31710119Snilay@cs.wisc.edustd::string m_name;
31810119Snilay@cs.wisc.eduint m_transitions_per_cycle;
31910119Snilay@cs.wisc.eduint m_buffer_size;
32012564Sgabeblack@google.comint m_recycle_latency;
32112564Sgabeblack@google.comstd::map<std::string, std::string> m_cfg;
32210119Snilay@cs.wisc.eduNodeID m_version;
32310119Snilay@cs.wisc.eduNetwork* m_net_ptr;
32410119Snilay@cs.wisc.eduMachineID m_machineID;
32510697SCurtis.Dunham@arm.combool m_is_blocking;
32610747SChris.Emmons@arm.comstd::map<Address, MessageBuffer*> m_block_map;
32710697SCurtis.Dunham@arm.comtypedef std::vector<MessageBuffer*> MsgVecType;
32810747SChris.Emmons@arm.comtypedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
32910119Snilay@cs.wisc.eduWaitingBufType m_waiting_buffers;
33010697SCurtis.Dunham@arm.comint m_max_in_port_rank;
33110747SChris.Emmons@arm.comint m_cur_in_port_rank;
33210119Snilay@cs.wisc.edustatic ${ident}_ProfileDumper s_profileDumper;
33310119Snilay@cs.wisc.edu${ident}_Profiler m_profiler;
33410119Snilay@cs.wisc.edustatic int m_num_controllers;
33510119Snilay@cs.wisc.edu
33610119Snilay@cs.wisc.edu// Internal functions
33710119Snilay@cs.wisc.edu''')
3388801Sgblack@eecs.umich.edu
33911291Sgabor.dozsa@arm.com        for func in self.functions:
34011291Sgabor.dozsa@arm.com            proto = func.prototype
34111291Sgabor.dozsa@arm.com            if proto:
34211291Sgabor.dozsa@arm.com                code('$proto')
34311291Sgabor.dozsa@arm.com
34411291Sgabor.dozsa@arm.com        if self.EntryType != None:
34511291Sgabor.dozsa@arm.com            code('''
34611291Sgabor.dozsa@arm.com
34711291Sgabor.dozsa@arm.com// Set and Reset for cache_entry variable
34811291Sgabor.dozsa@arm.comvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
34911291Sgabor.dozsa@arm.comvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
35011291Sgabor.dozsa@arm.com''')
3513005Sstever@eecs.umich.edu
3528801Sgblack@eecs.umich.edu        if self.TBEType != None:
3533005Sstever@eecs.umich.edu            code('''
35412564Sgabeblack@google.com
3553005Sstever@eecs.umich.edu// Set and Reset for tbe variable
3562566SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3577861Sgblack@eecs.umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3587861Sgblack@eecs.umich.edu''')
3597861Sgblack@eecs.umich.edu
3608635Schris.emmons@arm.com        code('''
3618635Schris.emmons@arm.com
3628635Schris.emmons@arm.com// Actions
36313606Sciro.santilli@arm.com''')
36413606Sciro.santilli@arm.com        if self.TBEType != None and self.EntryType != None:
36512475Sglenn.bergmans@arm.com            for action in self.actions.itervalues():
36612475Sglenn.bergmans@arm.com                code('/** \\brief ${{action.desc}} */')
36712475Sglenn.bergmans@arm.com                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
36812475Sglenn.bergmans@arm.com        elif self.TBEType != None:
36912475Sglenn.bergmans@arm.com            for action in self.actions.itervalues():
37012475Sglenn.bergmans@arm.com                code('/** \\brief ${{action.desc}} */')
37112475Sglenn.bergmans@arm.com                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
37212475Sglenn.bergmans@arm.com        elif self.EntryType != None:
37312475Sglenn.bergmans@arm.com            for action in self.actions.itervalues():
37413608Sgiacomo.travaglini@arm.com                code('/** \\brief ${{action.desc}} */')
37512475Sglenn.bergmans@arm.com                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
3769061Snilay@cs.wisc.edu        else:
3773481Shsul@eecs.umich.edu            for action in self.actions.itervalues():
378                code('/** \\brief ${{action.desc}} */')
379                code('void ${{action.ident}}(const Address& addr);')
380
381        # the controller internal variables
382        code('''
383
384// Objects
385''')
386        for var in self.objects:
387            th = var.get("template_hack", "")
388            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
389
390            if var.type.ident == "MessageBuffer":
391                self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
392
393        code.dedent()
394        code('};')
395        code('#endif // __${ident}_CONTROLLER_H__')
396        code.write(path, '%s.hh' % c_ident)
397
398    def printControllerCC(self, path):
399        '''Output the actions for performing the actions'''
400
401        code = self.symtab.codeFormatter()
402        ident = self.ident
403        c_ident = "%s_Controller" % self.ident
404
405        code('''
406/** \\file $c_ident.cc
407 *
408 * Auto generated C++ code started by $__file__:$__line__
409 * Created by slicc definition of Module "${{self.short}}"
410 */
411
412#include <cassert>
413#include <sstream>
414#include <string>
415
416#include "base/cprintf.hh"
417#include "mem/protocol/${ident}_Controller.hh"
418#include "mem/protocol/${ident}_State.hh"
419#include "mem/protocol/${ident}_Event.hh"
420#include "mem/protocol/Types.hh"
421#include "mem/ruby/common/Global.hh"
422#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
423#include "mem/ruby/system/System.hh"
424
425using namespace std;
426''')
427
428        # include object classes
429        seen_types = set()
430        for var in self.objects:
431            if var.type.ident not in seen_types and not var.type.isPrimitive:
432                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
433            seen_types.add(var.type.ident)
434
435        code('''
436$c_ident *
437${c_ident}Params::create()
438{
439    return new $c_ident(this);
440}
441
442int $c_ident::m_num_controllers = 0;
443${ident}_ProfileDumper $c_ident::s_profileDumper;
444
445// for adding information to the protocol debug trace
446stringstream ${ident}_transitionComment;
447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
448
449/** \\brief constructor */
450$c_ident::$c_ident(const Params *p)
451    : AbstractController(p)
452{
453    m_version = p->version;
454    m_transitions_per_cycle = p->transitions_per_cycle;
455    m_buffer_size = p->buffer_size;
456    m_recycle_latency = p->recycle_latency;
457    m_number_of_TBEs = p->number_of_TBEs;
458    m_is_blocking = false;
459''')
460        #
461        # max_port_rank is used to size vectors and thus should be one plus the
462        # largest port rank
463        #
464        max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
465        code('    m_max_in_port_rank = $max_port_rank;')
466        code.indent()
467
468        #
469        # After initializing the universal machine parameters, initialize the
470        # this machines config parameters.  Also detemine if these configuration
471        # params include a sequencer.  This information will be used later for
472        # contecting the sequencer back to the L1 cache controller.
473        #
474        contains_sequencer = False
475        for param in self.config_parameters:
476            if param.name == "sequencer" or param.name == "dma_sequencer":
477                contains_sequencer = True
478            if param.pointer:
479                code('m_${{param.name}}_ptr = p->${{param.name}};')
480            else:
481                code('m_${{param.name}} = p->${{param.name}};')
482
483        #
484        # For the l1 cache controller, add the special atomic support which
485        # includes passing the sequencer a pointer to the controller.
486        #
487        if self.ident == "L1Cache":
488            if not contains_sequencer:
489                self.error("The L1Cache controller must include the sequencer " \
490                           "configuration parameter")
491
492            code('''
493m_sequencer_ptr->setController(this);
494''')
495        #
496        # For the DMA controller, pass the sequencer a pointer to the
497        # controller.
498        #
499        if self.ident == "DMA":
500            if not contains_sequencer:
501                self.error("The DMA controller must include the sequencer " \
502                           "configuration parameter")
503
504            code('''
505m_dma_sequencer_ptr->setController(this);
506''')
507
508        code('m_num_controllers++;')
509        for var in self.objects:
510            if var.ident.find("mandatoryQueue") >= 0:
511                code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
512
513        code.dedent()
514        code('''
515}
516
517void
518$c_ident::init()
519{
520    MachineType machine_type;
521    int base;
522
523    m_machineID.type = MachineType_${ident};
524    m_machineID.num = m_version;
525
526    // initialize objects
527    m_profiler.setVersion(m_version);
528    s_profileDumper.registerProfiler(&m_profiler);
529
530''')
531
532        code.indent()
533        for var in self.objects:
534            vtype = var.type
535            vid = "m_%s_ptr" % var.c_ident
536            if "network" not in var:
537                # Not a network port object
538                if "primitive" in vtype:
539                    code('$vid = new ${{vtype.c_ident}};')
540                    if "default" in var:
541                        code('(*$vid) = ${{var["default"]}};')
542                else:
543                    # Normal Object
544                    # added by SS
545                    if "factory" in var:
546                        code('$vid = ${{var["factory"]}};')
547                    elif var.ident.find("mandatoryQueue") < 0:
548                        th = var.get("template_hack", "")
549                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
550
551                        args = ""
552                        if "non_obj" not in vtype and not vtype.isEnumeration:
553                            if expr.find("TBETable") >= 0:
554                                args = "m_number_of_TBEs"
555                            else:
556                                args = var.get("constructor_hack", "")
557
558                        code('$expr($args);')
559
560                    code('assert($vid != NULL);')
561
562                    if "default" in var:
563                        code('*$vid = ${{var["default"]}}; // Object default')
564                    elif "default" in vtype:
565                        comment = "Type %s default" % vtype.ident
566                        code('*$vid = ${{vtype["default"]}}; // $comment')
567
568                    # Set ordering
569                    if "ordered" in var and "trigger_queue" not in var:
570                        # A buffer
571                        code('$vid->setOrdering(${{var["ordered"]}});')
572
573                    # Set randomization
574                    if "random" in var:
575                        # A buffer
576                        code('$vid->setRandomization(${{var["random"]}});')
577
578                    # Set Priority
579                    if vtype.isBuffer and \
580                           "rank" in var and "trigger_queue" not in var:
581                        code('$vid->setPriority(${{var["rank"]}});')
582
583            else:
584                # Network port object
585                network = var["network"]
586                ordered =  var["ordered"]
587                vnet = var["virtual_network"]
588
589                assert var.machine is not None
590                code('''
591machine_type = string_to_MachineType("${{var.machine.ident}}");
592base = MachineType_base_number(machine_type);
593$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
594''')
595
596                code('assert($vid != NULL);')
597
598                # Set ordering
599                if "ordered" in var:
600                    # A buffer
601                    code('$vid->setOrdering(${{var["ordered"]}});')
602
603                # Set randomization
604                if "random" in var:
605                    # A buffer
606                    code('$vid->setRandomization(${{var["random"]}})')
607
608                # Set Priority
609                if "rank" in var:
610                    code('$vid->setPriority(${{var["rank"]}})')
611
612                # Set buffer size
613                if vtype.isBuffer:
614                    code('''
615if (m_buffer_size > 0) {
616    $vid->resize(m_buffer_size);
617}
618''')
619
620                # set description (may be overriden later by port def)
621                code('''
622$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
623
624''')
625
626            if vtype.isBuffer:
627                if "recycle_latency" in var:
628                    code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
629                else:
630                    code('$vid->setRecycleLatency(m_recycle_latency);')
631
632
633        # Set the queue consumers
634        code()
635        for port in self.in_ports:
636            code('${{port.code}}.setConsumer(this);')
637
638        # Set the queue descriptions
639        code()
640        for port in self.in_ports:
641            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
642
643        # Initialize the transition profiling
644        code()
645        for trans in self.transitions:
646            # Figure out if we stall
647            stall = False
648            for action in trans.actions:
649                if action.ident == "z_stall":
650                    stall = True
651
652            # Only possible if it is not a 'z' case
653            if not stall:
654                state = "%s_State_%s" % (self.ident, trans.state.ident)
655                event = "%s_Event_%s" % (self.ident, trans.event.ident)
656                code('m_profiler.possibleTransition($state, $event);')
657
658        code.dedent()
659        code('}')
660
661        has_mandatory_q = False
662        for port in self.in_ports:
663            if port.code.find("mandatoryQueue_ptr") >= 0:
664                has_mandatory_q = True
665
666        if has_mandatory_q:
667            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
668        else:
669            mq_ident = "NULL"
670
671        code('''
672int
673$c_ident::getNumControllers()
674{
675    return m_num_controllers;
676}
677
678MessageBuffer*
679$c_ident::getMandatoryQueue() const
680{
681    return $mq_ident;
682}
683
684const int &
685$c_ident::getVersion() const
686{
687    return m_version;
688}
689
690const string
691$c_ident::toString() const
692{
693    return "$c_ident";
694}
695
696const string
697$c_ident::getName() const
698{
699    return m_name;
700}
701
702const MachineType
703$c_ident::getMachineType() const
704{
705    return MachineType_${ident};
706}
707
708void
709$c_ident::stallBuffer(MessageBuffer* buf, Address addr)
710{
711    if (m_waiting_buffers.count(addr) == 0) {
712        MsgVecType* msgVec = new MsgVecType;
713        msgVec->resize(m_max_in_port_rank, NULL);
714        m_waiting_buffers[addr] = msgVec;
715    }
716    (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
717}
718
719void
720$c_ident::wakeUpBuffers(Address addr)
721{
722    //
723    // Wake up all possible lower rank (i.e. lower priority) buffers that could
724    // be waiting on this message.
725    //
726    for (int in_port_rank = m_cur_in_port_rank - 1;
727         in_port_rank >= 0;
728         in_port_rank--) {
729        if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
730            (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
731        }
732    }
733    delete m_waiting_buffers[addr];
734    m_waiting_buffers.erase(addr);
735}
736
737void
738$c_ident::wakeUpAllBuffers()
739{
740    //
741    // Wake up all possible buffers that could be waiting on any message.
742    //
743
744    std::vector<MsgVecType*> wokeUpMsgVecs;
745
746    for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
747         buf_iter != m_waiting_buffers.end();
748         ++buf_iter) {
749         for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
750              vec_iter != buf_iter->second->end();
751              ++vec_iter) {
752              if (*vec_iter != NULL) {
753                  (*vec_iter)->reanalyzeAllMessages();
754              }
755         }
756         wokeUpMsgVecs.push_back(buf_iter->second);
757    }
758
759    for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
760         wb_iter != wokeUpMsgVecs.end();
761         ++wb_iter) {
762         delete (*wb_iter);
763    }
764
765    m_waiting_buffers.clear();
766}
767
768void
769$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
770{
771    m_is_blocking = true;
772    m_block_map[addr] = port;
773}
774
775void
776$c_ident::unblock(Address addr)
777{
778    m_block_map.erase(addr);
779    if (m_block_map.size() == 0) {
780       m_is_blocking = false;
781    }
782}
783
784void
785$c_ident::print(ostream& out) const
786{
787    out << "[$c_ident " << m_version << "]";
788}
789
790void
791$c_ident::printConfig(ostream& out) const
792{
793    out << "$c_ident config: " << m_name << endl;
794    out << "  version: " << m_version << endl;
795    map<string, string>::const_iterator it;
796    for (it = m_cfg.begin(); it != m_cfg.end(); it++)
797        out << "  " << it->first << ": " << it->second << endl;
798}
799
800void
801$c_ident::printStats(ostream& out) const
802{
803''')
804        #
805        # Cache and Memory Controllers have specific profilers associated with
806        # them.  Print out these stats before dumping state transition stats.
807        #
808        for param in self.config_parameters:
809            if param.type_ast.type.ident == "CacheMemory" or \
810               param.type_ast.type.ident == "DirectoryMemory" or \
811                   param.type_ast.type.ident == "MemoryControl":
812                assert(param.pointer)
813                code('    m_${{param.ident}}_ptr->printStats(out);')
814
815        code('''
816    if (m_version == 0) {
817        s_profileDumper.dumpStats(out);
818    }
819}
820
821void $c_ident::clearStats() {
822''')
823        #
824        # Cache and Memory Controllers have specific profilers associated with
825        # them.  These stats must be cleared too.
826        #
827        for param in self.config_parameters:
828            if param.type_ast.type.ident == "CacheMemory" or \
829                   param.type_ast.type.ident == "MemoryControl":
830                assert(param.pointer)
831                code('    m_${{param.ident}}_ptr->clearStats();')
832
833        code('''
834    m_profiler.clearStats();
835}
836''')
837
838        if self.EntryType != None:
839            code('''
840
841// Set and Reset for cache_entry variable
842void
843$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
844{
845  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
846}
847
848void
849$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
850{
851  m_cache_entry_ptr = 0;
852}
853''')
854
855        if self.TBEType != None:
856            code('''
857
858// Set and Reset for tbe variable
859void
860$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
861{
862  m_tbe_ptr = m_new_tbe;
863}
864
865void
866$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
867{
868  m_tbe_ptr = NULL;
869}
870''')
871
872        code('''
873
874// Actions
875''')
876        if self.TBEType != None and self.EntryType != None:
877            for action in self.actions.itervalues():
878                if "c_code" not in action:
879                 continue
880
881                code('''
882/** \\brief ${{action.desc}} */
883void
884$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
885{
886    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
887    ${{action["c_code"]}}
888}
889
890''')
891        elif self.TBEType != None:
892            for action in self.actions.itervalues():
893                if "c_code" not in action:
894                 continue
895
896                code('''
897/** \\brief ${{action.desc}} */
898void
899$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
900{
901    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
902    ${{action["c_code"]}}
903}
904
905''')
906        elif self.EntryType != None:
907            for action in self.actions.itervalues():
908                if "c_code" not in action:
909                 continue
910
911                code('''
912/** \\brief ${{action.desc}} */
913void
914$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
915{
916    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
917    ${{action["c_code"]}}
918}
919
920''')
921        else:
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}}(const Address& addr)
930{
931    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
932    ${{action["c_code"]}}
933}
934
935''')
936        code.write(path, "%s.cc" % c_ident)
937
938    def printCWakeup(self, path):
939        '''Output the wakeup loop for the events'''
940
941        code = self.symtab.codeFormatter()
942        ident = self.ident
943
944        code('''
945// Auto generated C++ code started by $__file__:$__line__
946// ${ident}: ${{self.short}}
947
948#include <cassert>
949
950#include "base/misc.hh"
951#include "mem/ruby/common/Global.hh"
952#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
953#include "mem/protocol/${ident}_Controller.hh"
954#include "mem/protocol/${ident}_State.hh"
955#include "mem/protocol/${ident}_Event.hh"
956#include "mem/protocol/Types.hh"
957#include "mem/ruby/system/System.hh"
958
959using namespace std;
960
961void
962${ident}_Controller::wakeup()
963{
964    int counter = 0;
965    while (true) {
966        // Some cases will put us into an infinite loop without this limit
967        assert(counter <= m_transitions_per_cycle);
968        if (counter == m_transitions_per_cycle) {
969            // Count how often we are fully utilized
970            g_system_ptr->getProfiler()->controllerBusy(m_machineID);
971
972            // Wakeup in another cycle and try again
973            g_eventQueue_ptr->scheduleEvent(this, 1);
974            break;
975        }
976''')
977
978        code.indent()
979        code.indent()
980
981        # InPorts
982        #
983        for port in self.in_ports:
984            code.indent()
985            code('// ${ident}InPort $port')
986            if port.pairs.has_key("rank"):
987                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
988            else:
989                code('m_cur_in_port_rank = 0;')
990            code('${{port["c_code_in_port"]}}')
991            code.dedent()
992
993            code('')
994
995        code.dedent()
996        code.dedent()
997        code('''
998        break;  // If we got this far, we have nothing left todo
999    }
1000    // g_eventQueue_ptr->scheduleEvent(this, 1);
1001}
1002''')
1003
1004        code.write(path, "%s_Wakeup.cc" % self.ident)
1005
1006    def printCSwitch(self, path):
1007        '''Output switch statement for transition table'''
1008
1009        code = self.symtab.codeFormatter()
1010        ident = self.ident
1011
1012        code('''
1013// Auto generated C++ code started by $__file__:$__line__
1014// ${ident}: ${{self.short}}
1015
1016#include <cassert>
1017
1018#include "base/misc.hh"
1019#include "base/trace.hh"
1020#include "mem/ruby/common/Global.hh"
1021#include "mem/protocol/${ident}_Controller.hh"
1022#include "mem/protocol/${ident}_State.hh"
1023#include "mem/protocol/${ident}_Event.hh"
1024#include "mem/protocol/Types.hh"
1025#include "mem/ruby/system/System.hh"
1026
1027#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1028
1029#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1030#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1031
1032TransitionResult
1033${ident}_Controller::doTransition(${ident}_Event event,
1034''')
1035        if self.EntryType != None:
1036            code('''
1037                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1038''')
1039        if self.TBEType != None:
1040            code('''
1041                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1042''')
1043        code('''
1044                                  const Address &addr)
1045{
1046''')
1047        if self.TBEType != None and self.EntryType != None:
1048            code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1049        elif self.TBEType != None:
1050            code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);')
1051        elif self.EntryType != None:
1052            code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);')
1053        else:
1054            code('${ident}_State state = ${ident}_getState(addr);')
1055
1056        code('''
1057    ${ident}_State next_state = state;
1058
1059    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1060            *this,
1061            g_eventQueue_ptr->getTime(),
1062            ${ident}_State_to_string(state),
1063            ${ident}_Event_to_string(event),
1064            addr);
1065
1066    TransitionResult result =
1067''')
1068        if self.TBEType != None and self.EntryType != None:
1069            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1070        elif self.TBEType != None:
1071            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1072        elif self.EntryType != None:
1073            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1074        else:
1075            code('doTransitionWorker(event, state, next_state, addr);')
1076
1077        code('''
1078    if (result == TransitionResult_Valid) {
1079        DPRINTF(RubyGenerated, "next_state: %s\\n",
1080                ${ident}_State_to_string(next_state));
1081        m_profiler.countTransition(state, event);
1082        DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n",
1083            g_eventQueue_ptr->getTime(), m_version, "${ident}",
1084            ${ident}_Event_to_string(event),
1085            ${ident}_State_to_string(state),
1086            ${ident}_State_to_string(next_state),
1087            addr, GET_TRANSITION_COMMENT());
1088
1089        CLEAR_TRANSITION_COMMENT();
1090''')
1091        if self.TBEType != None and self.EntryType != None:
1092            code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1093        elif self.TBEType != None:
1094            code('${ident}_setState(m_tbe_ptr, addr, next_state);')
1095        elif self.EntryType != None:
1096            code('${ident}_setState(m_cache_entry_ptr, addr, next_state);')
1097        else:
1098            code('${ident}_setState(addr, next_state);')
1099
1100        code('''
1101    } else if (result == TransitionResult_ResourceStall) {
1102        DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1103            g_eventQueue_ptr->getTime(), m_version, "${ident}",
1104            ${ident}_Event_to_string(event),
1105            ${ident}_State_to_string(state),
1106            ${ident}_State_to_string(next_state),
1107            addr, "Resource Stall");
1108    } else if (result == TransitionResult_ProtocolStall) {
1109        DPRINTF(RubyGenerated, "stalling\\n");
1110        DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1111            g_eventQueue_ptr->getTime(), m_version, "${ident}",
1112            ${ident}_Event_to_string(event),
1113            ${ident}_State_to_string(state),
1114            ${ident}_State_to_string(next_state),
1115            addr, "Protocol Stall");
1116    }
1117
1118    return result;
1119}
1120
1121TransitionResult
1122${ident}_Controller::doTransitionWorker(${ident}_Event event,
1123                                        ${ident}_State state,
1124                                        ${ident}_State& next_state,
1125''')
1126
1127        if self.TBEType != None:
1128            code('''
1129                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1130''')
1131        if self.EntryType != None:
1132                  code('''
1133                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1134''')
1135        code('''
1136                                        const Address& addr)
1137{
1138    switch(HASH_FUN(state, event)) {
1139''')
1140
1141        # This map will allow suppress generating duplicate code
1142        cases = orderdict()
1143
1144        for trans in self.transitions:
1145            case_string = "%s_State_%s, %s_Event_%s" % \
1146                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1147
1148            case = self.symtab.codeFormatter()
1149            # Only set next_state if it changes
1150            if trans.state != trans.nextState:
1151                ns_ident = trans.nextState.ident
1152                case('next_state = ${ident}_State_${ns_ident};')
1153
1154            actions = trans.actions
1155
1156            # Check for resources
1157            case_sorter = []
1158            res = trans.resources
1159            for key,val in res.iteritems():
1160                if key.type.ident != "DNUCAStopTable":
1161                    val = '''
1162if (!%s.areNSlotsAvailable(%s))
1163    return TransitionResult_ResourceStall;
1164''' % (key.code, val)
1165                case_sorter.append(val)
1166
1167
1168            # Emit the code sequences in a sorted order.  This makes the
1169            # output deterministic (without this the output order can vary
1170            # since Map's keys() on a vector of pointers is not deterministic
1171            for c in sorted(case_sorter):
1172                case("$c")
1173
1174            # Figure out if we stall
1175            stall = False
1176            for action in actions:
1177                if action.ident == "z_stall":
1178                    stall = True
1179                    break
1180
1181            if stall:
1182                case('return TransitionResult_ProtocolStall;')
1183            else:
1184                if self.TBEType != None and self.EntryType != None:
1185                    for action in actions:
1186                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1187                elif self.TBEType != None:
1188                    for action in actions:
1189                        case('${{action.ident}}(m_tbe_ptr, addr);')
1190                elif self.EntryType != None:
1191                    for action in actions:
1192                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1193                else:
1194                    for action in actions:
1195                        case('${{action.ident}}(addr);')
1196                case('return TransitionResult_Valid;')
1197
1198            case = str(case)
1199
1200            # Look to see if this transition code is unique.
1201            if case not in cases:
1202                cases[case] = []
1203
1204            cases[case].append(case_string)
1205
1206        # Walk through all of the unique code blocks and spit out the
1207        # corresponding case statement elements
1208        for case,transitions in cases.iteritems():
1209            # Iterative over all the multiple transitions that share
1210            # the same code
1211            for trans in transitions:
1212                code('  case HASH_FUN($trans):')
1213            code('    $case')
1214
1215        code('''
1216      default:
1217        fatal("Invalid transition\\n"
1218              "version: %d time: %d addr: %s event: %s state: %s\\n",
1219              m_version, g_eventQueue_ptr->getTime(), addr, event, state);
1220    }
1221    return TransitionResult_Valid;
1222}
1223''')
1224        code.write(path, "%s_Transitions.cc" % self.ident)
1225
1226    def printProfileDumperHH(self, path):
1227        code = self.symtab.codeFormatter()
1228        ident = self.ident
1229
1230        code('''
1231// Auto generated C++ code started by $__file__:$__line__
1232// ${ident}: ${{self.short}}
1233
1234#ifndef __${ident}_PROFILE_DUMPER_HH__
1235#define __${ident}_PROFILE_DUMPER_HH__
1236
1237#include <cassert>
1238#include <iostream>
1239#include <vector>
1240
1241#include "${ident}_Profiler.hh"
1242#include "${ident}_Event.hh"
1243
1244typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1245
1246class ${ident}_ProfileDumper
1247{
1248  public:
1249    ${ident}_ProfileDumper();
1250    void registerProfiler(${ident}_Profiler* profiler);
1251    void dumpStats(std::ostream& out) const;
1252
1253  private:
1254    ${ident}_profilers m_profilers;
1255};
1256
1257#endif // __${ident}_PROFILE_DUMPER_HH__
1258''')
1259        code.write(path, "%s_ProfileDumper.hh" % self.ident)
1260
1261    def printProfileDumperCC(self, path):
1262        code = self.symtab.codeFormatter()
1263        ident = self.ident
1264
1265        code('''
1266// Auto generated C++ code started by $__file__:$__line__
1267// ${ident}: ${{self.short}}
1268
1269#include "mem/protocol/${ident}_ProfileDumper.hh"
1270
1271${ident}_ProfileDumper::${ident}_ProfileDumper()
1272{
1273}
1274
1275void
1276${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1277{
1278    m_profilers.push_back(profiler);
1279}
1280
1281void
1282${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1283{
1284    out << " --- ${ident} ---\\n";
1285    out << " - Event Counts -\\n";
1286    for (${ident}_Event event = ${ident}_Event_FIRST;
1287         event < ${ident}_Event_NUM;
1288         ++event) {
1289        out << (${ident}_Event) event << " [";
1290        uint64 total = 0;
1291        for (int i = 0; i < m_profilers.size(); i++) {
1292             out << m_profilers[i]->getEventCount(event) << " ";
1293             total += m_profilers[i]->getEventCount(event);
1294        }
1295        out << "] " << total << "\\n";
1296    }
1297    out << "\\n";
1298    out << " - Transitions -\\n";
1299    for (${ident}_State state = ${ident}_State_FIRST;
1300         state < ${ident}_State_NUM;
1301         ++state) {
1302        for (${ident}_Event event = ${ident}_Event_FIRST;
1303             event < ${ident}_Event_NUM;
1304             ++event) {
1305            if (m_profilers[0]->isPossible(state, event)) {
1306                out << (${ident}_State) state << "  "
1307                    << (${ident}_Event) event << " [";
1308                uint64 total = 0;
1309                for (int i = 0; i < m_profilers.size(); i++) {
1310                     out << m_profilers[i]->getTransitionCount(state, event) << " ";
1311                     total += m_profilers[i]->getTransitionCount(state, event);
1312                }
1313                out << "] " << total << "\\n";
1314            }
1315        }
1316        out << "\\n";
1317    }
1318}
1319''')
1320        code.write(path, "%s_ProfileDumper.cc" % self.ident)
1321
1322    def printProfilerHH(self, path):
1323        code = self.symtab.codeFormatter()
1324        ident = self.ident
1325
1326        code('''
1327// Auto generated C++ code started by $__file__:$__line__
1328// ${ident}: ${{self.short}}
1329
1330#ifndef __${ident}_PROFILER_HH__
1331#define __${ident}_PROFILER_HH__
1332
1333#include <cassert>
1334#include <iostream>
1335
1336#include "mem/ruby/common/Global.hh"
1337#include "mem/protocol/${ident}_State.hh"
1338#include "mem/protocol/${ident}_Event.hh"
1339
1340class ${ident}_Profiler
1341{
1342  public:
1343    ${ident}_Profiler();
1344    void setVersion(int version);
1345    void countTransition(${ident}_State state, ${ident}_Event event);
1346    void possibleTransition(${ident}_State state, ${ident}_Event event);
1347    uint64 getEventCount(${ident}_Event event);
1348    bool isPossible(${ident}_State state, ${ident}_Event event);
1349    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1350    void clearStats();
1351
1352  private:
1353    int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1354    int m_event_counters[${ident}_Event_NUM];
1355    bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1356    int m_version;
1357};
1358
1359#endif // __${ident}_PROFILER_HH__
1360''')
1361        code.write(path, "%s_Profiler.hh" % self.ident)
1362
1363    def printProfilerCC(self, path):
1364        code = self.symtab.codeFormatter()
1365        ident = self.ident
1366
1367        code('''
1368// Auto generated C++ code started by $__file__:$__line__
1369// ${ident}: ${{self.short}}
1370
1371#include <cassert>
1372
1373#include "mem/protocol/${ident}_Profiler.hh"
1374
1375${ident}_Profiler::${ident}_Profiler()
1376{
1377    for (int state = 0; state < ${ident}_State_NUM; state++) {
1378        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1379            m_possible[state][event] = false;
1380            m_counters[state][event] = 0;
1381        }
1382    }
1383    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1384        m_event_counters[event] = 0;
1385    }
1386}
1387
1388void
1389${ident}_Profiler::setVersion(int version)
1390{
1391    m_version = version;
1392}
1393
1394void
1395${ident}_Profiler::clearStats()
1396{
1397    for (int state = 0; state < ${ident}_State_NUM; state++) {
1398        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1399            m_counters[state][event] = 0;
1400        }
1401    }
1402
1403    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1404        m_event_counters[event] = 0;
1405    }
1406}
1407void
1408${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1409{
1410    assert(m_possible[state][event]);
1411    m_counters[state][event]++;
1412    m_event_counters[event]++;
1413}
1414void
1415${ident}_Profiler::possibleTransition(${ident}_State state,
1416                                      ${ident}_Event event)
1417{
1418    m_possible[state][event] = true;
1419}
1420
1421uint64
1422${ident}_Profiler::getEventCount(${ident}_Event event)
1423{
1424    return m_event_counters[event];
1425}
1426
1427bool
1428${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1429{
1430    return m_possible[state][event];
1431}
1432
1433uint64
1434${ident}_Profiler::getTransitionCount(${ident}_State state,
1435                                      ${ident}_Event event)
1436{
1437    return m_counters[state][event];
1438}
1439
1440''')
1441        code.write(path, "%s_Profiler.cc" % self.ident)
1442
1443    # **************************
1444    # ******* HTML Files *******
1445    # **************************
1446    def frameRef(self, click_href, click_target, over_href, over_num, text):
1447        code = self.symtab.codeFormatter(fix_newlines=False)
1448        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1449    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1450        parent.frames[$over_num].location='$over_href'
1451    }\">
1452    ${{html.formatShorthand(text)}}
1453    </A>""")
1454        return str(code)
1455
1456    def writeHTMLFiles(self, path):
1457        # Create table with no row hilighted
1458        self.printHTMLTransitions(path, None)
1459
1460        # Generate transition tables
1461        for state in self.states.itervalues():
1462            self.printHTMLTransitions(path, state)
1463
1464        # Generate action descriptions
1465        for action in self.actions.itervalues():
1466            name = "%s_action_%s.html" % (self.ident, action.ident)
1467            code = html.createSymbol(action, "Action")
1468            code.write(path, name)
1469
1470        # Generate state descriptions
1471        for state in self.states.itervalues():
1472            name = "%s_State_%s.html" % (self.ident, state.ident)
1473            code = html.createSymbol(state, "State")
1474            code.write(path, name)
1475
1476        # Generate event descriptions
1477        for event in self.events.itervalues():
1478            name = "%s_Event_%s.html" % (self.ident, event.ident)
1479            code = html.createSymbol(event, "Event")
1480            code.write(path, name)
1481
1482    def printHTMLTransitions(self, path, active_state):
1483        code = self.symtab.codeFormatter()
1484
1485        code('''
1486<HTML>
1487<BODY link="blue" vlink="blue">
1488
1489<H1 align="center">${{html.formatShorthand(self.short)}}:
1490''')
1491        code.indent()
1492        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1493            mid = machine.ident
1494            if i != 0:
1495                extra = " - "
1496            else:
1497                extra = ""
1498            if machine == self:
1499                code('$extra$mid')
1500            else:
1501                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1502        code.dedent()
1503
1504        code("""
1505</H1>
1506
1507<TABLE border=1>
1508<TR>
1509  <TH> </TH>
1510""")
1511
1512        for event in self.events.itervalues():
1513            href = "%s_Event_%s.html" % (self.ident, event.ident)
1514            ref = self.frameRef(href, "Status", href, "1", event.short)
1515            code('<TH bgcolor=white>$ref</TH>')
1516
1517        code('</TR>')
1518        # -- Body of table
1519        for state in self.states.itervalues():
1520            # -- Each row
1521            if state == active_state:
1522                color = "yellow"
1523            else:
1524                color = "white"
1525
1526            click = "%s_table_%s.html" % (self.ident, state.ident)
1527            over = "%s_State_%s.html" % (self.ident, state.ident)
1528            text = html.formatShorthand(state.short)
1529            ref = self.frameRef(click, "Table", over, "1", state.short)
1530            code('''
1531<TR>
1532  <TH bgcolor=$color>$ref</TH>
1533''')
1534
1535            # -- One column for each event
1536            for event in self.events.itervalues():
1537                trans = self.table.get((state,event), None)
1538                if trans is None:
1539                    # This is the no transition case
1540                    if state == active_state:
1541                        color = "#C0C000"
1542                    else:
1543                        color = "lightgrey"
1544
1545                    code('<TD bgcolor=$color>&nbsp;</TD>')
1546                    continue
1547
1548                next = trans.nextState
1549                stall_action = False
1550
1551                # -- Get the actions
1552                for action in trans.actions:
1553                    if action.ident == "z_stall" or \
1554                       action.ident == "zz_recycleMandatoryQueue":
1555                        stall_action = True
1556
1557                # -- Print out "actions/next-state"
1558                if stall_action:
1559                    if state == active_state:
1560                        color = "#C0C000"
1561                    else:
1562                        color = "lightgrey"
1563
1564                elif active_state and next.ident == active_state.ident:
1565                    color = "aqua"
1566                elif state == active_state:
1567                    color = "yellow"
1568                else:
1569                    color = "white"
1570
1571                code('<TD bgcolor=$color>')
1572                for action in trans.actions:
1573                    href = "%s_action_%s.html" % (self.ident, action.ident)
1574                    ref = self.frameRef(href, "Status", href, "1",
1575                                        action.short)
1576                    code('  $ref')
1577                if next != state:
1578                    if trans.actions:
1579                        code('/')
1580                    click = "%s_table_%s.html" % (self.ident, next.ident)
1581                    over = "%s_State_%s.html" % (self.ident, next.ident)
1582                    ref = self.frameRef(click, "Table", over, "1", next.short)
1583                    code("$ref")
1584                code("</TD>")
1585
1586            # -- Each row
1587            if state == active_state:
1588                color = "yellow"
1589            else:
1590                color = "white"
1591
1592            click = "%s_table_%s.html" % (self.ident, state.ident)
1593            over = "%s_State_%s.html" % (self.ident, state.ident)
1594            ref = self.frameRef(click, "Table", over, "1", state.short)
1595            code('''
1596  <TH bgcolor=$color>$ref</TH>
1597</TR>
1598''')
1599        code('''
1600<!- Column footer->
1601<TR>
1602  <TH> </TH>
1603''')
1604
1605        for event in self.events.itervalues():
1606            href = "%s_Event_%s.html" % (self.ident, event.ident)
1607            ref = self.frameRef(href, "Status", href, "1", event.short)
1608            code('<TH bgcolor=white>$ref</TH>')
1609        code('''
1610</TR>
1611</TABLE>
1612</BODY></HTML>
1613''')
1614
1615
1616        if active_state:
1617            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1618        else:
1619            name = "%s_table.html" % self.ident
1620        code.write(path, name)
1621
1622__all__ = [ "StateMachine" ]
1623