StateMachine.py revision 9801
111598Sandreas.sandberg@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.eduimport re
343005Sstever@eecs.umich.edu
353005Sstever@eecs.umich.edupython_class_map = {
363005Sstever@eecs.umich.edu                    "int": "Int",
373005Sstever@eecs.umich.edu                    "uint32_t" : "UInt32",
383005Sstever@eecs.umich.edu                    "std::string": "String",
393005Sstever@eecs.umich.edu                    "bool": "Bool",
403005Sstever@eecs.umich.edu                    "CacheMemory": "RubyCache",
413005Sstever@eecs.umich.edu                    "WireBuffer": "RubyWireBuffer",
4210118Snilay@cs.wisc.edu                    "Sequencer": "RubySequencer",
433005Sstever@eecs.umich.edu                    "DirectoryMemory": "RubyDirectoryMemory",
446654Snate@binkert.org                    "MemoryControl": "MemoryControl",
456654Snate@binkert.org                    "DMASequencer": "DMASequencer",
462889SN/A                    "Prefetcher":"Prefetcher",
472710SN/A                    "Cycles":"Cycles",
486654Snate@binkert.org                   }
496654Snate@binkert.org
506654Snate@binkert.orgclass StateMachine(Symbol):
515457Ssaidi@eecs.umich.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
5211670Sandreas.hansson@arm.com        super(StateMachine, self).__init__(symtab, ident, location, pairs)
5310118Snilay@cs.wisc.edu        self.table = None
5411670Sandreas.hansson@arm.com        self.config_parameters = config_parameters
556654Snate@binkert.org        self.prefetchers = []
5611682Sandreas.hansson@arm.com
5711682Sandreas.hansson@arm.com        for param in config_parameters:
5811682Sandreas.hansson@arm.com            if param.pointer:
5911682Sandreas.hansson@arm.com                var = Var(symtab, param.name, location, param.type_ast.type,
6011682Sandreas.hansson@arm.com                          "(*m_%s_ptr)" % param.name, {}, self)
6111682Sandreas.hansson@arm.com            else:
6211790Sjungma@eit.uni-kl.de                var = Var(symtab, param.name, location, param.type_ast.type,
6311682Sandreas.hansson@arm.com                          "m_%s" % param.name, {}, self)
6411682Sandreas.hansson@arm.com            self.symtab.registerSym(param.name, var)
653444Sktlim@umich.edu            if str(param.type_ast.type) == "Prefetcher":
663304Sstever@eecs.umich.edu                self.prefetchers.append(var)
679653SAndreas.Sandberg@ARM.com
689653SAndreas.Sandberg@ARM.com        self.states = orderdict()
699653SAndreas.Sandberg@ARM.com        self.events = orderdict()
709653SAndreas.Sandberg@ARM.com        self.actions = orderdict()
719653SAndreas.Sandberg@ARM.com        self.request_types = orderdict()
729653SAndreas.Sandberg@ARM.com        self.transitions = []
739653SAndreas.Sandberg@ARM.com        self.in_ports = []
7410594Sgabeblack@google.com        self.functions = []
7510594Sgabeblack@google.com        self.objects = []
7610594Sgabeblack@google.com        self.TBEType   = None
7710594Sgabeblack@google.com        self.EntryType = None
7810594Sgabeblack@google.com
7910594Sgabeblack@google.com    def __repr__(self):
8010594Sgabeblack@google.com        return "[StateMachine: %s]" % self.ident
8110594Sgabeblack@google.com
8210594Sgabeblack@google.com    def addState(self, state):
8310594Sgabeblack@google.com        assert self.table is None
8410594Sgabeblack@google.com        self.states[state.ident] = state
8510119Snilay@cs.wisc.edu
8610594Sgabeblack@google.com    def addEvent(self, event):
8710119Snilay@cs.wisc.edu        assert self.table is None
8810594Sgabeblack@google.com        self.events[event.ident] = event
8910594Sgabeblack@google.com
9010119Snilay@cs.wisc.edu    def addAction(self, action):
9110594Sgabeblack@google.com        assert self.table is None
9210119Snilay@cs.wisc.edu
9310594Sgabeblack@google.com        # Check for duplicate action
9410119Snilay@cs.wisc.edu        for other in self.actions.itervalues():
9510119Snilay@cs.wisc.edu            if action.ident == other.ident:
9610594Sgabeblack@google.com                action.warning("Duplicate action definition: %s" % action.ident)
9710119Snilay@cs.wisc.edu                action.error("Duplicate action definition: %s" % action.ident)
9810512SAli.Saidi@ARM.com            if action.short == other.short:
9910512SAli.Saidi@ARM.com                other.warning("Duplicate action shorthand: %s" % other.ident)
10010594Sgabeblack@google.com                other.warning("    shorthand = %s" % other.short)
10110780SCurtis.Dunham@arm.com                action.warning("Duplicate action shorthand: %s" % action.ident)
10211598Sandreas.sandberg@arm.com                action.error("    shorthand = %s" % action.short)
10311598Sandreas.sandberg@arm.com
10410119Snilay@cs.wisc.edu        self.actions[action.ident] = action
10510119Snilay@cs.wisc.edu
10610119Snilay@cs.wisc.edu    def addRequestType(self, request_type):
10710119Snilay@cs.wisc.edu        assert self.table is None
1082566SN/A        self.request_types[request_type.ident] = request_type
10910119Snilay@cs.wisc.edu
11010119Snilay@cs.wisc.edu    def addTransition(self, trans):
1119665Sandreas.hansson@arm.com        assert self.table is None
11210119Snilay@cs.wisc.edu        self.transitions.append(trans)
11310119Snilay@cs.wisc.edu
11410119Snilay@cs.wisc.edu    def addInPort(self, var):
11510119Snilay@cs.wisc.edu        self.in_ports.append(var)
11610119Snilay@cs.wisc.edu
11710119Snilay@cs.wisc.edu    def addFunc(self, func):
11810119Snilay@cs.wisc.edu        # register func in the symbol table
11910119Snilay@cs.wisc.edu        self.symtab.registerSym(str(func), func)
12010119Snilay@cs.wisc.edu        self.functions.append(func)
12110119Snilay@cs.wisc.edu
12210119Snilay@cs.wisc.edu    def addObject(self, obj):
12310119Snilay@cs.wisc.edu        self.objects.append(obj)
12410119Snilay@cs.wisc.edu
12510119Snilay@cs.wisc.edu    def addType(self, type):
12610119Snilay@cs.wisc.edu        type_ident = '%s' % type.c_ident
12710119Snilay@cs.wisc.edu
12810119Snilay@cs.wisc.edu        if type_ident == "%s_TBE" %self.ident:
12910119Snilay@cs.wisc.edu            if self.TBEType != None:
13010119Snilay@cs.wisc.edu                self.error("Multiple Transaction Buffer types in a " \
13110119Snilay@cs.wisc.edu                           "single machine.");
13210119Snilay@cs.wisc.edu            self.TBEType = type
13310119Snilay@cs.wisc.edu
13410119Snilay@cs.wisc.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
13510119Snilay@cs.wisc.edu            if self.EntryType != None:
13610119Snilay@cs.wisc.edu                self.error("Multiple AbstractCacheEntry types in a " \
13710119Snilay@cs.wisc.edu                           "single machine.");
13810119Snilay@cs.wisc.edu            self.EntryType = type
13910119Snilay@cs.wisc.edu
14010119Snilay@cs.wisc.edu    # Needs to be called before accessing the table
14110119Snilay@cs.wisc.edu    def buildTable(self):
14210119Snilay@cs.wisc.edu        assert self.table is None
14310119Snilay@cs.wisc.edu
14410119Snilay@cs.wisc.edu        table = {}
14510119Snilay@cs.wisc.edu
14611839SCurtis.Dunham@arm.com        for trans in self.transitions:
14710119Snilay@cs.wisc.edu            # Track which actions we touch so we know if we use them
14810119Snilay@cs.wisc.edu            # all -- really this should be done for all symbols as
14910119Snilay@cs.wisc.edu            # part of the symbol table, then only trigger it for
15010119Snilay@cs.wisc.edu            # Actions, States, Events, etc.
15110119Snilay@cs.wisc.edu
15210119Snilay@cs.wisc.edu            for action in trans.actions:
15310119Snilay@cs.wisc.edu                action.used = True
15410519Snilay@cs.wisc.edu
15510519Snilay@cs.wisc.edu            index = (trans.state, trans.event)
15610119Snilay@cs.wisc.edu            if index in table:
15710119Snilay@cs.wisc.edu                table[index].warning("Duplicate transition: %s" % table[index])
15810119Snilay@cs.wisc.edu                trans.error("Duplicate transition: %s" % trans)
15910119Snilay@cs.wisc.edu            table[index] = trans
16010119Snilay@cs.wisc.edu
16110547Snilay@cs.wisc.edu        # Look at all actions to make sure we used them all
16210547Snilay@cs.wisc.edu        for action in self.actions.itervalues():
16310547Snilay@cs.wisc.edu            if not action.used:
16410547Snilay@cs.wisc.edu                error_msg = "Unused action: %s" % action.ident
16510119Snilay@cs.wisc.edu                if "desc" in action:
16610119Snilay@cs.wisc.edu                    error_msg += ", "  + action.desc
16710119Snilay@cs.wisc.edu                action.warning(error_msg)
16810119Snilay@cs.wisc.edu        self.table = table
16910119Snilay@cs.wisc.edu
17010119Snilay@cs.wisc.edu    def writeCodeFiles(self, path, includes):
17110119Snilay@cs.wisc.edu        self.printControllerPython(path)
17210119Snilay@cs.wisc.edu        self.printControllerHH(path)
17310120Snilay@cs.wisc.edu        self.printControllerCC(path, includes)
17410120Snilay@cs.wisc.edu        self.printCSwitch(path)
17510119Snilay@cs.wisc.edu        self.printCWakeup(path, includes)
17611598Sandreas.sandberg@arm.com
17710120Snilay@cs.wisc.edu    def printControllerPython(self, path):
17810120Snilay@cs.wisc.edu        code = self.symtab.codeFormatter()
17910119Snilay@cs.wisc.edu        ident = self.ident
18011598Sandreas.sandberg@arm.com        py_ident = "%s_Controller" % ident
18111150Smitch.hayenga@arm.com        c_ident = "%s_Controller" % self.ident
18211150Smitch.hayenga@arm.com        code('''
18311150Smitch.hayenga@arm.comfrom m5.params import *
18410119Snilay@cs.wisc.edufrom m5.SimObject import SimObject
1852995SN/Afrom Controller import RubyController
18610119Snilay@cs.wisc.edu
18710119Snilay@cs.wisc.educlass $py_ident(RubyController):
18810119Snilay@cs.wisc.edu    type = '$py_ident'
18910119Snilay@cs.wisc.edu    cxx_header = 'mem/protocol/${c_ident}.hh'
19010119Snilay@cs.wisc.edu''')
19110780SCurtis.Dunham@arm.com        code.indent()
19210119Snilay@cs.wisc.edu        for param in self.config_parameters:
19310119Snilay@cs.wisc.edu            dflt_str = ''
19410119Snilay@cs.wisc.edu            if param.default is not None:
1953304Sstever@eecs.umich.edu                dflt_str = str(param.default) + ', '
19610119Snilay@cs.wisc.edu            if python_class_map.has_key(param.type_ast.type.c_ident):
19710119Snilay@cs.wisc.edu                python_type = python_class_map[param.type_ast.type.c_ident]
19810119Snilay@cs.wisc.edu                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
19910119Snilay@cs.wisc.edu            else:
20010119Snilay@cs.wisc.edu                self.error("Unknown c++ to python class conversion for c++ " \
20110119Snilay@cs.wisc.edu                           "type: '%s'. Please update the python_class_map " \
2026135Sgblack@eecs.umich.edu                           "in StateMachine.py", param.type_ast.type.c_ident)
20310608Sdam.sunwoo@arm.com        code.dedent()
20410608Sdam.sunwoo@arm.com        code.write(path, '%s.py' % py_ident)
20510608Sdam.sunwoo@arm.com
20610608Sdam.sunwoo@arm.com
20710608Sdam.sunwoo@arm.com    def printControllerHH(self, path):
20810608Sdam.sunwoo@arm.com        '''Output the method declarations for the class declaration'''
20910608Sdam.sunwoo@arm.com        code = self.symtab.codeFormatter()
21010119Snilay@cs.wisc.edu        ident = self.ident
21110119Snilay@cs.wisc.edu        c_ident = "%s_Controller" % self.ident
21210119Snilay@cs.wisc.edu
21310608Sdam.sunwoo@arm.com        code('''
21410608Sdam.sunwoo@arm.com/** \\file $c_ident.hh
21510119Snilay@cs.wisc.edu *
21610119Snilay@cs.wisc.edu * Auto generated C++ code started by $__file__:$__line__
21710119Snilay@cs.wisc.edu * Created by slicc definition of Module "${{self.short}}"
2183819Shsul@eecs.umich.edu */
21911251Sradhika.jagtap@ARM.com
22011251Sradhika.jagtap@ARM.com#ifndef __${ident}_CONTROLLER_HH__
22111251Sradhika.jagtap@ARM.com#define __${ident}_CONTROLLER_HH__
22211251Sradhika.jagtap@ARM.com
22311251Sradhika.jagtap@ARM.com#include <iostream>
22411251Sradhika.jagtap@ARM.com#include <sstream>
22511251Sradhika.jagtap@ARM.com#include <string>
22611251Sradhika.jagtap@ARM.com
22711251Sradhika.jagtap@ARM.com#include "mem/protocol/TransitionResult.hh"
22811251Sradhika.jagtap@ARM.com#include "mem/protocol/Types.hh"
22911251Sradhika.jagtap@ARM.com#include "mem/ruby/common/Consumer.hh"
23010119Snilay@cs.wisc.edu#include "mem/ruby/common/Global.hh"
23111183Serfan.azarkhish@unibo.it#include "mem/ruby/slicc_interface/AbstractController.hh"
23210119Snilay@cs.wisc.edu#include "params/$c_ident.hh"
23310118Snilay@cs.wisc.edu''')
23410119Snilay@cs.wisc.edu
2359827Sakash.bagdia@arm.com        seen_types = set()
23610119Snilay@cs.wisc.edu        has_peer = False
23710119Snilay@cs.wisc.edu        for var in self.objects:
23810119Snilay@cs.wisc.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
23910119Snilay@cs.wisc.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
24010119Snilay@cs.wisc.edu            if "network" in var and "physical_network" in var:
24110119Snilay@cs.wisc.edu                has_peer = True
2429827Sakash.bagdia@arm.com            seen_types.add(var.type.ident)
24310594Sgabeblack@google.com
2446654Snate@binkert.org        # for adding information to the protocol debug trace
24510594Sgabeblack@google.com        code('''
2466654Snate@binkert.orgextern std::stringstream ${ident}_transitionComment;
24710594Sgabeblack@google.com
2486654Snate@binkert.orgclass $c_ident : public AbstractController
24910594Sgabeblack@google.com{
2506654Snate@binkert.org  public:
25110594Sgabeblack@google.com    typedef ${c_ident}Params Params;
25210594Sgabeblack@google.com    $c_ident(const Params *p);
2537586SAli.Saidi@arm.com    static int getNumControllers();
25410635Satgutier@umich.edu    void init();
25510635Satgutier@umich.edu    MessageBuffer* getMandatoryQueue() const;
2568661SAli.Saidi@ARM.com    const int & getVersion() const;
2579827Sakash.bagdia@arm.com    const std::string toString() const;
2589827Sakash.bagdia@arm.com    const std::string getName() const;
2599827Sakash.bagdia@arm.com    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
2609793Sakash.bagdia@arm.com
26110119Snilay@cs.wisc.edu    void print(std::ostream& out) const;
26210119Snilay@cs.wisc.edu    void wakeup();
2639790Sakash.bagdia@arm.com    void printStats(std::ostream& out) const;
2649827Sakash.bagdia@arm.com    void clearStats();
2659827Sakash.bagdia@arm.com    void regStats();
2669827Sakash.bagdia@arm.com    void collateStats();
2679793Sakash.bagdia@arm.com
2689827Sakash.bagdia@arm.com    void blockOnQueue(Address addr, MessageBuffer* port);
2699827Sakash.bagdia@arm.com    void unblock(Address addr);
2709827Sakash.bagdia@arm.com    void recordCacheTrace(int cntrl, CacheRecorder* tr);
2719793Sakash.bagdia@arm.com    Sequencer* getSequencer() const;
2729793Sakash.bagdia@arm.com
2739793Sakash.bagdia@arm.com    bool functionalReadBuffers(PacketPtr&);
2749384SAndreas.Sandberg@arm.com    uint32_t functionalWriteBuffers(PacketPtr&);
2758863Snilay@cs.wisc.edu
2767876Sgblack@eecs.umich.edu    void countTransition(${ident}_State state, ${ident}_Event event);
2774968Sacolyte@umich.edu    void possibleTransition(${ident}_State state, ${ident}_Event event);
2788926Sandreas.hansson@arm.com    uint64 getEventCount(${ident}_Event event);
2794837Ssaidi@eecs.umich.edu    bool isPossible(${ident}_State state, ${ident}_Event event);
2804837Ssaidi@eecs.umich.edu    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
2819408Sandreas.hansson@arm.com
2829653SAndreas.Sandberg@ARM.comprivate:
28311839SCurtis.Dunham@arm.com''')
2849653SAndreas.Sandberg@ARM.com
2859164Sandreas.hansson@arm.com        code.indent()
2869408Sandreas.hansson@arm.com        # added by SS
2878845Sandreas.hansson@arm.com        for param in self.config_parameters:
2888845Sandreas.hansson@arm.com            if param.pointer:
2894837Ssaidi@eecs.umich.edu                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
2909826Sandreas.hansson@arm.com            else:
2919826Sandreas.hansson@arm.com                code('${{param.type_ast.type}} m_${{param.ident}};')
2929835Sandreas.hansson@arm.com
2939826Sandreas.hansson@arm.com        code('''
2949826Sandreas.hansson@arm.comTransitionResult doTransition(${ident}_Event event,
2959826Sandreas.hansson@arm.com''')
2969826Sandreas.hansson@arm.com
2978659SAli.Saidi@ARM.com        if self.EntryType != None:
29810119Snilay@cs.wisc.edu            code('''
29910119Snilay@cs.wisc.edu                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
30010119Snilay@cs.wisc.edu''')
30110119Snilay@cs.wisc.edu        if self.TBEType != None:
30210119Snilay@cs.wisc.edu            code('''
30310119Snilay@cs.wisc.edu                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
30410119Snilay@cs.wisc.edu''')
30510119Snilay@cs.wisc.edu
30610119Snilay@cs.wisc.edu        code('''
30710119Snilay@cs.wisc.edu                              const Address& addr);
30810119Snilay@cs.wisc.edu
30910119Snilay@cs.wisc.eduTransitionResult doTransitionWorker(${ident}_Event event,
31010119Snilay@cs.wisc.edu                                    ${ident}_State state,
31110119Snilay@cs.wisc.edu                                    ${ident}_State& next_state,
31210119Snilay@cs.wisc.edu''')
31310119Snilay@cs.wisc.edu
31410119Snilay@cs.wisc.edu        if self.TBEType != None:
31510119Snilay@cs.wisc.edu            code('''
31610119Snilay@cs.wisc.edu                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
31710119Snilay@cs.wisc.edu''')
31810119Snilay@cs.wisc.edu        if self.EntryType != None:
31910119Snilay@cs.wisc.edu            code('''
32010119Snilay@cs.wisc.edu                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
32110119Snilay@cs.wisc.edu''')
32210119Snilay@cs.wisc.edu
32310119Snilay@cs.wisc.edu        code('''
32410119Snilay@cs.wisc.edu                                    const Address& addr);
32510119Snilay@cs.wisc.edu
32610119Snilay@cs.wisc.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
32710119Snilay@cs.wisc.eduint m_event_counters[${ident}_Event_NUM];
32810119Snilay@cs.wisc.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
32910119Snilay@cs.wisc.edu
33010119Snilay@cs.wisc.edustatic std::vector<Stats::Vector *> eventVec;
33110697SCurtis.Dunham@arm.comstatic std::vector<std::vector<Stats::Vector *> > transVec;
33210747SChris.Emmons@arm.comstatic int m_num_controllers;
33310697SCurtis.Dunham@arm.com
33410747SChris.Emmons@arm.com// Internal functions
33510119Snilay@cs.wisc.edu''')
33610697SCurtis.Dunham@arm.com
33710747SChris.Emmons@arm.com        for func in self.functions:
33810119Snilay@cs.wisc.edu            proto = func.prototype
33910119Snilay@cs.wisc.edu            if proto:
34010119Snilay@cs.wisc.edu                code('$proto')
34110119Snilay@cs.wisc.edu
34210119Snilay@cs.wisc.edu        if has_peer:
34310119Snilay@cs.wisc.edu            code('void getQueuesFromPeer(AbstractController *);')
3448801Sgblack@eecs.umich.edu        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''')
35111291Sgabor.dozsa@arm.com
35211291Sgabor.dozsa@arm.com        if self.TBEType != None:
35311291Sgabor.dozsa@arm.com            code('''
35411291Sgabor.dozsa@arm.com
35511291Sgabor.dozsa@arm.com// Set and Reset for tbe variable
35611291Sgabor.dozsa@arm.comvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3573005Sstever@eecs.umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3588801Sgblack@eecs.umich.edu''')
3593005Sstever@eecs.umich.edu
3603005Sstever@eecs.umich.edu        code('''
3613005Sstever@eecs.umich.edu
3622566SN/A// Actions
3637861Sgblack@eecs.umich.edu''')
3647861Sgblack@eecs.umich.edu        if self.TBEType != None and self.EntryType != None:
3657861Sgblack@eecs.umich.edu            for action in self.actions.itervalues():
3668635Schris.emmons@arm.com                code('/** \\brief ${{action.desc}} */')
3678635Schris.emmons@arm.com                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
3688635Schris.emmons@arm.com        elif self.TBEType != None:
3699061Snilay@cs.wisc.edu            for action in self.actions.itervalues():
3703481Shsul@eecs.umich.edu                code('/** \\brief ${{action.desc}} */')
371                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
372        elif self.EntryType != None:
373            for action in self.actions.itervalues():
374                code('/** \\brief ${{action.desc}} */')
375                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
376        else:
377            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", "")
388            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
389
390        code.dedent()
391        code('};')
392        code('#endif // __${ident}_CONTROLLER_H__')
393        code.write(path, '%s.hh' % c_ident)
394
395    def printControllerCC(self, path, includes):
396        '''Output the actions for performing the actions'''
397
398        code = self.symtab.codeFormatter()
399        ident = self.ident
400        c_ident = "%s_Controller" % self.ident
401        has_peer = False
402
403        code('''
404/** \\file $c_ident.cc
405 *
406 * Auto generated C++ code started by $__file__:$__line__
407 * Created by slicc definition of Module "${{self.short}}"
408 */
409
410#include <sys/types.h>
411#include <unistd.h>
412
413#include <cassert>
414#include <sstream>
415#include <string>
416
417#include "base/compiler.hh"
418#include "base/cprintf.hh"
419#include "debug/RubyGenerated.hh"
420#include "debug/RubySlicc.hh"
421#include "mem/protocol/${ident}_Controller.hh"
422#include "mem/protocol/${ident}_Event.hh"
423#include "mem/protocol/${ident}_State.hh"
424#include "mem/protocol/Types.hh"
425#include "mem/ruby/common/Global.hh"
426#include "mem/ruby/system/System.hh"
427''')
428        for include_path in includes:
429            code('#include "${{include_path}}"')
430
431        code('''
432
433using namespace std;
434''')
435
436        # include object classes
437        seen_types = set()
438        for var in self.objects:
439            if var.type.ident not in seen_types and not var.type.isPrimitive:
440                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
441            seen_types.add(var.type.ident)
442
443        code('''
444$c_ident *
445${c_ident}Params::create()
446{
447    return new $c_ident(this);
448}
449
450int $c_ident::m_num_controllers = 0;
451std::vector<Stats::Vector *>  $c_ident::eventVec;
452std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
453
454// for adding information to the protocol debug trace
455stringstream ${ident}_transitionComment;
456
457#ifndef NDEBUG
458#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
459#else
460#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
461#endif
462
463/** \\brief constructor */
464$c_ident::$c_ident(const Params *p)
465    : AbstractController(p)
466{
467    m_name = "${ident}";
468''')
469        #
470        # max_port_rank is used to size vectors and thus should be one plus the
471        # largest port rank
472        #
473        max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
474        code('    m_max_in_port_rank = $max_port_rank;')
475        code.indent()
476
477        #
478        # After initializing the universal machine parameters, initialize the
479        # this machines config parameters.  Also detemine if these configuration
480        # params include a sequencer.  This information will be used later for
481        # contecting the sequencer back to the L1 cache controller.
482        #
483        contains_dma_sequencer = False
484        sequencers = []
485        for param in self.config_parameters:
486            if param.name == "dma_sequencer":
487                contains_dma_sequencer = True
488            elif re.compile("sequencer").search(param.name):
489                sequencers.append(param.name)
490            if param.pointer:
491                code('m_${{param.name}}_ptr = p->${{param.name}};')
492            else:
493                code('m_${{param.name}} = p->${{param.name}};')
494
495        #
496        # For the l1 cache controller, add the special atomic support which
497        # includes passing the sequencer a pointer to the controller.
498        #
499        for seq in sequencers:
500            code('''
501m_${{seq}}_ptr->setController(this);
502    ''')
503
504        #
505        # For the DMA controller, pass the sequencer a pointer to the
506        # controller.
507        #
508        if self.ident == "DMA":
509            if not contains_dma_sequencer:
510                self.error("The DMA controller must include the sequencer " \
511                           "configuration parameter")
512
513            code('''
514m_dma_sequencer_ptr->setController(this);
515''')
516
517        code('m_num_controllers++;')
518        for var in self.objects:
519            if var.ident.find("mandatoryQueue") >= 0:
520                code('''
521m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
522m_${{var.c_ident}}_ptr->setReceiver(this);
523''')
524            else:
525                if "network" in var and "physical_network" in var and \
526                   var["network"] == "To":
527                    has_peer = True
528                    code('''
529m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
530peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
531m_${{var.c_ident}}_ptr->setSender(this);
532''')
533
534        code('''
535if (p->peer != NULL)
536    connectWithPeer(p->peer);
537
538for (int state = 0; state < ${ident}_State_NUM; state++) {
539    for (int event = 0; event < ${ident}_Event_NUM; event++) {
540        m_possible[state][event] = false;
541        m_counters[state][event] = 0;
542    }
543}
544for (int event = 0; event < ${ident}_Event_NUM; event++) {
545    m_event_counters[event] = 0;
546}
547''')
548        code.dedent()
549        code('''
550}
551
552void
553$c_ident::init()
554{
555    MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
556    int base = MachineType_base_number(machine_type);
557
558    m_machineID.type = MachineType_${ident};
559    m_machineID.num = m_version;
560
561    // initialize objects
562
563''')
564
565        code.indent()
566        for var in self.objects:
567            vtype = var.type
568            vid = "m_%s_ptr" % var.c_ident
569            if "network" not in var:
570                # Not a network port object
571                if "primitive" in vtype:
572                    code('$vid = new ${{vtype.c_ident}};')
573                    if "default" in var:
574                        code('(*$vid) = ${{var["default"]}};')
575                else:
576                    # Normal Object
577                    if var.ident.find("mandatoryQueue") < 0:
578                        th = var.get("template", "")
579                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
580                        args = ""
581                        if "non_obj" not in vtype and not vtype.isEnumeration:
582                            args = var.get("constructor", "")
583                        code('$expr($args);')
584
585                    code('assert($vid != NULL);')
586
587                    if "default" in var:
588                        code('*$vid = ${{var["default"]}}; // Object default')
589                    elif "default" in vtype:
590                        comment = "Type %s default" % vtype.ident
591                        code('*$vid = ${{vtype["default"]}}; // $comment')
592
593                    # Set ordering
594                    if "ordered" in var:
595                        # A buffer
596                        code('$vid->setOrdering(${{var["ordered"]}});')
597
598                    # Set randomization
599                    if "random" in var:
600                        # A buffer
601                        code('$vid->setRandomization(${{var["random"]}});')
602
603                    # Set Priority
604                    if vtype.isBuffer and "rank" in var:
605                        code('$vid->setPriority(${{var["rank"]}});')
606
607                    # Set sender and receiver for trigger queue
608                    if var.ident.find("triggerQueue") >= 0:
609                        code('$vid->setSender(this);')
610                        code('$vid->setReceiver(this);')
611                    elif vtype.c_ident == "TimerTable":
612                        code('$vid->setClockObj(this);')
613                    elif var.ident.find("optionalQueue") >= 0:
614                        code('$vid->setSender(this);')
615                        code('$vid->setReceiver(this);')
616
617            else:
618                # Network port object
619                network = var["network"]
620                ordered =  var["ordered"]
621
622                if "virtual_network" in var:
623                    vnet = var["virtual_network"]
624                    vnet_type = var["vnet_type"]
625
626                    assert var.machine is not None
627                    code('''
628$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
629assert($vid != NULL);
630''')
631
632                    # Set the end
633                    if network == "To":
634                        code('$vid->setSender(this);')
635                    else:
636                        code('$vid->setReceiver(this);')
637
638                # Set ordering
639                if "ordered" in var:
640                    # A buffer
641                    code('$vid->setOrdering(${{var["ordered"]}});')
642
643                # Set randomization
644                if "random" in var:
645                    # A buffer
646                    code('$vid->setRandomization(${{var["random"]}});')
647
648                # Set Priority
649                if "rank" in var:
650                    code('$vid->setPriority(${{var["rank"]}})')
651
652                # Set buffer size
653                if vtype.isBuffer:
654                    code('''
655if (m_buffer_size > 0) {
656    $vid->resize(m_buffer_size);
657}
658''')
659
660                # set description (may be overriden later by port def)
661                code('''
662$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
663
664''')
665
666            if vtype.isBuffer:
667                if "recycle_latency" in var:
668                    code('$vid->setRecycleLatency( ' \
669                         'Cycles(${{var["recycle_latency"]}}));')
670                else:
671                    code('$vid->setRecycleLatency(m_recycle_latency);')
672
673        # Set the prefetchers
674        code()
675        for prefetcher in self.prefetchers:
676            code('${{prefetcher.code}}.setController(this);')
677
678        code()
679        for port in self.in_ports:
680            # Set the queue consumers
681            code('${{port.code}}.setConsumer(this);')
682            # Set the queue descriptions
683            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
684
685        # Initialize the transition profiling
686        code()
687        for trans in self.transitions:
688            # Figure out if we stall
689            stall = False
690            for action in trans.actions:
691                if action.ident == "z_stall":
692                    stall = True
693
694            # Only possible if it is not a 'z' case
695            if not stall:
696                state = "%s_State_%s" % (self.ident, trans.state.ident)
697                event = "%s_Event_%s" % (self.ident, trans.event.ident)
698                code('possibleTransition($state, $event);')
699
700        code.dedent()
701        code('''
702    AbstractController::init();
703    clearStats();
704}
705''')
706
707        has_mandatory_q = False
708        for port in self.in_ports:
709            if port.code.find("mandatoryQueue_ptr") >= 0:
710                has_mandatory_q = True
711
712        if has_mandatory_q:
713            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
714        else:
715            mq_ident = "NULL"
716
717        seq_ident = "NULL"
718        for param in self.config_parameters:
719            if param.name == "sequencer":
720                assert(param.pointer)
721                seq_ident = "m_%s_ptr" % param.name
722
723        code('''
724
725void
726$c_ident::regStats()
727{
728    if (m_version == 0) {
729        for (${ident}_Event event = ${ident}_Event_FIRST;
730             event < ${ident}_Event_NUM; ++event) {
731            Stats::Vector *t = new Stats::Vector();
732            t->init(m_num_controllers);
733            t->name(name() + "." + ${ident}_Event_to_string(event));
734            t->flags(Stats::pdf | Stats::total | Stats::oneline |
735                     Stats::nozero);
736
737            eventVec.push_back(t);
738        }
739
740        for (${ident}_State state = ${ident}_State_FIRST;
741             state < ${ident}_State_NUM; ++state) {
742
743            transVec.push_back(std::vector<Stats::Vector *>());
744
745            for (${ident}_Event event = ${ident}_Event_FIRST;
746                 event < ${ident}_Event_NUM; ++event) {
747
748                Stats::Vector *t = new Stats::Vector();
749                t->init(m_num_controllers);
750                t->name(name() + "." + ${ident}_State_to_string(state) +
751                        "." + ${ident}_Event_to_string(event));
752
753                t->flags(Stats::pdf | Stats::total | Stats::oneline |
754                         Stats::nozero);
755                transVec[state].push_back(t);
756            }
757        }
758    }
759}
760
761void
762$c_ident::collateStats()
763{
764    for (${ident}_Event event = ${ident}_Event_FIRST;
765         event < ${ident}_Event_NUM; ++event) {
766        for (unsigned int i = 0; i < m_num_controllers; ++i) {
767            std::map<uint32_t, AbstractController *>::iterator it =
768                                g_abs_controls[MachineType_${ident}].find(i);
769            assert(it != g_abs_controls[MachineType_${ident}].end());
770            (*eventVec[event])[i] =
771                (($c_ident *)(*it).second)->getEventCount(event);
772        }
773    }
774
775    for (${ident}_State state = ${ident}_State_FIRST;
776         state < ${ident}_State_NUM; ++state) {
777
778        for (${ident}_Event event = ${ident}_Event_FIRST;
779             event < ${ident}_Event_NUM; ++event) {
780
781            for (unsigned int i = 0; i < m_num_controllers; ++i) {
782                std::map<uint32_t, AbstractController *>::iterator it =
783                                g_abs_controls[MachineType_${ident}].find(i);
784                assert(it != g_abs_controls[MachineType_${ident}].end());
785                (*transVec[state][event])[i] =
786                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
787            }
788        }
789    }
790}
791
792void
793$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
794{
795    assert(m_possible[state][event]);
796    m_counters[state][event]++;
797    m_event_counters[event]++;
798}
799void
800$c_ident::possibleTransition(${ident}_State state,
801                             ${ident}_Event event)
802{
803    m_possible[state][event] = true;
804}
805
806uint64
807$c_ident::getEventCount(${ident}_Event event)
808{
809    return m_event_counters[event];
810}
811
812bool
813$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
814{
815    return m_possible[state][event];
816}
817
818uint64
819$c_ident::getTransitionCount(${ident}_State state,
820                             ${ident}_Event event)
821{
822    return m_counters[state][event];
823}
824
825int
826$c_ident::getNumControllers()
827{
828    return m_num_controllers;
829}
830
831MessageBuffer*
832$c_ident::getMandatoryQueue() const
833{
834    return $mq_ident;
835}
836
837Sequencer*
838$c_ident::getSequencer() const
839{
840    return $seq_ident;
841}
842
843const int &
844$c_ident::getVersion() const
845{
846    return m_version;
847}
848
849const string
850$c_ident::toString() const
851{
852    return "$c_ident";
853}
854
855const string
856$c_ident::getName() const
857{
858    return m_name;
859}
860
861void
862$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
863{
864    m_is_blocking = true;
865    m_block_map[addr] = port;
866}
867
868void
869$c_ident::unblock(Address addr)
870{
871    m_block_map.erase(addr);
872    if (m_block_map.size() == 0) {
873       m_is_blocking = false;
874    }
875}
876
877void
878$c_ident::print(ostream& out) const
879{
880    out << "[$c_ident " << m_version << "]";
881}
882
883void
884$c_ident::printStats(ostream& out) const
885{
886''')
887        #
888        # Cache and Memory Controllers have specific profilers associated with
889        # them.  Print out these stats before dumping state transition stats.
890        #
891        for param in self.config_parameters:
892            if param.type_ast.type.ident == "DirectoryMemory":
893                assert(param.pointer)
894                code('    m_${{param.ident}}_ptr->printStats(out);')
895
896        code('''
897}
898
899void $c_ident::clearStats()
900{
901    for (int state = 0; state < ${ident}_State_NUM; state++) {
902        for (int event = 0; event < ${ident}_Event_NUM; event++) {
903            m_counters[state][event] = 0;
904        }
905    }
906
907    for (int event = 0; event < ${ident}_Event_NUM; event++) {
908        m_event_counters[event] = 0;
909    }
910
911    AbstractController::clearStats();
912}
913''')
914
915        if self.EntryType != None:
916            code('''
917
918// Set and Reset for cache_entry variable
919void
920$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
921{
922  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
923}
924
925void
926$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
927{
928  m_cache_entry_ptr = 0;
929}
930''')
931
932        if self.TBEType != None:
933            code('''
934
935// Set and Reset for tbe variable
936void
937$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
938{
939  m_tbe_ptr = m_new_tbe;
940}
941
942void
943$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
944{
945  m_tbe_ptr = NULL;
946}
947''')
948
949        code('''
950
951void
952$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
953{
954''')
955        #
956        # Record cache contents for all associated caches.
957        #
958        code.indent()
959        for param in self.config_parameters:
960            if param.type_ast.type.ident == "CacheMemory":
961                assert(param.pointer)
962                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
963
964        code.dedent()
965        code('''
966}
967
968// Actions
969''')
970        if self.TBEType != None and self.EntryType != None:
971            for action in self.actions.itervalues():
972                if "c_code" not in action:
973                 continue
974
975                code('''
976/** \\brief ${{action.desc}} */
977void
978$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
979{
980    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
981    ${{action["c_code"]}}
982}
983
984''')
985        elif self.TBEType != None:
986            for action in self.actions.itervalues():
987                if "c_code" not in action:
988                 continue
989
990                code('''
991/** \\brief ${{action.desc}} */
992void
993$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
994{
995    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
996    ${{action["c_code"]}}
997}
998
999''')
1000        elif self.EntryType != None:
1001            for action in self.actions.itervalues():
1002                if "c_code" not in action:
1003                 continue
1004
1005                code('''
1006/** \\brief ${{action.desc}} */
1007void
1008$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
1009{
1010    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
1011    ${{action["c_code"]}}
1012}
1013
1014''')
1015        else:
1016            for action in self.actions.itervalues():
1017                if "c_code" not in action:
1018                 continue
1019
1020                code('''
1021/** \\brief ${{action.desc}} */
1022void
1023$c_ident::${{action.ident}}(const Address& addr)
1024{
1025    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
1026    ${{action["c_code"]}}
1027}
1028
1029''')
1030        for func in self.functions:
1031            code(func.generateCode())
1032
1033        # Function for functional reads from messages buffered in the controller
1034        code('''
1035bool
1036$c_ident::functionalReadBuffers(PacketPtr& pkt)
1037{
1038''')
1039        for var in self.objects:
1040            vtype = var.type
1041            if vtype.isBuffer:
1042                vid = "m_%s_ptr" % var.c_ident
1043                code('if ($vid->functionalRead(pkt)) { return true; }')
1044        code('''
1045                return false;
1046}
1047''')
1048
1049        # Function for functional writes to messages buffered in the controller
1050        code('''
1051uint32_t
1052$c_ident::functionalWriteBuffers(PacketPtr& pkt)
1053{
1054    uint32_t num_functional_writes = 0;
1055''')
1056        for var in self.objects:
1057            vtype = var.type
1058            if vtype.isBuffer:
1059                vid = "m_%s_ptr" % var.c_ident
1060                code('num_functional_writes += $vid->functionalWrite(pkt);')
1061        code('''
1062    return num_functional_writes;
1063}
1064''')
1065
1066        # Check if this controller has a peer, if yes then write the
1067        # function for connecting to the peer.
1068        if has_peer:
1069            code('''
1070
1071void
1072$c_ident::getQueuesFromPeer(AbstractController *peer)
1073{
1074''')
1075            for var in self.objects:
1076                if "network" in var and "physical_network" in var and \
1077                   var["network"] == "From":
1078                    code('''
1079m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1080assert(m_${{var.c_ident}}_ptr != NULL);
1081m_${{var.c_ident}}_ptr->setReceiver(this);
1082
1083''')
1084            code('}')
1085
1086        code.write(path, "%s.cc" % c_ident)
1087
1088    def printCWakeup(self, path, includes):
1089        '''Output the wakeup loop for the events'''
1090
1091        code = self.symtab.codeFormatter()
1092        ident = self.ident
1093
1094        outputRequest_types = True
1095        if len(self.request_types) == 0:
1096            outputRequest_types = False
1097
1098        code('''
1099// Auto generated C++ code started by $__file__:$__line__
1100// ${ident}: ${{self.short}}
1101
1102#include <sys/types.h>
1103#include <unistd.h>
1104
1105#include <cassert>
1106
1107#include "base/misc.hh"
1108#include "debug/RubySlicc.hh"
1109#include "mem/protocol/${ident}_Controller.hh"
1110#include "mem/protocol/${ident}_Event.hh"
1111#include "mem/protocol/${ident}_State.hh"
1112''')
1113
1114        if outputRequest_types:
1115            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1116
1117        code('''
1118#include "mem/protocol/Types.hh"
1119#include "mem/ruby/common/Global.hh"
1120#include "mem/ruby/system/System.hh"
1121''')
1122
1123
1124        for include_path in includes:
1125            code('#include "${{include_path}}"')
1126
1127        code('''
1128
1129using namespace std;
1130
1131void
1132${ident}_Controller::wakeup()
1133{
1134    int counter = 0;
1135    while (true) {
1136        // Some cases will put us into an infinite loop without this limit
1137        assert(counter <= m_transitions_per_cycle);
1138        if (counter == m_transitions_per_cycle) {
1139            // Count how often we are fully utilized
1140            m_fully_busy_cycles++;
1141
1142            // Wakeup in another cycle and try again
1143            scheduleEvent(Cycles(1));
1144            break;
1145        }
1146''')
1147
1148        code.indent()
1149        code.indent()
1150
1151        # InPorts
1152        #
1153        for port in self.in_ports:
1154            code.indent()
1155            code('// ${ident}InPort $port')
1156            if port.pairs.has_key("rank"):
1157                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1158            else:
1159                code('m_cur_in_port_rank = 0;')
1160            code('${{port["c_code_in_port"]}}')
1161            code.dedent()
1162
1163            code('')
1164
1165        code.dedent()
1166        code.dedent()
1167        code('''
1168        break;  // If we got this far, we have nothing left todo
1169    }
1170}
1171''')
1172
1173        code.write(path, "%s_Wakeup.cc" % self.ident)
1174
1175    def printCSwitch(self, path):
1176        '''Output switch statement for transition table'''
1177
1178        code = self.symtab.codeFormatter()
1179        ident = self.ident
1180
1181        code('''
1182// Auto generated C++ code started by $__file__:$__line__
1183// ${ident}: ${{self.short}}
1184
1185#include <cassert>
1186
1187#include "base/misc.hh"
1188#include "base/trace.hh"
1189#include "debug/ProtocolTrace.hh"
1190#include "debug/RubyGenerated.hh"
1191#include "mem/protocol/${ident}_Controller.hh"
1192#include "mem/protocol/${ident}_Event.hh"
1193#include "mem/protocol/${ident}_State.hh"
1194#include "mem/protocol/Types.hh"
1195#include "mem/ruby/common/Global.hh"
1196#include "mem/ruby/system/System.hh"
1197
1198#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1199
1200#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1201#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1202
1203TransitionResult
1204${ident}_Controller::doTransition(${ident}_Event event,
1205''')
1206        if self.EntryType != None:
1207            code('''
1208                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1209''')
1210        if self.TBEType != None:
1211            code('''
1212                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1213''')
1214        code('''
1215                                  const Address &addr)
1216{
1217''')
1218        if self.TBEType != None and self.EntryType != None:
1219            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1220        elif self.TBEType != None:
1221            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1222        elif self.EntryType != None:
1223            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1224        else:
1225            code('${ident}_State state = getState(addr);')
1226
1227        code('''
1228    ${ident}_State next_state = state;
1229
1230    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1231            *this, curCycle(), ${ident}_State_to_string(state),
1232            ${ident}_Event_to_string(event), addr);
1233
1234    TransitionResult result =
1235''')
1236        if self.TBEType != None and self.EntryType != None:
1237            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1238        elif self.TBEType != None:
1239            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1240        elif self.EntryType != None:
1241            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1242        else:
1243            code('doTransitionWorker(event, state, next_state, addr);')
1244
1245        code('''
1246    if (result == TransitionResult_Valid) {
1247        DPRINTF(RubyGenerated, "next_state: %s\\n",
1248                ${ident}_State_to_string(next_state));
1249        countTransition(state, event);
1250        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1251                 curTick(), m_version, "${ident}",
1252                 ${ident}_Event_to_string(event),
1253                 ${ident}_State_to_string(state),
1254                 ${ident}_State_to_string(next_state),
1255                 addr, GET_TRANSITION_COMMENT());
1256
1257        CLEAR_TRANSITION_COMMENT();
1258''')
1259        if self.TBEType != None and self.EntryType != None:
1260            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1261            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1262        elif self.TBEType != None:
1263            code('setState(m_tbe_ptr, addr, next_state);')
1264            code('setAccessPermission(addr, next_state);')
1265        elif self.EntryType != None:
1266            code('setState(m_cache_entry_ptr, addr, next_state);')
1267            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1268        else:
1269            code('setState(addr, next_state);')
1270            code('setAccessPermission(addr, next_state);')
1271
1272        code('''
1273    } else if (result == TransitionResult_ResourceStall) {
1274        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1275                 curTick(), m_version, "${ident}",
1276                 ${ident}_Event_to_string(event),
1277                 ${ident}_State_to_string(state),
1278                 ${ident}_State_to_string(next_state),
1279                 addr, "Resource Stall");
1280    } else if (result == TransitionResult_ProtocolStall) {
1281        DPRINTF(RubyGenerated, "stalling\\n");
1282        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1283                 curTick(), m_version, "${ident}",
1284                 ${ident}_Event_to_string(event),
1285                 ${ident}_State_to_string(state),
1286                 ${ident}_State_to_string(next_state),
1287                 addr, "Protocol Stall");
1288    }
1289
1290    return result;
1291}
1292
1293TransitionResult
1294${ident}_Controller::doTransitionWorker(${ident}_Event event,
1295                                        ${ident}_State state,
1296                                        ${ident}_State& next_state,
1297''')
1298
1299        if self.TBEType != None:
1300            code('''
1301                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1302''')
1303        if self.EntryType != None:
1304                  code('''
1305                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1306''')
1307        code('''
1308                                        const Address& addr)
1309{
1310    switch(HASH_FUN(state, event)) {
1311''')
1312
1313        # This map will allow suppress generating duplicate code
1314        cases = orderdict()
1315
1316        for trans in self.transitions:
1317            case_string = "%s_State_%s, %s_Event_%s" % \
1318                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1319
1320            case = self.symtab.codeFormatter()
1321            # Only set next_state if it changes
1322            if trans.state != trans.nextState:
1323                ns_ident = trans.nextState.ident
1324                case('next_state = ${ident}_State_${ns_ident};')
1325
1326            actions = trans.actions
1327            request_types = trans.request_types
1328
1329            # Check for resources
1330            case_sorter = []
1331            res = trans.resources
1332            for key,val in res.iteritems():
1333                if key.type.ident != "DNUCAStopTable":
1334                    val = '''
1335if (!%s.areNSlotsAvailable(%s))
1336    return TransitionResult_ResourceStall;
1337''' % (key.code, val)
1338                case_sorter.append(val)
1339
1340            # Check all of the request_types for resource constraints
1341            for request_type in request_types:
1342                val = '''
1343if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1344    return TransitionResult_ResourceStall;
1345}
1346''' % (self.ident, request_type.ident)
1347                case_sorter.append(val)
1348
1349            # Emit the code sequences in a sorted order.  This makes the
1350            # output deterministic (without this the output order can vary
1351            # since Map's keys() on a vector of pointers is not deterministic
1352            for c in sorted(case_sorter):
1353                case("$c")
1354
1355            # Record access types for this transition
1356            for request_type in request_types:
1357                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1358
1359            # Figure out if we stall
1360            stall = False
1361            for action in actions:
1362                if action.ident == "z_stall":
1363                    stall = True
1364                    break
1365
1366            if stall:
1367                case('return TransitionResult_ProtocolStall;')
1368            else:
1369                if self.TBEType != None and self.EntryType != None:
1370                    for action in actions:
1371                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1372                elif self.TBEType != None:
1373                    for action in actions:
1374                        case('${{action.ident}}(m_tbe_ptr, addr);')
1375                elif self.EntryType != None:
1376                    for action in actions:
1377                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1378                else:
1379                    for action in actions:
1380                        case('${{action.ident}}(addr);')
1381                case('return TransitionResult_Valid;')
1382
1383            case = str(case)
1384
1385            # Look to see if this transition code is unique.
1386            if case not in cases:
1387                cases[case] = []
1388
1389            cases[case].append(case_string)
1390
1391        # Walk through all of the unique code blocks and spit out the
1392        # corresponding case statement elements
1393        for case,transitions in cases.iteritems():
1394            # Iterative over all the multiple transitions that share
1395            # the same code
1396            for trans in transitions:
1397                code('  case HASH_FUN($trans):')
1398            code('    $case')
1399
1400        code('''
1401      default:
1402        fatal("Invalid transition\\n"
1403              "%s time: %d addr: %s event: %s state: %s\\n",
1404              name(), curCycle(), addr, event, state);
1405    }
1406    return TransitionResult_Valid;
1407}
1408''')
1409        code.write(path, "%s_Transitions.cc" % self.ident)
1410
1411
1412    # **************************
1413    # ******* HTML Files *******
1414    # **************************
1415    def frameRef(self, click_href, click_target, over_href, over_num, text):
1416        code = self.symtab.codeFormatter(fix_newlines=False)
1417        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1418    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1419        parent.frames[$over_num].location='$over_href'
1420    }\">
1421    ${{html.formatShorthand(text)}}
1422    </A>""")
1423        return str(code)
1424
1425    def writeHTMLFiles(self, path):
1426        # Create table with no row hilighted
1427        self.printHTMLTransitions(path, None)
1428
1429        # Generate transition tables
1430        for state in self.states.itervalues():
1431            self.printHTMLTransitions(path, state)
1432
1433        # Generate action descriptions
1434        for action in self.actions.itervalues():
1435            name = "%s_action_%s.html" % (self.ident, action.ident)
1436            code = html.createSymbol(action, "Action")
1437            code.write(path, name)
1438
1439        # Generate state descriptions
1440        for state in self.states.itervalues():
1441            name = "%s_State_%s.html" % (self.ident, state.ident)
1442            code = html.createSymbol(state, "State")
1443            code.write(path, name)
1444
1445        # Generate event descriptions
1446        for event in self.events.itervalues():
1447            name = "%s_Event_%s.html" % (self.ident, event.ident)
1448            code = html.createSymbol(event, "Event")
1449            code.write(path, name)
1450
1451    def printHTMLTransitions(self, path, active_state):
1452        code = self.symtab.codeFormatter()
1453
1454        code('''
1455<HTML>
1456<BODY link="blue" vlink="blue">
1457
1458<H1 align="center">${{html.formatShorthand(self.short)}}:
1459''')
1460        code.indent()
1461        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1462            mid = machine.ident
1463            if i != 0:
1464                extra = " - "
1465            else:
1466                extra = ""
1467            if machine == self:
1468                code('$extra$mid')
1469            else:
1470                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1471        code.dedent()
1472
1473        code("""
1474</H1>
1475
1476<TABLE border=1>
1477<TR>
1478  <TH> </TH>
1479""")
1480
1481        for event in self.events.itervalues():
1482            href = "%s_Event_%s.html" % (self.ident, event.ident)
1483            ref = self.frameRef(href, "Status", href, "1", event.short)
1484            code('<TH bgcolor=white>$ref</TH>')
1485
1486        code('</TR>')
1487        # -- Body of table
1488        for state in self.states.itervalues():
1489            # -- Each row
1490            if state == active_state:
1491                color = "yellow"
1492            else:
1493                color = "white"
1494
1495            click = "%s_table_%s.html" % (self.ident, state.ident)
1496            over = "%s_State_%s.html" % (self.ident, state.ident)
1497            text = html.formatShorthand(state.short)
1498            ref = self.frameRef(click, "Table", over, "1", state.short)
1499            code('''
1500<TR>
1501  <TH bgcolor=$color>$ref</TH>
1502''')
1503
1504            # -- One column for each event
1505            for event in self.events.itervalues():
1506                trans = self.table.get((state,event), None)
1507                if trans is None:
1508                    # This is the no transition case
1509                    if state == active_state:
1510                        color = "#C0C000"
1511                    else:
1512                        color = "lightgrey"
1513
1514                    code('<TD bgcolor=$color>&nbsp;</TD>')
1515                    continue
1516
1517                next = trans.nextState
1518                stall_action = False
1519
1520                # -- Get the actions
1521                for action in trans.actions:
1522                    if action.ident == "z_stall" or \
1523                       action.ident == "zz_recycleMandatoryQueue":
1524                        stall_action = True
1525
1526                # -- Print out "actions/next-state"
1527                if stall_action:
1528                    if state == active_state:
1529                        color = "#C0C000"
1530                    else:
1531                        color = "lightgrey"
1532
1533                elif active_state and next.ident == active_state.ident:
1534                    color = "aqua"
1535                elif state == active_state:
1536                    color = "yellow"
1537                else:
1538                    color = "white"
1539
1540                code('<TD bgcolor=$color>')
1541                for action in trans.actions:
1542                    href = "%s_action_%s.html" % (self.ident, action.ident)
1543                    ref = self.frameRef(href, "Status", href, "1",
1544                                        action.short)
1545                    code('  $ref')
1546                if next != state:
1547                    if trans.actions:
1548                        code('/')
1549                    click = "%s_table_%s.html" % (self.ident, next.ident)
1550                    over = "%s_State_%s.html" % (self.ident, next.ident)
1551                    ref = self.frameRef(click, "Table", over, "1", next.short)
1552                    code("$ref")
1553                code("</TD>")
1554
1555            # -- Each row
1556            if state == active_state:
1557                color = "yellow"
1558            else:
1559                color = "white"
1560
1561            click = "%s_table_%s.html" % (self.ident, state.ident)
1562            over = "%s_State_%s.html" % (self.ident, state.ident)
1563            ref = self.frameRef(click, "Table", over, "1", state.short)
1564            code('''
1565  <TH bgcolor=$color>$ref</TH>
1566</TR>
1567''')
1568        code('''
1569<!- Column footer->
1570<TR>
1571  <TH> </TH>
1572''')
1573
1574        for event in self.events.itervalues():
1575            href = "%s_Event_%s.html" % (self.ident, event.ident)
1576            ref = self.frameRef(href, "Status", href, "1", event.short)
1577            code('<TH bgcolor=white>$ref</TH>')
1578        code('''
1579</TR>
1580</TABLE>
1581</BODY></HTML>
1582''')
1583
1584
1585        if active_state:
1586            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1587        else:
1588            name = "%s_table.html" % self.ident
1589        code.write(path, name)
1590
1591__all__ = [ "StateMachine" ]
1592