StateMachine.py revision 10917
111482Sandreas.sandberg@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
211482Sandreas.sandberg@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company
311482Sandreas.sandberg@arm.com# All rights reserved.
411482Sandreas.sandberg@arm.com#
511482Sandreas.sandberg@arm.com# Redistribution and use in source and binary forms, with or without
611482Sandreas.sandberg@arm.com# modification, are permitted provided that the following conditions are
711482Sandreas.sandberg@arm.com# met: redistributions of source code must retain the above copyright
811482Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer;
911482Sandreas.sandberg@arm.com# redistributions in binary form must reproduce the above copyright
1011482Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer in the
1111482Sandreas.sandberg@arm.com# documentation and/or other materials provided with the distribution;
1211482Sandreas.sandberg@arm.com# neither the name of the copyright holders nor the names of its
1311482Sandreas.sandberg@arm.com# contributors may be used to endorse or promote products derived from
1411482Sandreas.sandberg@arm.com# this software without specific prior written permission.
1511482Sandreas.sandberg@arm.com#
1611482Sandreas.sandberg@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1711482Sandreas.sandberg@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811482Sandreas.sandberg@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911482Sandreas.sandberg@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011482Sandreas.sandberg@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111482Sandreas.sandberg@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211482Sandreas.sandberg@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311482Sandreas.sandberg@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411482Sandreas.sandberg@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511482Sandreas.sandberg@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611482Sandreas.sandberg@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711482Sandreas.sandberg@arm.com
2811482Sandreas.sandberg@arm.comfrom m5.util import orderdict
2911482Sandreas.sandberg@arm.com
3011482Sandreas.sandberg@arm.comfrom slicc.symbols.Symbol import Symbol
3111482Sandreas.sandberg@arm.comfrom slicc.symbols.Var import Var
3211482Sandreas.sandberg@arm.comimport slicc.generate.html as html
3311482Sandreas.sandberg@arm.comimport re
3411482Sandreas.sandberg@arm.com
3511482Sandreas.sandberg@arm.compython_class_map = {
3611482Sandreas.sandberg@arm.com                    "int": "Int",
3711482Sandreas.sandberg@arm.com                    "uint32_t" : "UInt32",
3811482Sandreas.sandberg@arm.com                    "std::string": "String",
3911482Sandreas.sandberg@arm.com                    "bool": "Bool",
4011482Sandreas.sandberg@arm.com                    "CacheMemory": "RubyCache",
4111482Sandreas.sandberg@arm.com                    "WireBuffer": "RubyWireBuffer",
4211482Sandreas.sandberg@arm.com                    "Sequencer": "RubySequencer",
4311482Sandreas.sandberg@arm.com                    "DirectoryMemory": "RubyDirectoryMemory",
4411482Sandreas.sandberg@arm.com                    "MemoryControl": "MemoryControl",
4511482Sandreas.sandberg@arm.com                    "DMASequencer": "DMASequencer",
4611482Sandreas.sandberg@arm.com                    "Prefetcher":"Prefetcher",
4711482Sandreas.sandberg@arm.com                    "Cycles":"Cycles",
4811482Sandreas.sandberg@arm.com                   }
4911482Sandreas.sandberg@arm.com
5011482Sandreas.sandberg@arm.comclass StateMachine(Symbol):
5111482Sandreas.sandberg@arm.com    def __init__(self, symtab, ident, location, pairs, config_parameters):
5211482Sandreas.sandberg@arm.com        super(StateMachine, self).__init__(symtab, ident, location, pairs)
5311482Sandreas.sandberg@arm.com        self.table = None
5411482Sandreas.sandberg@arm.com
5511482Sandreas.sandberg@arm.com        # Data members in the State Machine that have been declared before
5611482Sandreas.sandberg@arm.com        # the opening brace '{'  of the machine.  Note that these along with
5711482Sandreas.sandberg@arm.com        # the members in self.objects form the entire set of data members.
5811482Sandreas.sandberg@arm.com        self.config_parameters = config_parameters
5911482Sandreas.sandberg@arm.com
6011482Sandreas.sandberg@arm.com        self.prefetchers = []
6111482Sandreas.sandberg@arm.com
6211482Sandreas.sandberg@arm.com        for param in config_parameters:
6311482Sandreas.sandberg@arm.com            if param.pointer:
6411482Sandreas.sandberg@arm.com                var = Var(symtab, param.ident, location, param.type_ast.type,
6511482Sandreas.sandberg@arm.com                          "(*m_%s_ptr)" % param.ident, {}, self)
6611482Sandreas.sandberg@arm.com            else:
6711482Sandreas.sandberg@arm.com                var = Var(symtab, param.ident, location, param.type_ast.type,
6811482Sandreas.sandberg@arm.com                          "m_%s" % param.ident, {}, self)
6911482Sandreas.sandberg@arm.com
7011482Sandreas.sandberg@arm.com            self.symtab.registerSym(param.ident, var)
7111482Sandreas.sandberg@arm.com
7211482Sandreas.sandberg@arm.com            if str(param.type_ast.type) == "Prefetcher":
7311482Sandreas.sandberg@arm.com                self.prefetchers.append(var)
7411482Sandreas.sandberg@arm.com
7511482Sandreas.sandberg@arm.com        self.states = orderdict()
7611482Sandreas.sandberg@arm.com        self.events = orderdict()
7711482Sandreas.sandberg@arm.com        self.actions = orderdict()
7811482Sandreas.sandberg@arm.com        self.request_types = orderdict()
7911482Sandreas.sandberg@arm.com        self.transitions = []
8011482Sandreas.sandberg@arm.com        self.in_ports = []
8111482Sandreas.sandberg@arm.com        self.functions = []
8211482Sandreas.sandberg@arm.com
8311482Sandreas.sandberg@arm.com        # Data members in the State Machine that have been declared inside
8411482Sandreas.sandberg@arm.com        # the {} machine.  Note that these along with the config params
8511482Sandreas.sandberg@arm.com        # form the entire set of data members of the machine.
8611482Sandreas.sandberg@arm.com        self.objects = []
8711482Sandreas.sandberg@arm.com        self.TBEType   = None
8811482Sandreas.sandberg@arm.com        self.EntryType = None
8911482Sandreas.sandberg@arm.com
9011482Sandreas.sandberg@arm.com    def __repr__(self):
9111482Sandreas.sandberg@arm.com        return "[StateMachine: %s]" % self.ident
9211482Sandreas.sandberg@arm.com
9311482Sandreas.sandberg@arm.com    def addState(self, state):
9411482Sandreas.sandberg@arm.com        assert self.table is None
9511482Sandreas.sandberg@arm.com        self.states[state.ident] = state
9611482Sandreas.sandberg@arm.com
9711482Sandreas.sandberg@arm.com    def addEvent(self, event):
9811482Sandreas.sandberg@arm.com        assert self.table is None
9911482Sandreas.sandberg@arm.com        self.events[event.ident] = event
10011482Sandreas.sandberg@arm.com
10111482Sandreas.sandberg@arm.com    def addAction(self, action):
10211482Sandreas.sandberg@arm.com        assert self.table is None
10311482Sandreas.sandberg@arm.com
10411482Sandreas.sandberg@arm.com        # Check for duplicate action
10511482Sandreas.sandberg@arm.com        for other in self.actions.itervalues():
10611482Sandreas.sandberg@arm.com            if action.ident == other.ident:
10711482Sandreas.sandberg@arm.com                action.warning("Duplicate action definition: %s" % action.ident)
10811482Sandreas.sandberg@arm.com                action.error("Duplicate action definition: %s" % action.ident)
10911482Sandreas.sandberg@arm.com            if action.short == other.short:
11011482Sandreas.sandberg@arm.com                other.warning("Duplicate action shorthand: %s" % other.ident)
11111482Sandreas.sandberg@arm.com                other.warning("    shorthand = %s" % other.short)
11211482Sandreas.sandberg@arm.com                action.warning("Duplicate action shorthand: %s" % action.ident)
11311482Sandreas.sandberg@arm.com                action.error("    shorthand = %s" % action.short)
11411482Sandreas.sandberg@arm.com
11511482Sandreas.sandberg@arm.com        self.actions[action.ident] = action
11611482Sandreas.sandberg@arm.com
11711482Sandreas.sandberg@arm.com    def addRequestType(self, request_type):
11811482Sandreas.sandberg@arm.com        assert self.table is None
11911482Sandreas.sandberg@arm.com        self.request_types[request_type.ident] = request_type
12011482Sandreas.sandberg@arm.com
12111482Sandreas.sandberg@arm.com    def addTransition(self, trans):
12211482Sandreas.sandberg@arm.com        assert self.table is None
12311482Sandreas.sandberg@arm.com        self.transitions.append(trans)
12411482Sandreas.sandberg@arm.com
12511482Sandreas.sandberg@arm.com    def addInPort(self, var):
12611482Sandreas.sandberg@arm.com        self.in_ports.append(var)
12711482Sandreas.sandberg@arm.com
12811482Sandreas.sandberg@arm.com    def addFunc(self, func):
12911482Sandreas.sandberg@arm.com        # register func in the symbol table
13011482Sandreas.sandberg@arm.com        self.symtab.registerSym(str(func), func)
13111482Sandreas.sandberg@arm.com        self.functions.append(func)
13211482Sandreas.sandberg@arm.com
13311482Sandreas.sandberg@arm.com    def addObject(self, obj):
13411482Sandreas.sandberg@arm.com        self.symtab.registerSym(str(obj), obj)
13511482Sandreas.sandberg@arm.com        self.objects.append(obj)
13611482Sandreas.sandberg@arm.com
13711482Sandreas.sandberg@arm.com    def addType(self, type):
13811482Sandreas.sandberg@arm.com        type_ident = '%s' % type.c_ident
13911482Sandreas.sandberg@arm.com
14011482Sandreas.sandberg@arm.com        if type_ident == "%s_TBE" %self.ident:
14111482Sandreas.sandberg@arm.com            if self.TBEType != None:
14211482Sandreas.sandberg@arm.com                self.error("Multiple Transaction Buffer types in a " \
14311482Sandreas.sandberg@arm.com                           "single machine.");
14411482Sandreas.sandberg@arm.com            self.TBEType = type
14511482Sandreas.sandberg@arm.com
14611482Sandreas.sandberg@arm.com        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
14711482Sandreas.sandberg@arm.com            if self.EntryType != None:
14811482Sandreas.sandberg@arm.com                self.error("Multiple AbstractCacheEntry types in a " \
14911482Sandreas.sandberg@arm.com                           "single machine.");
15011482Sandreas.sandberg@arm.com            self.EntryType = type
15111482Sandreas.sandberg@arm.com
15211482Sandreas.sandberg@arm.com    # Needs to be called before accessing the table
15311482Sandreas.sandberg@arm.com    def buildTable(self):
15411482Sandreas.sandberg@arm.com        assert self.table is None
15511482Sandreas.sandberg@arm.com
15611482Sandreas.sandberg@arm.com        table = {}
15711482Sandreas.sandberg@arm.com
15811482Sandreas.sandberg@arm.com        for trans in self.transitions:
15911482Sandreas.sandberg@arm.com            # Track which actions we touch so we know if we use them
16011482Sandreas.sandberg@arm.com            # all -- really this should be done for all symbols as
16111482Sandreas.sandberg@arm.com            # part of the symbol table, then only trigger it for
16211482Sandreas.sandberg@arm.com            # Actions, States, Events, etc.
16311482Sandreas.sandberg@arm.com
16411482Sandreas.sandberg@arm.com            for action in trans.actions:
16511482Sandreas.sandberg@arm.com                action.used = True
16611482Sandreas.sandberg@arm.com
16711482Sandreas.sandberg@arm.com            index = (trans.state, trans.event)
16811482Sandreas.sandberg@arm.com            if index in table:
16911482Sandreas.sandberg@arm.com                table[index].warning("Duplicate transition: %s" % table[index])
17011482Sandreas.sandberg@arm.com                trans.error("Duplicate transition: %s" % trans)
17111482Sandreas.sandberg@arm.com            table[index] = trans
17211482Sandreas.sandberg@arm.com
17311482Sandreas.sandberg@arm.com        # Look at all actions to make sure we used them all
17411482Sandreas.sandberg@arm.com        for action in self.actions.itervalues():
17511482Sandreas.sandberg@arm.com            if not action.used:
17611482Sandreas.sandberg@arm.com                error_msg = "Unused action: %s" % action.ident
17711482Sandreas.sandberg@arm.com                if "desc" in action:
17811482Sandreas.sandberg@arm.com                    error_msg += ", "  + action.desc
17911482Sandreas.sandberg@arm.com                action.warning(error_msg)
18011482Sandreas.sandberg@arm.com        self.table = table
18111482Sandreas.sandberg@arm.com
18211482Sandreas.sandberg@arm.com    def writeCodeFiles(self, path, includes):
18311482Sandreas.sandberg@arm.com        self.printControllerPython(path)
18411482Sandreas.sandberg@arm.com        self.printControllerHH(path)
18511482Sandreas.sandberg@arm.com        self.printControllerCC(path, includes)
18611482Sandreas.sandberg@arm.com        self.printCSwitch(path)
18711482Sandreas.sandberg@arm.com        self.printCWakeup(path, includes)
18811482Sandreas.sandberg@arm.com
18911482Sandreas.sandberg@arm.com    def printControllerPython(self, path):
19011482Sandreas.sandberg@arm.com        code = self.symtab.codeFormatter()
19111482Sandreas.sandberg@arm.com        ident = self.ident
19211482Sandreas.sandberg@arm.com
19311482Sandreas.sandberg@arm.com        py_ident = "%s_Controller" % ident
19411482Sandreas.sandberg@arm.com        c_ident = "%s_Controller" % self.ident
19511482Sandreas.sandberg@arm.com
19611482Sandreas.sandberg@arm.com        code('''
19711482Sandreas.sandberg@arm.comfrom m5.params import *
19811482Sandreas.sandberg@arm.comfrom m5.SimObject import SimObject
19911482Sandreas.sandberg@arm.comfrom Controller import RubyController
20011482Sandreas.sandberg@arm.com
20111482Sandreas.sandberg@arm.comclass $py_ident(RubyController):
20211482Sandreas.sandberg@arm.com    type = '$py_ident'
20311482Sandreas.sandberg@arm.com    cxx_header = 'mem/protocol/${c_ident}.hh'
20411482Sandreas.sandberg@arm.com''')
20511482Sandreas.sandberg@arm.com        code.indent()
20611482Sandreas.sandberg@arm.com        for param in self.config_parameters:
20711482Sandreas.sandberg@arm.com            dflt_str = ''
20811482Sandreas.sandberg@arm.com
20911482Sandreas.sandberg@arm.com            if param.rvalue is not None:
21011482Sandreas.sandberg@arm.com                dflt_str = str(param.rvalue.inline()) + ', '
21111482Sandreas.sandberg@arm.com
21211482Sandreas.sandberg@arm.com            if param.type_ast.type.c_ident == "MessageBuffer":
21311482Sandreas.sandberg@arm.com                if param["network"] == "To":
21411482Sandreas.sandberg@arm.com                    code('${{param.ident}} = MasterPort(${dflt_str}"")')
21511482Sandreas.sandberg@arm.com                else:
21611542Sandreas.sandberg@arm.com                    code('${{param.ident}} = SlavePort(${dflt_str}"")')
21711542Sandreas.sandberg@arm.com
21811542Sandreas.sandberg@arm.com            elif python_class_map.has_key(param.type_ast.type.c_ident):
21911482Sandreas.sandberg@arm.com                python_type = python_class_map[param.type_ast.type.c_ident]
22011482Sandreas.sandberg@arm.com                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
22111482Sandreas.sandberg@arm.com
22211482Sandreas.sandberg@arm.com            else:
22311482Sandreas.sandberg@arm.com                self.error("Unknown c++ to python class conversion for c++ " \
22411503Sandreas.sandberg@arm.com                           "type: '%s'. Please update the python_class_map " \
22511503Sandreas.sandberg@arm.com                           "in StateMachine.py", param.type_ast.type.c_ident)
22611503Sandreas.sandberg@arm.com        code.dedent()
22711503Sandreas.sandberg@arm.com        code.write(path, '%s.py' % py_ident)
22811503Sandreas.sandberg@arm.com
22911482Sandreas.sandberg@arm.com
23011503Sandreas.sandberg@arm.com    def printControllerHH(self, path):
23111503Sandreas.sandberg@arm.com        '''Output the method declarations for the class declaration'''
23211503Sandreas.sandberg@arm.com        code = self.symtab.codeFormatter()
23311503Sandreas.sandberg@arm.com        ident = self.ident
23411503Sandreas.sandberg@arm.com        c_ident = "%s_Controller" % self.ident
23511503Sandreas.sandberg@arm.com
23611503Sandreas.sandberg@arm.com        code('''
23711482Sandreas.sandberg@arm.com/** \\file $c_ident.hh
23811482Sandreas.sandberg@arm.com *
23911482Sandreas.sandberg@arm.com * Auto generated C++ code started by $__file__:$__line__
24011482Sandreas.sandberg@arm.com * Created by slicc definition of Module "${{self.short}}"
24111482Sandreas.sandberg@arm.com */
24211482Sandreas.sandberg@arm.com
24311482Sandreas.sandberg@arm.com#ifndef __${ident}_CONTROLLER_HH__
24411482Sandreas.sandberg@arm.com#define __${ident}_CONTROLLER_HH__
24511482Sandreas.sandberg@arm.com
24611482Sandreas.sandberg@arm.com#include <iostream>
24711482Sandreas.sandberg@arm.com#include <sstream>
24811482Sandreas.sandberg@arm.com#include <string>
24911482Sandreas.sandberg@arm.com
25011482Sandreas.sandberg@arm.com#include "mem/protocol/TransitionResult.hh"
25111482Sandreas.sandberg@arm.com#include "mem/protocol/Types.hh"
25211482Sandreas.sandberg@arm.com#include "mem/ruby/common/Consumer.hh"
25311482Sandreas.sandberg@arm.com#include "mem/ruby/common/Global.hh"
25411482Sandreas.sandberg@arm.com#include "mem/ruby/slicc_interface/AbstractController.hh"
25511482Sandreas.sandberg@arm.com#include "params/$c_ident.hh"
25611482Sandreas.sandberg@arm.com''')
25711482Sandreas.sandberg@arm.com
25811482Sandreas.sandberg@arm.com        seen_types = set()
25911482Sandreas.sandberg@arm.com        for var in self.objects:
26011482Sandreas.sandberg@arm.com            if var.type.ident not in seen_types and not var.type.isPrimitive:
26111482Sandreas.sandberg@arm.com                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
26211482Sandreas.sandberg@arm.com                seen_types.add(var.type.ident)
26311482Sandreas.sandberg@arm.com
26411503Sandreas.sandberg@arm.com        # for adding information to the protocol debug trace
26511482Sandreas.sandberg@arm.com        code('''
26611482Sandreas.sandberg@arm.comextern std::stringstream ${ident}_transitionComment;
26711482Sandreas.sandberg@arm.com
26811482Sandreas.sandberg@arm.comclass $c_ident : public AbstractController
26911482Sandreas.sandberg@arm.com{
27011482Sandreas.sandberg@arm.com  public:
27111482Sandreas.sandberg@arm.com    typedef ${c_ident}Params Params;
27211482Sandreas.sandberg@arm.com    $c_ident(const Params *p);
27311482Sandreas.sandberg@arm.com    static int getNumControllers();
27411482Sandreas.sandberg@arm.com    void init();
27511482Sandreas.sandberg@arm.com
27611482Sandreas.sandberg@arm.com    MessageBuffer* getMandatoryQueue() const;
27711482Sandreas.sandberg@arm.com    void setNetQueue(const std::string& name, MessageBuffer *b);
27811482Sandreas.sandberg@arm.com
27911482Sandreas.sandberg@arm.com    void print(std::ostream& out) const;
28011482Sandreas.sandberg@arm.com    void wakeup();
28111482Sandreas.sandberg@arm.com    void resetStats();
28211482Sandreas.sandberg@arm.com    void regStats();
28311482Sandreas.sandberg@arm.com    void collateStats();
28411482Sandreas.sandberg@arm.com
28511482Sandreas.sandberg@arm.com    void recordCacheTrace(int cntrl, CacheRecorder* tr);
28611482Sandreas.sandberg@arm.com    Sequencer* getSequencer() const;
28711482Sandreas.sandberg@arm.com
28811482Sandreas.sandberg@arm.com    int functionalWriteBuffers(PacketPtr&);
28911482Sandreas.sandberg@arm.com
29011482Sandreas.sandberg@arm.com    void countTransition(${ident}_State state, ${ident}_Event event);
29111482Sandreas.sandberg@arm.com    void possibleTransition(${ident}_State state, ${ident}_Event event);
29211482Sandreas.sandberg@arm.com    uint64 getEventCount(${ident}_Event event);
29311482Sandreas.sandberg@arm.com    bool isPossible(${ident}_State state, ${ident}_Event event);
29411482Sandreas.sandberg@arm.com    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
29511482Sandreas.sandberg@arm.com
29611482Sandreas.sandberg@arm.comprivate:
29711482Sandreas.sandberg@arm.com''')
29811482Sandreas.sandberg@arm.com
29911482Sandreas.sandberg@arm.com        code.indent()
30011482Sandreas.sandberg@arm.com        # added by SS
30111482Sandreas.sandberg@arm.com        for param in self.config_parameters:
30211482Sandreas.sandberg@arm.com            if param.pointer:
30311482Sandreas.sandberg@arm.com                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
30411482Sandreas.sandberg@arm.com            else:
30511482Sandreas.sandberg@arm.com                code('${{param.type_ast.type}} m_${{param.ident}};')
30611482Sandreas.sandberg@arm.com
30711482Sandreas.sandberg@arm.com        code('''
30811482Sandreas.sandberg@arm.comTransitionResult doTransition(${ident}_Event event,
30911482Sandreas.sandberg@arm.com''')
31011482Sandreas.sandberg@arm.com
31111482Sandreas.sandberg@arm.com        if self.EntryType != None:
31211482Sandreas.sandberg@arm.com            code('''
31311482Sandreas.sandberg@arm.com                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
31411482Sandreas.sandberg@arm.com''')
31511482Sandreas.sandberg@arm.com        if self.TBEType != None:
31611482Sandreas.sandberg@arm.com            code('''
31711482Sandreas.sandberg@arm.com                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
31811482Sandreas.sandberg@arm.com''')
31911482Sandreas.sandberg@arm.com
32011482Sandreas.sandberg@arm.com        code('''
32111482Sandreas.sandberg@arm.com                              const Address addr);
32211482Sandreas.sandberg@arm.com
32311482Sandreas.sandberg@arm.comTransitionResult doTransitionWorker(${ident}_Event event,
32411482Sandreas.sandberg@arm.com                                    ${ident}_State state,
32511482Sandreas.sandberg@arm.com                                    ${ident}_State& next_state,
32611482Sandreas.sandberg@arm.com''')
32711482Sandreas.sandberg@arm.com
32811482Sandreas.sandberg@arm.com        if self.TBEType != None:
32911482Sandreas.sandberg@arm.com            code('''
33011482Sandreas.sandberg@arm.com                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
33111511Sandreas.sandberg@arm.com''')
33211511Sandreas.sandberg@arm.com        if self.EntryType != None:
33311511Sandreas.sandberg@arm.com            code('''
33411511Sandreas.sandberg@arm.com                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
33511511Sandreas.sandberg@arm.com''')
33611482Sandreas.sandberg@arm.com
33711482Sandreas.sandberg@arm.com        code('''
33811482Sandreas.sandberg@arm.com                                    const Address& addr);
33911482Sandreas.sandberg@arm.com
34011482Sandreas.sandberg@arm.comint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
34111482Sandreas.sandberg@arm.comint m_event_counters[${ident}_Event_NUM];
34211482Sandreas.sandberg@arm.combool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
34311482Sandreas.sandberg@arm.com
34411482Sandreas.sandberg@arm.comstatic std::vector<Stats::Vector *> eventVec;
34511482Sandreas.sandberg@arm.comstatic std::vector<std::vector<Stats::Vector *> > transVec;
34611482Sandreas.sandberg@arm.comstatic int m_num_controllers;
34711482Sandreas.sandberg@arm.com
34811482Sandreas.sandberg@arm.com// Internal functions
34911482Sandreas.sandberg@arm.com''')
35011482Sandreas.sandberg@arm.com
35111482Sandreas.sandberg@arm.com        for func in self.functions:
35211482Sandreas.sandberg@arm.com            proto = func.prototype
35311482Sandreas.sandberg@arm.com            if proto:
35411482Sandreas.sandberg@arm.com                code('$proto')
35511482Sandreas.sandberg@arm.com
35611482Sandreas.sandberg@arm.com        if self.EntryType != None:
35711482Sandreas.sandberg@arm.com            code('''
358
359// Set and Reset for cache_entry variable
360void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
361void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
362''')
363
364        if self.TBEType != None:
365            code('''
366
367// Set and Reset for tbe variable
368void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
369void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
370''')
371
372        # Prototype the actions that the controller can take
373        code('''
374
375// Actions
376''')
377        if self.TBEType != None and self.EntryType != None:
378            for action in self.actions.itervalues():
379                code('/** \\brief ${{action.desc}} */')
380                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
381                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
382                     'm_cache_entry_ptr, const Address& addr);')
383        elif self.TBEType != None:
384            for action in self.actions.itervalues():
385                code('/** \\brief ${{action.desc}} */')
386                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
387                     'm_tbe_ptr, const Address& addr);')
388        elif self.EntryType != None:
389            for action in self.actions.itervalues():
390                code('/** \\brief ${{action.desc}} */')
391                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
392                     'm_cache_entry_ptr, const Address& addr);')
393        else:
394            for action in self.actions.itervalues():
395                code('/** \\brief ${{action.desc}} */')
396                code('void ${{action.ident}}(const Address& addr);')
397
398        # the controller internal variables
399        code('''
400
401// Objects
402''')
403        for var in self.objects:
404            th = var.get("template", "")
405            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
406
407        code.dedent()
408        code('};')
409        code('#endif // __${ident}_CONTROLLER_H__')
410        code.write(path, '%s.hh' % c_ident)
411
412    def printControllerCC(self, path, includes):
413        '''Output the actions for performing the actions'''
414
415        code = self.symtab.codeFormatter()
416        ident = self.ident
417        c_ident = "%s_Controller" % self.ident
418
419        code('''
420/** \\file $c_ident.cc
421 *
422 * Auto generated C++ code started by $__file__:$__line__
423 * Created by slicc definition of Module "${{self.short}}"
424 */
425
426#include <sys/types.h>
427#include <unistd.h>
428
429#include <cassert>
430#include <sstream>
431#include <string>
432
433#include "base/compiler.hh"
434#include "base/cprintf.hh"
435#include "debug/RubyGenerated.hh"
436#include "debug/RubySlicc.hh"
437#include "mem/protocol/${ident}_Controller.hh"
438#include "mem/protocol/${ident}_Event.hh"
439#include "mem/protocol/${ident}_State.hh"
440#include "mem/protocol/Types.hh"
441#include "mem/ruby/common/Global.hh"
442#include "mem/ruby/system/System.hh"
443''')
444        for include_path in includes:
445            code('#include "${{include_path}}"')
446
447        code('''
448
449using namespace std;
450''')
451
452        # include object classes
453        seen_types = set()
454        for var in self.objects:
455            if var.type.ident not in seen_types and not var.type.isPrimitive:
456                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
457            seen_types.add(var.type.ident)
458
459        num_in_ports = len(self.in_ports)
460
461        code('''
462$c_ident *
463${c_ident}Params::create()
464{
465    return new $c_ident(this);
466}
467
468int $c_ident::m_num_controllers = 0;
469std::vector<Stats::Vector *>  $c_ident::eventVec;
470std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
471
472// for adding information to the protocol debug trace
473stringstream ${ident}_transitionComment;
474
475#ifndef NDEBUG
476#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
477#else
478#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
479#endif
480
481/** \\brief constructor */
482$c_ident::$c_ident(const Params *p)
483    : AbstractController(p)
484{
485    m_machineID.type = MachineType_${ident};
486    m_machineID.num = m_version;
487    m_num_controllers++;
488
489    m_in_ports = $num_in_ports;
490''')
491        code.indent()
492
493        #
494        # After initializing the universal machine parameters, initialize the
495        # this machines config parameters.  Also if these configuration params
496        # include a sequencer, connect the it to the controller.
497        #
498        for param in self.config_parameters:
499
500            # Do not initialize messgage buffers since they are initialized
501            # when the port based connections are made.
502            if param.type_ast.type.c_ident == "MessageBuffer":
503                continue
504
505            if param.pointer:
506                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
507            else:
508                code('m_${{param.ident}} = p->${{param.ident}};')
509
510            if re.compile("sequencer").search(param.ident):
511                code('m_${{param.ident}}_ptr->setController(this);')
512
513        for var in self.objects:
514            if var.ident.find("mandatoryQueue") >= 0:
515                code('''
516m_${{var.ident}}_ptr = new ${{var.type.c_ident}}();
517m_${{var.ident}}_ptr->setReceiver(this);
518''')
519
520        code('''
521
522for (int state = 0; state < ${ident}_State_NUM; state++) {
523    for (int event = 0; event < ${ident}_Event_NUM; event++) {
524        m_possible[state][event] = false;
525        m_counters[state][event] = 0;
526    }
527}
528for (int event = 0; event < ${ident}_Event_NUM; event++) {
529    m_event_counters[event] = 0;
530}
531''')
532        code.dedent()
533        code('''
534}
535
536void
537$c_ident::setNetQueue(const std::string& name, MessageBuffer *b)
538{
539    MachineType machine_type = string_to_MachineType("${{self.ident}}");
540    int base M5_VAR_USED = MachineType_base_number(machine_type);
541
542''')
543        code.indent()
544
545        # set for maintaining the vnet, direction pairs already seen for this
546        # machine.  This map helps in implementing the check for avoiding
547        # multiple message buffers being mapped to the same vnet.
548        vnet_dir_set = set()
549
550        for var in self.config_parameters:
551            if "network" in var:
552                vtype = var.type_ast.type
553                vid = "m_%s_ptr" % var.ident
554
555                code('''
556if ("${{var.ident}}" == name) {
557    $vid = b;
558    assert($vid != NULL);
559''')
560                code.indent()
561                # Network port object
562                network = var["network"]
563                ordered =  var["ordered"]
564
565                if "virtual_network" in var:
566                    vnet = var["virtual_network"]
567                    vnet_type = var["vnet_type"]
568
569                    assert (vnet, network) not in vnet_dir_set
570                    vnet_dir_set.add((vnet,network))
571
572                    code('''
573m_net_ptr->set${network}NetQueue(m_version + base, $ordered, $vnet,
574                                 "$vnet_type", b);
575''')
576                # Set the end
577                if network == "To":
578                    code('$vid->setSender(this);')
579                else:
580                    code('$vid->setReceiver(this);')
581
582                # Set ordering
583                code('$vid->setOrdering(${{var["ordered"]}});')
584
585                # Set randomization
586                if "random" in var:
587                    # A buffer
588                    code('$vid->setRandomization(${{var["random"]}});')
589
590                # Set Priority
591                if "rank" in var:
592                    code('$vid->setPriority(${{var["rank"]}})')
593
594                # Set buffer size
595                code('$vid->resize(m_buffer_size);')
596
597                if "recycle_latency" in var:
598                    code('$vid->setRecycleLatency( ' \
599                         'Cycles(${{var["recycle_latency"]}}));')
600                else:
601                    code('$vid->setRecycleLatency(m_recycle_latency);')
602
603                # set description (may be overriden later by port def)
604                code('''
605$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.ident}}]");
606''')
607                code.dedent()
608                code('}\n')
609
610        code.dedent()
611        code('''
612}
613
614void
615$c_ident::init()
616{
617    // initialize objects
618
619''')
620
621        code.indent()
622
623        for var in self.objects:
624            vtype = var.type
625            vid = "m_%s_ptr" % var.ident
626            if "network" not in var:
627                # Not a network port object
628                if "primitive" in vtype:
629                    code('$vid = new ${{vtype.c_ident}};')
630                    if "default" in var:
631                        code('(*$vid) = ${{var["default"]}};')
632                else:
633                    # Normal Object
634                    if var.ident.find("mandatoryQueue") < 0:
635                        th = var.get("template", "")
636                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
637                        args = ""
638                        if "non_obj" not in vtype and not vtype.isEnumeration:
639                            args = var.get("constructor", "")
640                        code('$expr($args);')
641
642                    code('assert($vid != NULL);')
643
644                    if "default" in var:
645                        code('*$vid = ${{var["default"]}}; // Object default')
646                    elif "default" in vtype:
647                        comment = "Type %s default" % vtype.ident
648                        code('*$vid = ${{vtype["default"]}}; // $comment')
649
650                    # Set ordering
651                    if "ordered" in var:
652                        # A buffer
653                        code('$vid->setOrdering(${{var["ordered"]}});')
654
655                    # Set randomization
656                    if "random" in var:
657                        # A buffer
658                        code('$vid->setRandomization(${{var["random"]}});')
659
660                    # Set Priority
661                    if vtype.isBuffer and "rank" in var:
662                        code('$vid->setPriority(${{var["rank"]}});')
663
664                    # Set sender and receiver for trigger queue
665                    if var.ident.find("triggerQueue") >= 0:
666                        code('$vid->setSender(this);')
667                        code('$vid->setReceiver(this);')
668                    elif vtype.c_ident == "TimerTable":
669                        code('$vid->setClockObj(this);')
670                    elif var.ident.find("optionalQueue") >= 0:
671                        code('$vid->setSender(this);')
672                        code('$vid->setReceiver(this);')
673
674            if vtype.isBuffer:
675                if "recycle_latency" in var:
676                    code('$vid->setRecycleLatency( ' \
677                         'Cycles(${{var["recycle_latency"]}}));')
678                else:
679                    code('$vid->setRecycleLatency(m_recycle_latency);')
680
681        # Set the prefetchers
682        code()
683        for prefetcher in self.prefetchers:
684            code('${{prefetcher.code}}.setController(this);')
685
686        code()
687        for port in self.in_ports:
688            # Set the queue consumers
689            code('${{port.code}}.setConsumer(this);')
690            # Set the queue descriptions
691            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
692
693        # Initialize the transition profiling
694        code()
695        for trans in self.transitions:
696            # Figure out if we stall
697            stall = False
698            for action in trans.actions:
699                if action.ident == "z_stall":
700                    stall = True
701
702            # Only possible if it is not a 'z' case
703            if not stall:
704                state = "%s_State_%s" % (self.ident, trans.state.ident)
705                event = "%s_Event_%s" % (self.ident, trans.event.ident)
706                code('possibleTransition($state, $event);')
707
708        code.dedent()
709        code('''
710    AbstractController::init();
711    resetStats();
712}
713''')
714
715        mq_ident = "NULL"
716        for port in self.in_ports:
717            if port.code.find("mandatoryQueue_ptr") >= 0:
718                mq_ident = "m_mandatoryQueue_ptr"
719
720        seq_ident = "NULL"
721        for param in self.config_parameters:
722            if param.ident == "sequencer":
723                assert(param.pointer)
724                seq_ident = "m_%s_ptr" % param.ident
725
726        code('''
727
728void
729$c_ident::regStats()
730{
731    AbstractController::regStats();
732
733    if (m_version == 0) {
734        for (${ident}_Event event = ${ident}_Event_FIRST;
735             event < ${ident}_Event_NUM; ++event) {
736            Stats::Vector *t = new Stats::Vector();
737            t->init(m_num_controllers);
738            t->name(g_system_ptr->name() + ".${c_ident}." +
739                ${ident}_Event_to_string(event));
740            t->flags(Stats::pdf | Stats::total | Stats::oneline |
741                     Stats::nozero);
742
743            eventVec.push_back(t);
744        }
745
746        for (${ident}_State state = ${ident}_State_FIRST;
747             state < ${ident}_State_NUM; ++state) {
748
749            transVec.push_back(std::vector<Stats::Vector *>());
750
751            for (${ident}_Event event = ${ident}_Event_FIRST;
752                 event < ${ident}_Event_NUM; ++event) {
753
754                Stats::Vector *t = new Stats::Vector();
755                t->init(m_num_controllers);
756                t->name(g_system_ptr->name() + ".${c_ident}." +
757                        ${ident}_State_to_string(state) +
758                        "." + ${ident}_Event_to_string(event));
759
760                t->flags(Stats::pdf | Stats::total | Stats::oneline |
761                         Stats::nozero);
762                transVec[state].push_back(t);
763            }
764        }
765    }
766}
767
768void
769$c_ident::collateStats()
770{
771    for (${ident}_Event event = ${ident}_Event_FIRST;
772         event < ${ident}_Event_NUM; ++event) {
773        for (unsigned int i = 0; i < m_num_controllers; ++i) {
774            std::map<uint32_t, AbstractController *>::iterator it =
775                                g_abs_controls[MachineType_${ident}].find(i);
776            assert(it != g_abs_controls[MachineType_${ident}].end());
777            (*eventVec[event])[i] =
778                (($c_ident *)(*it).second)->getEventCount(event);
779        }
780    }
781
782    for (${ident}_State state = ${ident}_State_FIRST;
783         state < ${ident}_State_NUM; ++state) {
784
785        for (${ident}_Event event = ${ident}_Event_FIRST;
786             event < ${ident}_Event_NUM; ++event) {
787
788            for (unsigned int i = 0; i < m_num_controllers; ++i) {
789                std::map<uint32_t, AbstractController *>::iterator it =
790                                g_abs_controls[MachineType_${ident}].find(i);
791                assert(it != g_abs_controls[MachineType_${ident}].end());
792                (*transVec[state][event])[i] =
793                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
794            }
795        }
796    }
797}
798
799void
800$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
801{
802    assert(m_possible[state][event]);
803    m_counters[state][event]++;
804    m_event_counters[event]++;
805}
806void
807$c_ident::possibleTransition(${ident}_State state,
808                             ${ident}_Event event)
809{
810    m_possible[state][event] = true;
811}
812
813uint64
814$c_ident::getEventCount(${ident}_Event event)
815{
816    return m_event_counters[event];
817}
818
819bool
820$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
821{
822    return m_possible[state][event];
823}
824
825uint64
826$c_ident::getTransitionCount(${ident}_State state,
827                             ${ident}_Event event)
828{
829    return m_counters[state][event];
830}
831
832int
833$c_ident::getNumControllers()
834{
835    return m_num_controllers;
836}
837
838MessageBuffer*
839$c_ident::getMandatoryQueue() const
840{
841    return $mq_ident;
842}
843
844Sequencer*
845$c_ident::getSequencer() const
846{
847    return $seq_ident;
848}
849
850void
851$c_ident::print(ostream& out) const
852{
853    out << "[$c_ident " << m_version << "]";
854}
855
856void $c_ident::resetStats()
857{
858    for (int state = 0; state < ${ident}_State_NUM; state++) {
859        for (int event = 0; event < ${ident}_Event_NUM; event++) {
860            m_counters[state][event] = 0;
861        }
862    }
863
864    for (int event = 0; event < ${ident}_Event_NUM; event++) {
865        m_event_counters[event] = 0;
866    }
867
868    AbstractController::resetStats();
869}
870''')
871
872        if self.EntryType != None:
873            code('''
874
875// Set and Reset for cache_entry variable
876void
877$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
878{
879  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
880}
881
882void
883$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
884{
885  m_cache_entry_ptr = 0;
886}
887''')
888
889        if self.TBEType != None:
890            code('''
891
892// Set and Reset for tbe variable
893void
894$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
895{
896  m_tbe_ptr = m_new_tbe;
897}
898
899void
900$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
901{
902  m_tbe_ptr = NULL;
903}
904''')
905
906        code('''
907
908void
909$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
910{
911''')
912        #
913        # Record cache contents for all associated caches.
914        #
915        code.indent()
916        for param in self.config_parameters:
917            if param.type_ast.type.ident == "CacheMemory":
918                assert(param.pointer)
919                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
920
921        code.dedent()
922        code('''
923}
924
925// Actions
926''')
927        if self.TBEType != None and self.EntryType != None:
928            for action in self.actions.itervalues():
929                if "c_code" not in action:
930                 continue
931
932                code('''
933/** \\brief ${{action.desc}} */
934void
935$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
936{
937    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
938    ${{action["c_code"]}}
939}
940
941''')
942        elif self.TBEType != None:
943            for action in self.actions.itervalues():
944                if "c_code" not in action:
945                 continue
946
947                code('''
948/** \\brief ${{action.desc}} */
949void
950$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
951{
952    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
953    ${{action["c_code"]}}
954}
955
956''')
957        elif self.EntryType != None:
958            for action in self.actions.itervalues():
959                if "c_code" not in action:
960                 continue
961
962                code('''
963/** \\brief ${{action.desc}} */
964void
965$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
966{
967    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
968    ${{action["c_code"]}}
969}
970
971''')
972        else:
973            for action in self.actions.itervalues():
974                if "c_code" not in action:
975                 continue
976
977                code('''
978/** \\brief ${{action.desc}} */
979void
980$c_ident::${{action.ident}}(const Address& addr)
981{
982    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
983    ${{action["c_code"]}}
984}
985
986''')
987        for func in self.functions:
988            code(func.generateCode())
989
990        # Function for functional writes to messages buffered in the controller
991        code('''
992int
993$c_ident::functionalWriteBuffers(PacketPtr& pkt)
994{
995    int num_functional_writes = 0;
996''')
997        for var in self.objects:
998            vtype = var.type
999            if vtype.isBuffer:
1000                vid = "m_%s_ptr" % var.ident
1001                code('num_functional_writes += $vid->functionalWrite(pkt);')
1002
1003        for var in self.config_parameters:
1004            vtype = var.type_ast.type
1005            if vtype.isBuffer:
1006                vid = "m_%s_ptr" % var.ident
1007                code('num_functional_writes += $vid->functionalWrite(pkt);')
1008
1009        code('''
1010    return num_functional_writes;
1011}
1012''')
1013
1014        code.write(path, "%s.cc" % c_ident)
1015
1016    def printCWakeup(self, path, includes):
1017        '''Output the wakeup loop for the events'''
1018
1019        code = self.symtab.codeFormatter()
1020        ident = self.ident
1021
1022        outputRequest_types = True
1023        if len(self.request_types) == 0:
1024            outputRequest_types = False
1025
1026        code('''
1027// Auto generated C++ code started by $__file__:$__line__
1028// ${ident}: ${{self.short}}
1029
1030#include <sys/types.h>
1031#include <unistd.h>
1032
1033#include <cassert>
1034
1035#include "base/misc.hh"
1036#include "debug/RubySlicc.hh"
1037#include "mem/protocol/${ident}_Controller.hh"
1038#include "mem/protocol/${ident}_Event.hh"
1039#include "mem/protocol/${ident}_State.hh"
1040''')
1041
1042        if outputRequest_types:
1043            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1044
1045        code('''
1046#include "mem/protocol/Types.hh"
1047#include "mem/ruby/common/Global.hh"
1048#include "mem/ruby/system/System.hh"
1049''')
1050
1051
1052        for include_path in includes:
1053            code('#include "${{include_path}}"')
1054
1055        code('''
1056
1057using namespace std;
1058
1059void
1060${ident}_Controller::wakeup()
1061{
1062    int counter = 0;
1063    while (true) {
1064        // Some cases will put us into an infinite loop without this limit
1065        assert(counter <= m_transitions_per_cycle);
1066        if (counter == m_transitions_per_cycle) {
1067            // Count how often we are fully utilized
1068            m_fully_busy_cycles++;
1069
1070            // Wakeup in another cycle and try again
1071            scheduleEvent(Cycles(1));
1072            break;
1073        }
1074''')
1075
1076        code.indent()
1077        code.indent()
1078
1079        # InPorts
1080        #
1081        for port in self.in_ports:
1082            code.indent()
1083            code('// ${ident}InPort $port')
1084            if port.pairs.has_key("rank"):
1085                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1086            else:
1087                code('m_cur_in_port = 0;')
1088            code('${{port["c_code_in_port"]}}')
1089            code.dedent()
1090
1091            code('')
1092
1093        code.dedent()
1094        code.dedent()
1095        code('''
1096        break;  // If we got this far, we have nothing left todo
1097    }
1098}
1099''')
1100
1101        code.write(path, "%s_Wakeup.cc" % self.ident)
1102
1103    def printCSwitch(self, path):
1104        '''Output switch statement for transition table'''
1105
1106        code = self.symtab.codeFormatter()
1107        ident = self.ident
1108
1109        code('''
1110// Auto generated C++ code started by $__file__:$__line__
1111// ${ident}: ${{self.short}}
1112
1113#include <cassert>
1114
1115#include "base/misc.hh"
1116#include "base/trace.hh"
1117#include "debug/ProtocolTrace.hh"
1118#include "debug/RubyGenerated.hh"
1119#include "mem/protocol/${ident}_Controller.hh"
1120#include "mem/protocol/${ident}_Event.hh"
1121#include "mem/protocol/${ident}_State.hh"
1122#include "mem/protocol/Types.hh"
1123#include "mem/ruby/common/Global.hh"
1124#include "mem/ruby/system/System.hh"
1125
1126#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1127
1128#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1129#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1130
1131TransitionResult
1132${ident}_Controller::doTransition(${ident}_Event event,
1133''')
1134        if self.EntryType != None:
1135            code('''
1136                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1137''')
1138        if self.TBEType != None:
1139            code('''
1140                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1141''')
1142        code('''
1143                                  const Address addr)
1144{
1145''')
1146        code.indent()
1147
1148        if self.TBEType != None and self.EntryType != None:
1149            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1150        elif self.TBEType != None:
1151            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1152        elif self.EntryType != None:
1153            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1154        else:
1155            code('${ident}_State state = getState(addr);')
1156
1157        code('''
1158${ident}_State next_state = state;
1159
1160DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1161        *this, curCycle(), ${ident}_State_to_string(state),
1162        ${ident}_Event_to_string(event), addr);
1163
1164TransitionResult result =
1165''')
1166        if self.TBEType != None and self.EntryType != None:
1167            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1168        elif self.TBEType != None:
1169            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1170        elif self.EntryType != None:
1171            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1172        else:
1173            code('doTransitionWorker(event, state, next_state, addr);')
1174
1175        code('''
1176
1177if (result == TransitionResult_Valid) {
1178    DPRINTF(RubyGenerated, "next_state: %s\\n",
1179            ${ident}_State_to_string(next_state));
1180    countTransition(state, event);
1181
1182    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1183             curTick(), m_version, "${ident}",
1184             ${ident}_Event_to_string(event),
1185             ${ident}_State_to_string(state),
1186             ${ident}_State_to_string(next_state),
1187             addr, GET_TRANSITION_COMMENT());
1188
1189    CLEAR_TRANSITION_COMMENT();
1190''')
1191        if self.TBEType != None and self.EntryType != None:
1192            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1193            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1194        elif self.TBEType != None:
1195            code('setState(m_tbe_ptr, addr, next_state);')
1196            code('setAccessPermission(addr, next_state);')
1197        elif self.EntryType != None:
1198            code('setState(m_cache_entry_ptr, addr, next_state);')
1199            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1200        else:
1201            code('setState(addr, next_state);')
1202            code('setAccessPermission(addr, next_state);')
1203
1204        code('''
1205} else if (result == TransitionResult_ResourceStall) {
1206    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1207             curTick(), m_version, "${ident}",
1208             ${ident}_Event_to_string(event),
1209             ${ident}_State_to_string(state),
1210             ${ident}_State_to_string(next_state),
1211             addr, "Resource Stall");
1212} else if (result == TransitionResult_ProtocolStall) {
1213    DPRINTF(RubyGenerated, "stalling\\n");
1214    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1215             curTick(), m_version, "${ident}",
1216             ${ident}_Event_to_string(event),
1217             ${ident}_State_to_string(state),
1218             ${ident}_State_to_string(next_state),
1219             addr, "Protocol Stall");
1220}
1221
1222return result;
1223''')
1224        code.dedent()
1225        code('''
1226}
1227
1228TransitionResult
1229${ident}_Controller::doTransitionWorker(${ident}_Event event,
1230                                        ${ident}_State state,
1231                                        ${ident}_State& next_state,
1232''')
1233
1234        if self.TBEType != None:
1235            code('''
1236                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1237''')
1238        if self.EntryType != None:
1239                  code('''
1240                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1241''')
1242        code('''
1243                                        const Address& addr)
1244{
1245    switch(HASH_FUN(state, event)) {
1246''')
1247
1248        # This map will allow suppress generating duplicate code
1249        cases = orderdict()
1250
1251        for trans in self.transitions:
1252            case_string = "%s_State_%s, %s_Event_%s" % \
1253                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1254
1255            case = self.symtab.codeFormatter()
1256            # Only set next_state if it changes
1257            if trans.state != trans.nextState:
1258                ns_ident = trans.nextState.ident
1259                case('next_state = ${ident}_State_${ns_ident};')
1260
1261            actions = trans.actions
1262            request_types = trans.request_types
1263
1264            # Check for resources
1265            case_sorter = []
1266            res = trans.resources
1267            for key,val in res.iteritems():
1268                val = '''
1269if (!%s.areNSlotsAvailable(%s))
1270    return TransitionResult_ResourceStall;
1271''' % (key.code, val)
1272                case_sorter.append(val)
1273
1274            # Check all of the request_types for resource constraints
1275            for request_type in request_types:
1276                val = '''
1277if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1278    return TransitionResult_ResourceStall;
1279}
1280''' % (self.ident, request_type.ident)
1281                case_sorter.append(val)
1282
1283            # Emit the code sequences in a sorted order.  This makes the
1284            # output deterministic (without this the output order can vary
1285            # since Map's keys() on a vector of pointers is not deterministic
1286            for c in sorted(case_sorter):
1287                case("$c")
1288
1289            # Record access types for this transition
1290            for request_type in request_types:
1291                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1292
1293            # Figure out if we stall
1294            stall = False
1295            for action in actions:
1296                if action.ident == "z_stall":
1297                    stall = True
1298                    break
1299
1300            if stall:
1301                case('return TransitionResult_ProtocolStall;')
1302            else:
1303                if self.TBEType != None and self.EntryType != None:
1304                    for action in actions:
1305                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1306                elif self.TBEType != None:
1307                    for action in actions:
1308                        case('${{action.ident}}(m_tbe_ptr, addr);')
1309                elif self.EntryType != None:
1310                    for action in actions:
1311                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1312                else:
1313                    for action in actions:
1314                        case('${{action.ident}}(addr);')
1315                case('return TransitionResult_Valid;')
1316
1317            case = str(case)
1318
1319            # Look to see if this transition code is unique.
1320            if case not in cases:
1321                cases[case] = []
1322
1323            cases[case].append(case_string)
1324
1325        # Walk through all of the unique code blocks and spit out the
1326        # corresponding case statement elements
1327        for case,transitions in cases.iteritems():
1328            # Iterative over all the multiple transitions that share
1329            # the same code
1330            for trans in transitions:
1331                code('  case HASH_FUN($trans):')
1332            code('    $case\n')
1333
1334        code('''
1335      default:
1336        fatal("Invalid transition\\n"
1337              "%s time: %d addr: %s event: %s state: %s\\n",
1338              name(), curCycle(), addr, event, state);
1339    }
1340
1341    return TransitionResult_Valid;
1342}
1343''')
1344        code.write(path, "%s_Transitions.cc" % self.ident)
1345
1346
1347    # **************************
1348    # ******* HTML Files *******
1349    # **************************
1350    def frameRef(self, click_href, click_target, over_href, over_num, text):
1351        code = self.symtab.codeFormatter(fix_newlines=False)
1352        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1353    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1354        parent.frames[$over_num].location='$over_href'
1355    }\">
1356    ${{html.formatShorthand(text)}}
1357    </A>""")
1358        return str(code)
1359
1360    def writeHTMLFiles(self, path):
1361        # Create table with no row hilighted
1362        self.printHTMLTransitions(path, None)
1363
1364        # Generate transition tables
1365        for state in self.states.itervalues():
1366            self.printHTMLTransitions(path, state)
1367
1368        # Generate action descriptions
1369        for action in self.actions.itervalues():
1370            name = "%s_action_%s.html" % (self.ident, action.ident)
1371            code = html.createSymbol(action, "Action")
1372            code.write(path, name)
1373
1374        # Generate state descriptions
1375        for state in self.states.itervalues():
1376            name = "%s_State_%s.html" % (self.ident, state.ident)
1377            code = html.createSymbol(state, "State")
1378            code.write(path, name)
1379
1380        # Generate event descriptions
1381        for event in self.events.itervalues():
1382            name = "%s_Event_%s.html" % (self.ident, event.ident)
1383            code = html.createSymbol(event, "Event")
1384            code.write(path, name)
1385
1386    def printHTMLTransitions(self, path, active_state):
1387        code = self.symtab.codeFormatter()
1388
1389        code('''
1390<HTML>
1391<BODY link="blue" vlink="blue">
1392
1393<H1 align="center">${{html.formatShorthand(self.short)}}:
1394''')
1395        code.indent()
1396        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1397            mid = machine.ident
1398            if i != 0:
1399                extra = " - "
1400            else:
1401                extra = ""
1402            if machine == self:
1403                code('$extra$mid')
1404            else:
1405                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1406        code.dedent()
1407
1408        code("""
1409</H1>
1410
1411<TABLE border=1>
1412<TR>
1413  <TH> </TH>
1414""")
1415
1416        for event in self.events.itervalues():
1417            href = "%s_Event_%s.html" % (self.ident, event.ident)
1418            ref = self.frameRef(href, "Status", href, "1", event.short)
1419            code('<TH bgcolor=white>$ref</TH>')
1420
1421        code('</TR>')
1422        # -- Body of table
1423        for state in self.states.itervalues():
1424            # -- Each row
1425            if state == active_state:
1426                color = "yellow"
1427            else:
1428                color = "white"
1429
1430            click = "%s_table_%s.html" % (self.ident, state.ident)
1431            over = "%s_State_%s.html" % (self.ident, state.ident)
1432            text = html.formatShorthand(state.short)
1433            ref = self.frameRef(click, "Table", over, "1", state.short)
1434            code('''
1435<TR>
1436  <TH bgcolor=$color>$ref</TH>
1437''')
1438
1439            # -- One column for each event
1440            for event in self.events.itervalues():
1441                trans = self.table.get((state,event), None)
1442                if trans is None:
1443                    # This is the no transition case
1444                    if state == active_state:
1445                        color = "#C0C000"
1446                    else:
1447                        color = "lightgrey"
1448
1449                    code('<TD bgcolor=$color>&nbsp;</TD>')
1450                    continue
1451
1452                next = trans.nextState
1453                stall_action = False
1454
1455                # -- Get the actions
1456                for action in trans.actions:
1457                    if action.ident == "z_stall" or \
1458                       action.ident == "zz_recycleMandatoryQueue":
1459                        stall_action = True
1460
1461                # -- Print out "actions/next-state"
1462                if stall_action:
1463                    if state == active_state:
1464                        color = "#C0C000"
1465                    else:
1466                        color = "lightgrey"
1467
1468                elif active_state and next.ident == active_state.ident:
1469                    color = "aqua"
1470                elif state == active_state:
1471                    color = "yellow"
1472                else:
1473                    color = "white"
1474
1475                code('<TD bgcolor=$color>')
1476                for action in trans.actions:
1477                    href = "%s_action_%s.html" % (self.ident, action.ident)
1478                    ref = self.frameRef(href, "Status", href, "1",
1479                                        action.short)
1480                    code('  $ref')
1481                if next != state:
1482                    if trans.actions:
1483                        code('/')
1484                    click = "%s_table_%s.html" % (self.ident, next.ident)
1485                    over = "%s_State_%s.html" % (self.ident, next.ident)
1486                    ref = self.frameRef(click, "Table", over, "1", next.short)
1487                    code("$ref")
1488                code("</TD>")
1489
1490            # -- Each row
1491            if state == active_state:
1492                color = "yellow"
1493            else:
1494                color = "white"
1495
1496            click = "%s_table_%s.html" % (self.ident, state.ident)
1497            over = "%s_State_%s.html" % (self.ident, state.ident)
1498            ref = self.frameRef(click, "Table", over, "1", state.short)
1499            code('''
1500  <TH bgcolor=$color>$ref</TH>
1501</TR>
1502''')
1503        code('''
1504<!- Column footer->
1505<TR>
1506  <TH> </TH>
1507''')
1508
1509        for event in self.events.itervalues():
1510            href = "%s_Event_%s.html" % (self.ident, event.ident)
1511            ref = self.frameRef(href, "Status", href, "1", event.short)
1512            code('<TH bgcolor=white>$ref</TH>')
1513        code('''
1514</TR>
1515</TABLE>
1516</BODY></HTML>
1517''')
1518
1519
1520        if active_state:
1521            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1522        else:
1523            name = "%s_table.html" % self.ident
1524        code.write(path, name)
1525
1526__all__ = [ "StateMachine" ]
1527