StateMachine.py revision 11309
14661Sksewell@umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
24661Sksewell@umich.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
34661Sksewell@umich.edu# Copyright (c) 2013 Advanced Micro Devices, Inc.
44661Sksewell@umich.edu# All rights reserved.
54661Sksewell@umich.edu#
64661Sksewell@umich.edu# Redistribution and use in source and binary forms, with or without
74661Sksewell@umich.edu# modification, are permitted provided that the following conditions are
84661Sksewell@umich.edu# met: redistributions of source code must retain the above copyright
94661Sksewell@umich.edu# notice, this list of conditions and the following disclaimer;
104661Sksewell@umich.edu# redistributions in binary form must reproduce the above copyright
114661Sksewell@umich.edu# notice, this list of conditions and the following disclaimer in the
124661Sksewell@umich.edu# documentation and/or other materials provided with the distribution;
134661Sksewell@umich.edu# neither the name of the copyright holders nor the names of its
144661Sksewell@umich.edu# contributors may be used to endorse or promote products derived from
154661Sksewell@umich.edu# this software without specific prior written permission.
164661Sksewell@umich.edu#
174661Sksewell@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
184661Sksewell@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
194661Sksewell@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
204661Sksewell@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
214661Sksewell@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
224661Sksewell@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
234661Sksewell@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244661Sksewell@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254661Sksewell@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264661Sksewell@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
274661Sksewell@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284661Sksewell@umich.edu
294661Sksewell@umich.edufrom m5.util import orderdict
304661Sksewell@umich.edu
314661Sksewell@umich.edufrom slicc.symbols.Symbol import Symbol
324661Sksewell@umich.edufrom slicc.symbols.Var import Var
334661Sksewell@umich.eduimport slicc.generate.html as html
344661Sksewell@umich.eduimport re
354661Sksewell@umich.edu
364661Sksewell@umich.edupython_class_map = {
374661Sksewell@umich.edu                    "int": "Int",
384661Sksewell@umich.edu                    "NodeID": "Int",
394661Sksewell@umich.edu                    "uint32_t" : "UInt32",
404661Sksewell@umich.edu                    "std::string": "String",
414661Sksewell@umich.edu                    "bool": "Bool",
424661Sksewell@umich.edu                    "CacheMemory": "RubyCache",
434661Sksewell@umich.edu                    "WireBuffer": "RubyWireBuffer",
444661Sksewell@umich.edu                    "Sequencer": "RubySequencer",
454661Sksewell@umich.edu                    "GPUCoalescer" : "RubyGPUCoalescer",
464661Sksewell@umich.edu                    "VIPERCoalescer" : "VIPERCoalescer",
474661Sksewell@umich.edu                    "DirectoryMemory": "RubyDirectoryMemory",
484661Sksewell@umich.edu                    "PerfectCacheMemory": "RubyPerfectCacheMemory",
494661Sksewell@umich.edu                    "MemoryControl": "MemoryControl",
504661Sksewell@umich.edu                    "MessageBuffer": "MessageBuffer",
514661Sksewell@umich.edu                    "DMASequencer": "DMASequencer",
524661Sksewell@umich.edu                    "Prefetcher":"Prefetcher",
534661Sksewell@umich.edu                    "Cycles":"Cycles",
544661Sksewell@umich.edu                   }
554661Sksewell@umich.edu
564661Sksewell@umich.educlass StateMachine(Symbol):
574661Sksewell@umich.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
584661Sksewell@umich.edu        super(StateMachine, self).__init__(symtab, ident, location, pairs)
594661Sksewell@umich.edu        self.table = None
604661Sksewell@umich.edu
614661Sksewell@umich.edu        # Data members in the State Machine that have been declared before
624661Sksewell@umich.edu        # the opening brace '{'  of the machine.  Note that these along with
634661Sksewell@umich.edu        # the members in self.objects form the entire set of data members.
644661Sksewell@umich.edu        self.config_parameters = config_parameters
654661Sksewell@umich.edu
664661Sksewell@umich.edu        self.prefetchers = []
674661Sksewell@umich.edu
684661Sksewell@umich.edu        for param in config_parameters:
694661Sksewell@umich.edu            if param.pointer:
704661Sksewell@umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
714661Sksewell@umich.edu                          "(*m_%s_ptr)" % param.ident, {}, self)
724661Sksewell@umich.edu            else:
734661Sksewell@umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
744661Sksewell@umich.edu                          "m_%s" % param.ident, {}, self)
754661Sksewell@umich.edu
764661Sksewell@umich.edu            self.symtab.registerSym(param.ident, var)
774661Sksewell@umich.edu
784661Sksewell@umich.edu            if str(param.type_ast.type) == "Prefetcher":
794661Sksewell@umich.edu                self.prefetchers.append(var)
804661Sksewell@umich.edu
814661Sksewell@umich.edu        self.states = orderdict()
824661Sksewell@umich.edu        self.events = orderdict()
834661Sksewell@umich.edu        self.actions = orderdict()
844661Sksewell@umich.edu        self.request_types = orderdict()
854661Sksewell@umich.edu        self.transitions = []
864661Sksewell@umich.edu        self.in_ports = []
874661Sksewell@umich.edu        self.functions = []
884661Sksewell@umich.edu
894661Sksewell@umich.edu        # Data members in the State Machine that have been declared inside
904661Sksewell@umich.edu        # the {} machine.  Note that these along with the config params
914661Sksewell@umich.edu        # form the entire set of data members of the machine.
924661Sksewell@umich.edu        self.objects = []
934661Sksewell@umich.edu        self.TBEType   = None
944661Sksewell@umich.edu        self.EntryType = None
954661Sksewell@umich.edu        self.debug_flags = set()
964661Sksewell@umich.edu        self.debug_flags.add('RubyGenerated')
974661Sksewell@umich.edu        self.debug_flags.add('RubySlicc')
984661Sksewell@umich.edu
994661Sksewell@umich.edu    def __repr__(self):
1004661Sksewell@umich.edu        return "[StateMachine: %s]" % self.ident
1014661Sksewell@umich.edu
1024661Sksewell@umich.edu    def addState(self, state):
1034661Sksewell@umich.edu        assert self.table is None
1044661Sksewell@umich.edu        self.states[state.ident] = state
1054661Sksewell@umich.edu
1064661Sksewell@umich.edu    def addEvent(self, event):
1074661Sksewell@umich.edu        assert self.table is None
1084661Sksewell@umich.edu        self.events[event.ident] = event
1094661Sksewell@umich.edu
1104661Sksewell@umich.edu    def addAction(self, action):
1114661Sksewell@umich.edu        assert self.table is None
1124661Sksewell@umich.edu
1134661Sksewell@umich.edu        # Check for duplicate action
1144661Sksewell@umich.edu        for other in self.actions.itervalues():
1154661Sksewell@umich.edu            if action.ident == other.ident:
1164661Sksewell@umich.edu                action.warning("Duplicate action definition: %s" % action.ident)
1174661Sksewell@umich.edu                action.error("Duplicate action definition: %s" % action.ident)
1184661Sksewell@umich.edu            if action.short == other.short:
1194661Sksewell@umich.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
1204661Sksewell@umich.edu                other.warning("    shorthand = %s" % other.short)
1214661Sksewell@umich.edu                action.warning("Duplicate action shorthand: %s" % action.ident)
1224661Sksewell@umich.edu                action.error("    shorthand = %s" % action.short)
1234661Sksewell@umich.edu
1244661Sksewell@umich.edu        self.actions[action.ident] = action
1254661Sksewell@umich.edu
1264661Sksewell@umich.edu    def addDebugFlag(self, flag):
1274661Sksewell@umich.edu        self.debug_flags.add(flag)
1284661Sksewell@umich.edu
1294661Sksewell@umich.edu    def addRequestType(self, request_type):
1304661Sksewell@umich.edu        assert self.table is None
1314661Sksewell@umich.edu        self.request_types[request_type.ident] = request_type
1324661Sksewell@umich.edu
1334661Sksewell@umich.edu    def addTransition(self, trans):
1344661Sksewell@umich.edu        assert self.table is None
1354661Sksewell@umich.edu        self.transitions.append(trans)
1364661Sksewell@umich.edu
1374661Sksewell@umich.edu    def addInPort(self, var):
1384661Sksewell@umich.edu        self.in_ports.append(var)
1394661Sksewell@umich.edu
1404661Sksewell@umich.edu    def addFunc(self, func):
1414661Sksewell@umich.edu        # register func in the symbol table
1424661Sksewell@umich.edu        self.symtab.registerSym(str(func), func)
1434661Sksewell@umich.edu        self.functions.append(func)
1444661Sksewell@umich.edu
1454661Sksewell@umich.edu    def addObject(self, obj):
1464661Sksewell@umich.edu        self.symtab.registerSym(str(obj), obj)
1474661Sksewell@umich.edu        self.objects.append(obj)
1484661Sksewell@umich.edu
1494661Sksewell@umich.edu    def addType(self, type):
1504661Sksewell@umich.edu        type_ident = '%s' % type.c_ident
1514661Sksewell@umich.edu
1524661Sksewell@umich.edu        if type_ident == "%s_TBE" %self.ident:
1534661Sksewell@umich.edu            if self.TBEType != None:
1544661Sksewell@umich.edu                self.error("Multiple Transaction Buffer types in a " \
1554661Sksewell@umich.edu                           "single machine.");
1564661Sksewell@umich.edu            self.TBEType = type
1574661Sksewell@umich.edu
1584661Sksewell@umich.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1594661Sksewell@umich.edu            if "main" in type and "false" == type["main"].lower():
1604661Sksewell@umich.edu                pass # this isn't the EntryType
1614661Sksewell@umich.edu            else:
1624661Sksewell@umich.edu                if self.EntryType != None:
1634661Sksewell@umich.edu                    self.error("Multiple AbstractCacheEntry types in a " \
1644661Sksewell@umich.edu                               "single machine.");
1654661Sksewell@umich.edu                self.EntryType = type
1664661Sksewell@umich.edu
1674661Sksewell@umich.edu    # Needs to be called before accessing the table
1684661Sksewell@umich.edu    def buildTable(self):
1694661Sksewell@umich.edu        assert self.table is None
1704661Sksewell@umich.edu
1714661Sksewell@umich.edu        table = {}
1724661Sksewell@umich.edu
1734661Sksewell@umich.edu        for trans in self.transitions:
1744661Sksewell@umich.edu            # Track which actions we touch so we know if we use them
1754661Sksewell@umich.edu            # all -- really this should be done for all symbols as
1764661Sksewell@umich.edu            # part of the symbol table, then only trigger it for
1774661Sksewell@umich.edu            # Actions, States, Events, etc.
1784661Sksewell@umich.edu
1794661Sksewell@umich.edu            for action in trans.actions:
1804661Sksewell@umich.edu                action.used = True
1814661Sksewell@umich.edu
1824661Sksewell@umich.edu            index = (trans.state, trans.event)
1834661Sksewell@umich.edu            if index in table:
1844661Sksewell@umich.edu                table[index].warning("Duplicate transition: %s" % table[index])
1854661Sksewell@umich.edu                trans.error("Duplicate transition: %s" % trans)
1864661Sksewell@umich.edu            table[index] = trans
1874661Sksewell@umich.edu
1884661Sksewell@umich.edu        # Look at all actions to make sure we used them all
1894661Sksewell@umich.edu        for action in self.actions.itervalues():
1904661Sksewell@umich.edu            if not action.used:
1914661Sksewell@umich.edu                error_msg = "Unused action: %s" % action.ident
1924661Sksewell@umich.edu                if "desc" in action:
1934661Sksewell@umich.edu                    error_msg += ", "  + action.desc
1944661Sksewell@umich.edu                action.warning(error_msg)
1954661Sksewell@umich.edu        self.table = table
1964661Sksewell@umich.edu
1974661Sksewell@umich.edu    # determine the port->msg buffer mappings
1984661Sksewell@umich.edu    def getBufferMaps(self, ident):
1994661Sksewell@umich.edu        msg_bufs = []
2004661Sksewell@umich.edu        port_to_buf_map = {}
2014661Sksewell@umich.edu        in_msg_bufs = {}
2024661Sksewell@umich.edu        for port in self.in_ports:
2034661Sksewell@umich.edu            buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name
2044661Sksewell@umich.edu            msg_bufs.append(buf_name)
2054661Sksewell@umich.edu            port_to_buf_map[port] = msg_bufs.index(buf_name)
2064661Sksewell@umich.edu            if buf_name not in in_msg_bufs:
2074661Sksewell@umich.edu                in_msg_bufs[buf_name] = [port]
2084661Sksewell@umich.edu            else:
2094661Sksewell@umich.edu                in_msg_bufs[buf_name].append(port)
2104661Sksewell@umich.edu        return port_to_buf_map, in_msg_bufs, msg_bufs
2114661Sksewell@umich.edu
2124661Sksewell@umich.edu    def writeCodeFiles(self, path, includes):
2134661Sksewell@umich.edu        self.printControllerPython(path)
2144661Sksewell@umich.edu        self.printControllerHH(path)
2154661Sksewell@umich.edu        self.printControllerCC(path, includes)
2164661Sksewell@umich.edu        self.printCSwitch(path)
2174661Sksewell@umich.edu        self.printCWakeup(path, includes)
2184661Sksewell@umich.edu
2194661Sksewell@umich.edu    def printControllerPython(self, path):
2204661Sksewell@umich.edu        code = self.symtab.codeFormatter()
2214661Sksewell@umich.edu        ident = self.ident
2224661Sksewell@umich.edu
2234661Sksewell@umich.edu        py_ident = "%s_Controller" % ident
2244661Sksewell@umich.edu        c_ident = "%s_Controller" % self.ident
2254661Sksewell@umich.edu
2264661Sksewell@umich.edu        code('''
2274661Sksewell@umich.edufrom m5.params import *
2284661Sksewell@umich.edufrom m5.SimObject import SimObject
2294661Sksewell@umich.edufrom Controller import RubyController
2304661Sksewell@umich.edu
2314661Sksewell@umich.educlass $py_ident(RubyController):
2324661Sksewell@umich.edu    type = '$py_ident'
2334661Sksewell@umich.edu    cxx_header = 'mem/protocol/${c_ident}.hh'
2344661Sksewell@umich.edu''')
2354661Sksewell@umich.edu        code.indent()
2364661Sksewell@umich.edu        for param in self.config_parameters:
2374661Sksewell@umich.edu            dflt_str = ''
2384661Sksewell@umich.edu
2394661Sksewell@umich.edu            if param.rvalue is not None:
2404661Sksewell@umich.edu                dflt_str = str(param.rvalue.inline()) + ', '
2414661Sksewell@umich.edu
2424661Sksewell@umich.edu            if python_class_map.has_key(param.type_ast.type.c_ident):
2434661Sksewell@umich.edu                python_type = python_class_map[param.type_ast.type.c_ident]
2444661Sksewell@umich.edu                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
2454661Sksewell@umich.edu
2464661Sksewell@umich.edu            else:
2474661Sksewell@umich.edu                self.error("Unknown c++ to python class conversion for c++ " \
2484661Sksewell@umich.edu                           "type: '%s'. Please update the python_class_map " \
2494661Sksewell@umich.edu                           "in StateMachine.py", param.type_ast.type.c_ident)
2504661Sksewell@umich.edu
2514661Sksewell@umich.edu        code.dedent()
2524661Sksewell@umich.edu        code.write(path, '%s.py' % py_ident)
2534661Sksewell@umich.edu
2544661Sksewell@umich.edu
2554661Sksewell@umich.edu    def printControllerHH(self, path):
2564661Sksewell@umich.edu        '''Output the method declarations for the class declaration'''
2574661Sksewell@umich.edu        code = self.symtab.codeFormatter()
2584661Sksewell@umich.edu        ident = self.ident
2594661Sksewell@umich.edu        c_ident = "%s_Controller" % self.ident
2604661Sksewell@umich.edu
2614661Sksewell@umich.edu        code('''
2624661Sksewell@umich.edu/** \\file $c_ident.hh
2634661Sksewell@umich.edu *
2644661Sksewell@umich.edu * Auto generated C++ code started by $__file__:$__line__
2654661Sksewell@umich.edu * Created by slicc definition of Module "${{self.short}}"
2664661Sksewell@umich.edu */
2674661Sksewell@umich.edu
2684661Sksewell@umich.edu#ifndef __${ident}_CONTROLLER_HH__
2694661Sksewell@umich.edu#define __${ident}_CONTROLLER_HH__
2704661Sksewell@umich.edu
2714661Sksewell@umich.edu#include <iostream>
2724661Sksewell@umich.edu#include <sstream>
2734661Sksewell@umich.edu#include <string>
2744661Sksewell@umich.edu
2754661Sksewell@umich.edu#include "mem/protocol/TransitionResult.hh"
2764661Sksewell@umich.edu#include "mem/protocol/Types.hh"
2774661Sksewell@umich.edu#include "mem/ruby/common/Consumer.hh"
2784661Sksewell@umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
2794661Sksewell@umich.edu#include "params/$c_ident.hh"
2804661Sksewell@umich.edu
2814661Sksewell@umich.edu''')
2824661Sksewell@umich.edu
2834661Sksewell@umich.edu        seen_types = set()
2844661Sksewell@umich.edu        for var in self.objects:
2854661Sksewell@umich.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
2864661Sksewell@umich.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2874661Sksewell@umich.edu                seen_types.add(var.type.ident)
2884661Sksewell@umich.edu
2894661Sksewell@umich.edu        # for adding information to the protocol debug trace
2904661Sksewell@umich.edu        code('''
2914661Sksewell@umich.eduextern std::stringstream ${ident}_transitionComment;
2924661Sksewell@umich.edu
2934661Sksewell@umich.educlass $c_ident : public AbstractController
2944661Sksewell@umich.edu{
2954661Sksewell@umich.edu  public:
2964661Sksewell@umich.edu    typedef ${c_ident}Params Params;
2974661Sksewell@umich.edu    $c_ident(const Params *p);
2984661Sksewell@umich.edu    static int getNumControllers();
2994661Sksewell@umich.edu    void init();
3004661Sksewell@umich.edu
3014661Sksewell@umich.edu    MessageBuffer *getMandatoryQueue() const;
3024661Sksewell@umich.edu    MessageBuffer *getMemoryQueue() const;
3034661Sksewell@umich.edu    void initNetQueues();
3044661Sksewell@umich.edu
3054661Sksewell@umich.edu    void print(std::ostream& out) const;
3064661Sksewell@umich.edu    void wakeup();
3074661Sksewell@umich.edu    void resetStats();
3084661Sksewell@umich.edu    void regStats();
3094661Sksewell@umich.edu    void collateStats();
3104661Sksewell@umich.edu
3114661Sksewell@umich.edu    void recordCacheTrace(int cntrl, CacheRecorder* tr);
3124661Sksewell@umich.edu    Sequencer* getCPUSequencer() const;
3134661Sksewell@umich.edu    GPUCoalescer* getGPUCoalescer() const;
3144661Sksewell@umich.edu
3154661Sksewell@umich.edu    int functionalWriteBuffers(PacketPtr&);
3164661Sksewell@umich.edu
3174661Sksewell@umich.edu    void countTransition(${ident}_State state, ${ident}_Event event);
3184661Sksewell@umich.edu    void possibleTransition(${ident}_State state, ${ident}_Event event);
3194661Sksewell@umich.edu    uint64_t getEventCount(${ident}_Event event);
3204661Sksewell@umich.edu    bool isPossible(${ident}_State state, ${ident}_Event event);
3214661Sksewell@umich.edu    uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event);
3224661Sksewell@umich.edu
3234661Sksewell@umich.eduprivate:
3244661Sksewell@umich.edu''')
3254661Sksewell@umich.edu
3264661Sksewell@umich.edu        code.indent()
3274661Sksewell@umich.edu        # added by SS
3284661Sksewell@umich.edu        for param in self.config_parameters:
3294661Sksewell@umich.edu            if param.pointer:
3304661Sksewell@umich.edu                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
3314661Sksewell@umich.edu            else:
3324661Sksewell@umich.edu                code('${{param.type_ast.type}} m_${{param.ident}};')
3334661Sksewell@umich.edu
3344661Sksewell@umich.edu        code('''
3354661Sksewell@umich.eduTransitionResult doTransition(${ident}_Event event,
3364661Sksewell@umich.edu''')
3374661Sksewell@umich.edu
3384661Sksewell@umich.edu        if self.EntryType != None:
3394661Sksewell@umich.edu            code('''
3404661Sksewell@umich.edu                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
3414661Sksewell@umich.edu''')
3424661Sksewell@umich.edu        if self.TBEType != None:
3434661Sksewell@umich.edu            code('''
3444661Sksewell@umich.edu                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
3454661Sksewell@umich.edu''')
3464661Sksewell@umich.edu
3474661Sksewell@umich.edu        code('''
3484661Sksewell@umich.edu                              Addr addr);
3494661Sksewell@umich.edu
3504661Sksewell@umich.eduTransitionResult doTransitionWorker(${ident}_Event event,
3514661Sksewell@umich.edu                                    ${ident}_State state,
3524661Sksewell@umich.edu                                    ${ident}_State& next_state,
3534661Sksewell@umich.edu''')
3544661Sksewell@umich.edu
3554661Sksewell@umich.edu        if self.TBEType != None:
3564661Sksewell@umich.edu            code('''
3574661Sksewell@umich.edu                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
3584661Sksewell@umich.edu''')
3594661Sksewell@umich.edu        if self.EntryType != None:
3604661Sksewell@umich.edu            code('''
3614661Sksewell@umich.edu                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
3624661Sksewell@umich.edu''')
3634661Sksewell@umich.edu
3644661Sksewell@umich.edu        code('''
3654661Sksewell@umich.edu                                    Addr addr);
3664661Sksewell@umich.edu
3674661Sksewell@umich.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
3684661Sksewell@umich.eduint m_event_counters[${ident}_Event_NUM];
3694661Sksewell@umich.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
3704661Sksewell@umich.edu
3714661Sksewell@umich.edustatic std::vector<Stats::Vector *> eventVec;
3724661Sksewell@umich.edustatic std::vector<std::vector<Stats::Vector *> > transVec;
3734661Sksewell@umich.edustatic int m_num_controllers;
3744661Sksewell@umich.edu
3754661Sksewell@umich.edu// Internal functions
3764661Sksewell@umich.edu''')
3774661Sksewell@umich.edu
3784661Sksewell@umich.edu        for func in self.functions:
3794661Sksewell@umich.edu            proto = func.prototype
3804661Sksewell@umich.edu            if proto:
3814661Sksewell@umich.edu                code('$proto')
3824661Sksewell@umich.edu
3834661Sksewell@umich.edu        if self.EntryType != None:
3844661Sksewell@umich.edu            code('''
3854661Sksewell@umich.edu
3864661Sksewell@umich.edu// Set and Reset for cache_entry variable
3874661Sksewell@umich.eduvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
3884661Sksewell@umich.eduvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
3894661Sksewell@umich.edu''')
3904661Sksewell@umich.edu
3914661Sksewell@umich.edu        if self.TBEType != None:
3924661Sksewell@umich.edu            code('''
3934661Sksewell@umich.edu
3944661Sksewell@umich.edu// Set and Reset for tbe variable
3954661Sksewell@umich.eduvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3964661Sksewell@umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3974661Sksewell@umich.edu''')
3984661Sksewell@umich.edu
3994661Sksewell@umich.edu        # Prototype the actions that the controller can take
4004661Sksewell@umich.edu        code('''
4014661Sksewell@umich.edu
4024661Sksewell@umich.edu// Actions
4034661Sksewell@umich.edu''')
4044661Sksewell@umich.edu        if self.TBEType != None and self.EntryType != None:
4054661Sksewell@umich.edu            for action in self.actions.itervalues():
4064661Sksewell@umich.edu                code('/** \\brief ${{action.desc}} */')
4074661Sksewell@umich.edu                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
4084661Sksewell@umich.edu                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
4094661Sksewell@umich.edu                     'm_cache_entry_ptr, Addr addr);')
4104661Sksewell@umich.edu        elif self.TBEType != None:
4114661Sksewell@umich.edu            for action in self.actions.itervalues():
4124661Sksewell@umich.edu                code('/** \\brief ${{action.desc}} */')
4134661Sksewell@umich.edu                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
4144661Sksewell@umich.edu                     'm_tbe_ptr, Addr addr);')
4154661Sksewell@umich.edu        elif self.EntryType != None:
4164661Sksewell@umich.edu            for action in self.actions.itervalues():
4174661Sksewell@umich.edu                code('/** \\brief ${{action.desc}} */')
4184661Sksewell@umich.edu                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
4194661Sksewell@umich.edu                     'm_cache_entry_ptr, Addr addr);')
4204661Sksewell@umich.edu        else:
4214661Sksewell@umich.edu            for action in self.actions.itervalues():
4224661Sksewell@umich.edu                code('/** \\brief ${{action.desc}} */')
4234661Sksewell@umich.edu                code('void ${{action.ident}}(Addr addr);')
4244661Sksewell@umich.edu
4254661Sksewell@umich.edu        # the controller internal variables
4264661Sksewell@umich.edu        code('''
4274661Sksewell@umich.edu
4284661Sksewell@umich.edu// Objects
4294661Sksewell@umich.edu''')
4304661Sksewell@umich.edu        for var in self.objects:
4314661Sksewell@umich.edu            th = var.get("template", "")
4324661Sksewell@umich.edu            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
4334661Sksewell@umich.edu
4344661Sksewell@umich.edu        code.dedent()
4354661Sksewell@umich.edu        code('};')
4364661Sksewell@umich.edu        code('#endif // __${ident}_CONTROLLER_H__')
4374661Sksewell@umich.edu        code.write(path, '%s.hh' % c_ident)
4384661Sksewell@umich.edu
4394661Sksewell@umich.edu    def printControllerCC(self, path, includes):
4404661Sksewell@umich.edu        '''Output the actions for performing the actions'''
4414661Sksewell@umich.edu
4424661Sksewell@umich.edu        code = self.symtab.codeFormatter()
4434661Sksewell@umich.edu        ident = self.ident
4444661Sksewell@umich.edu        c_ident = "%s_Controller" % self.ident
4454661Sksewell@umich.edu
4464661Sksewell@umich.edu        code('''
4474661Sksewell@umich.edu/** \\file $c_ident.cc
4484661Sksewell@umich.edu *
4494661Sksewell@umich.edu * Auto generated C++ code started by $__file__:$__line__
4504661Sksewell@umich.edu * Created by slicc definition of Module "${{self.short}}"
4514661Sksewell@umich.edu */
4524661Sksewell@umich.edu
4534661Sksewell@umich.edu#include <sys/types.h>
4544661Sksewell@umich.edu#include <unistd.h>
4554661Sksewell@umich.edu
4564661Sksewell@umich.edu#include <cassert>
4574661Sksewell@umich.edu#include <sstream>
4584661Sksewell@umich.edu#include <string>
4594661Sksewell@umich.edu#include <typeinfo>
4604661Sksewell@umich.edu
4614661Sksewell@umich.edu#include "base/compiler.hh"
4624661Sksewell@umich.edu#include "base/cprintf.hh"
4634661Sksewell@umich.edu
4644661Sksewell@umich.edu''')
465        for f in self.debug_flags:
466            code('#include "debug/${{f}}.hh"')
467        code('''
468#include "mem/protocol/${ident}_Controller.hh"
469#include "mem/protocol/${ident}_Event.hh"
470#include "mem/protocol/${ident}_State.hh"
471#include "mem/protocol/Types.hh"
472#include "mem/ruby/system/RubySystem.hh"
473
474''')
475        for include_path in includes:
476            code('#include "${{include_path}}"')
477
478        code('''
479
480using namespace std;
481''')
482
483        # include object classes
484        seen_types = set()
485        for var in self.objects:
486            if var.type.ident not in seen_types and not var.type.isPrimitive:
487                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
488            seen_types.add(var.type.ident)
489
490        num_in_ports = len(self.in_ports)
491
492        code('''
493$c_ident *
494${c_ident}Params::create()
495{
496    return new $c_ident(this);
497}
498
499int $c_ident::m_num_controllers = 0;
500std::vector<Stats::Vector *>  $c_ident::eventVec;
501std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
502
503// for adding information to the protocol debug trace
504stringstream ${ident}_transitionComment;
505
506#ifndef NDEBUG
507#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
508#else
509#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
510#endif
511
512/** \\brief constructor */
513$c_ident::$c_ident(const Params *p)
514    : AbstractController(p)
515{
516    m_machineID.type = MachineType_${ident};
517    m_machineID.num = m_version;
518    m_num_controllers++;
519
520    m_in_ports = $num_in_ports;
521''')
522        code.indent()
523
524        #
525        # After initializing the universal machine parameters, initialize the
526        # this machines config parameters.  Also if these configuration params
527        # include a sequencer, connect the it to the controller.
528        #
529        for param in self.config_parameters:
530            if param.pointer:
531                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
532            else:
533                code('m_${{param.ident}} = p->${{param.ident}};')
534
535            if re.compile("sequencer").search(param.ident) or \
536                   param.type_ast.type.c_ident == "GPUCoalescer" or \
537                   param.type_ast.type.c_ident == "VIPERCoalescer":
538                code('''
539if (m_${{param.ident}}_ptr != NULL) {
540    m_${{param.ident}}_ptr->setController(this);
541}
542''')
543
544        code('''
545
546for (int state = 0; state < ${ident}_State_NUM; state++) {
547    for (int event = 0; event < ${ident}_Event_NUM; event++) {
548        m_possible[state][event] = false;
549        m_counters[state][event] = 0;
550    }
551}
552for (int event = 0; event < ${ident}_Event_NUM; event++) {
553    m_event_counters[event] = 0;
554}
555''')
556        code.dedent()
557        code('''
558}
559
560void
561$c_ident::initNetQueues()
562{
563    MachineType machine_type = string_to_MachineType("${{self.ident}}");
564    int base M5_VAR_USED = MachineType_base_number(machine_type);
565
566''')
567        code.indent()
568
569        # set for maintaining the vnet, direction pairs already seen for this
570        # machine.  This map helps in implementing the check for avoiding
571        # multiple message buffers being mapped to the same vnet.
572        vnet_dir_set = set()
573
574        for var in self.config_parameters:
575            vid = "m_%s_ptr" % var.ident
576            if "network" in var:
577                vtype = var.type_ast.type
578                code('assert($vid != NULL);')
579
580                # Network port object
581                network = var["network"]
582
583                if "virtual_network" in var:
584                    vnet = var["virtual_network"]
585                    vnet_type = var["vnet_type"]
586
587                    assert (vnet, network) not in vnet_dir_set
588                    vnet_dir_set.add((vnet,network))
589
590                    code('''
591m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet,
592                                 "$vnet_type", $vid);
593''')
594                # Set Priority
595                if "rank" in var:
596                    code('$vid->setPriority(${{var["rank"]}})')
597
598        code.dedent()
599        code('''
600}
601
602void
603$c_ident::init()
604{
605    // initialize objects
606''')
607
608        code.indent()
609
610        for var in self.objects:
611            vtype = var.type
612            vid = "m_%s_ptr" % var.ident
613            if "network" not in var:
614                # Not a network port object
615                if "primitive" in vtype:
616                    code('$vid = new ${{vtype.c_ident}};')
617                    if "default" in var:
618                        code('(*$vid) = ${{var["default"]}};')
619                else:
620                    # Normal Object
621                    th = var.get("template", "")
622                    expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
623                    args = ""
624                    if "non_obj" not in vtype and not vtype.isEnumeration:
625                        args = var.get("constructor", "")
626
627                    code('$expr($args);')
628                    code('assert($vid != NULL);')
629
630                    if "default" in var:
631                        code('*$vid = ${{var["default"]}}; // Object default')
632                    elif "default" in vtype:
633                        comment = "Type %s default" % vtype.ident
634                        code('*$vid = ${{vtype["default"]}}; // $comment')
635
636        # Set the prefetchers
637        code()
638        for prefetcher in self.prefetchers:
639            code('${{prefetcher.code}}.setController(this);')
640
641        code()
642        for port in self.in_ports:
643            # Set the queue consumers
644            code('${{port.code}}.setConsumer(this);')
645
646        # Initialize the transition profiling
647        code()
648        for trans in self.transitions:
649            # Figure out if we stall
650            stall = False
651            for action in trans.actions:
652                if action.ident == "z_stall":
653                    stall = True
654
655            # Only possible if it is not a 'z' case
656            if not stall:
657                state = "%s_State_%s" % (self.ident, trans.state.ident)
658                event = "%s_Event_%s" % (self.ident, trans.event.ident)
659                code('possibleTransition($state, $event);')
660
661        code.dedent()
662        code('''
663    AbstractController::init();
664    resetStats();
665}
666''')
667
668        mq_ident = "NULL"
669        for port in self.in_ports:
670            if port.code.find("mandatoryQueue_ptr") >= 0:
671                mq_ident = "m_mandatoryQueue_ptr"
672
673        memq_ident = "NULL"
674        for port in self.in_ports:
675            if port.code.find("responseFromMemory_ptr") >= 0:
676                memq_ident = "m_responseFromMemory_ptr"
677
678        seq_ident = "NULL"
679        for param in self.config_parameters:
680            if param.ident == "sequencer":
681                assert(param.pointer)
682                seq_ident = "m_%s_ptr" % param.ident
683
684        coal_ident = "NULL"
685        for param in self.config_parameters:
686            if param.ident == "coalescer":
687                assert(param.pointer)
688                coal_ident = "m_%s_ptr" % param.ident
689
690        if seq_ident != "NULL":
691            code('''
692Sequencer*
693$c_ident::getCPUSequencer() const
694{
695    if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) {
696        return $seq_ident;
697    } else {
698        return NULL;
699    }
700}
701''')
702        else:
703            code('''
704
705Sequencer*
706$c_ident::getCPUSequencer() const
707{
708    return NULL;
709}
710''')
711
712        if coal_ident != "NULL":
713            code('''
714GPUCoalescer*
715$c_ident::getGPUCoalescer() const
716{
717    if (NULL != $coal_ident && !$coal_ident->isCPUSequencer()) {
718        return $coal_ident;
719    } else {
720        return NULL;
721    }
722}
723''')
724        else:
725            code('''
726
727GPUCoalescer*
728$c_ident::getGPUCoalescer() const
729{
730    return NULL;
731}
732''')
733
734        code('''
735
736void
737$c_ident::regStats()
738{
739    AbstractController::regStats();
740
741    if (m_version == 0) {
742        for (${ident}_Event event = ${ident}_Event_FIRST;
743             event < ${ident}_Event_NUM; ++event) {
744            Stats::Vector *t = new Stats::Vector();
745            t->init(m_num_controllers);
746            t->name(params()->ruby_system->name() + ".${c_ident}." +
747                ${ident}_Event_to_string(event));
748            t->flags(Stats::pdf | Stats::total | Stats::oneline |
749                     Stats::nozero);
750
751            eventVec.push_back(t);
752        }
753
754        for (${ident}_State state = ${ident}_State_FIRST;
755             state < ${ident}_State_NUM; ++state) {
756
757            transVec.push_back(std::vector<Stats::Vector *>());
758
759            for (${ident}_Event event = ${ident}_Event_FIRST;
760                 event < ${ident}_Event_NUM; ++event) {
761
762                Stats::Vector *t = new Stats::Vector();
763                t->init(m_num_controllers);
764                t->name(params()->ruby_system->name() + ".${c_ident}." +
765                        ${ident}_State_to_string(state) +
766                        "." + ${ident}_Event_to_string(event));
767
768                t->flags(Stats::pdf | Stats::total | Stats::oneline |
769                         Stats::nozero);
770                transVec[state].push_back(t);
771            }
772        }
773    }
774}
775
776void
777$c_ident::collateStats()
778{
779    for (${ident}_Event event = ${ident}_Event_FIRST;
780         event < ${ident}_Event_NUM; ++event) {
781        for (unsigned int i = 0; i < m_num_controllers; ++i) {
782            RubySystem *rs = params()->ruby_system;
783            std::map<uint32_t, AbstractController *>::iterator it =
784                     rs->m_abstract_controls[MachineType_${ident}].find(i);
785            assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
786            (*eventVec[event])[i] =
787                (($c_ident *)(*it).second)->getEventCount(event);
788        }
789    }
790
791    for (${ident}_State state = ${ident}_State_FIRST;
792         state < ${ident}_State_NUM; ++state) {
793
794        for (${ident}_Event event = ${ident}_Event_FIRST;
795             event < ${ident}_Event_NUM; ++event) {
796
797            for (unsigned int i = 0; i < m_num_controllers; ++i) {
798                RubySystem *rs = params()->ruby_system;
799                std::map<uint32_t, AbstractController *>::iterator it =
800                         rs->m_abstract_controls[MachineType_${ident}].find(i);
801                assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
802                (*transVec[state][event])[i] =
803                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
804            }
805        }
806    }
807}
808
809void
810$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
811{
812    assert(m_possible[state][event]);
813    m_counters[state][event]++;
814    m_event_counters[event]++;
815}
816void
817$c_ident::possibleTransition(${ident}_State state,
818                             ${ident}_Event event)
819{
820    m_possible[state][event] = true;
821}
822
823uint64_t
824$c_ident::getEventCount(${ident}_Event event)
825{
826    return m_event_counters[event];
827}
828
829bool
830$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
831{
832    return m_possible[state][event];
833}
834
835uint64_t
836$c_ident::getTransitionCount(${ident}_State state,
837                             ${ident}_Event event)
838{
839    return m_counters[state][event];
840}
841
842int
843$c_ident::getNumControllers()
844{
845    return m_num_controllers;
846}
847
848MessageBuffer*
849$c_ident::getMandatoryQueue() const
850{
851    return $mq_ident;
852}
853
854MessageBuffer*
855$c_ident::getMemoryQueue() const
856{
857    return $memq_ident;
858}
859
860void
861$c_ident::print(ostream& out) const
862{
863    out << "[$c_ident " << m_version << "]";
864}
865
866void $c_ident::resetStats()
867{
868    for (int state = 0; state < ${ident}_State_NUM; state++) {
869        for (int event = 0; event < ${ident}_Event_NUM; event++) {
870            m_counters[state][event] = 0;
871        }
872    }
873
874    for (int event = 0; event < ${ident}_Event_NUM; event++) {
875        m_event_counters[event] = 0;
876    }
877
878    AbstractController::resetStats();
879}
880''')
881
882        if self.EntryType != None:
883            code('''
884
885// Set and Reset for cache_entry variable
886void
887$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
888{
889  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
890}
891
892void
893$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
894{
895  m_cache_entry_ptr = 0;
896}
897''')
898
899        if self.TBEType != None:
900            code('''
901
902// Set and Reset for tbe variable
903void
904$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
905{
906  m_tbe_ptr = m_new_tbe;
907}
908
909void
910$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
911{
912  m_tbe_ptr = NULL;
913}
914''')
915
916        code('''
917
918void
919$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
920{
921''')
922        #
923        # Record cache contents for all associated caches.
924        #
925        code.indent()
926        for param in self.config_parameters:
927            if param.type_ast.type.ident == "CacheMemory":
928                assert(param.pointer)
929                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
930
931        code.dedent()
932        code('''
933}
934
935// Actions
936''')
937        if self.TBEType != None and self.EntryType != None:
938            for action in self.actions.itervalues():
939                if "c_code" not in action:
940                 continue
941
942                code('''
943/** \\brief ${{action.desc}} */
944void
945$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
946{
947    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
948    try {
949       ${{action["c_code"]}}
950    } catch (const RejectException & e) {
951       fatal("Error in action ${{ident}}:${{action.ident}}: "
952             "executed a peek statement with the wrong message "
953             "type specified. ");
954    }
955}
956
957''')
958        elif self.TBEType != None:
959            for action in self.actions.itervalues():
960                if "c_code" not in action:
961                 continue
962
963                code('''
964/** \\brief ${{action.desc}} */
965void
966$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr)
967{
968    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
969    ${{action["c_code"]}}
970}
971
972''')
973        elif self.EntryType != None:
974            for action in self.actions.itervalues():
975                if "c_code" not in action:
976                 continue
977
978                code('''
979/** \\brief ${{action.desc}} */
980void
981$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
982{
983    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
984    ${{action["c_code"]}}
985}
986
987''')
988        else:
989            for action in self.actions.itervalues():
990                if "c_code" not in action:
991                 continue
992
993                code('''
994/** \\brief ${{action.desc}} */
995void
996$c_ident::${{action.ident}}(Addr addr)
997{
998    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
999    ${{action["c_code"]}}
1000}
1001
1002''')
1003        for func in self.functions:
1004            code(func.generateCode())
1005
1006        # Function for functional writes to messages buffered in the controller
1007        code('''
1008int
1009$c_ident::functionalWriteBuffers(PacketPtr& pkt)
1010{
1011    int num_functional_writes = 0;
1012''')
1013        for var in self.objects:
1014            vtype = var.type
1015            if vtype.isBuffer:
1016                vid = "m_%s_ptr" % var.ident
1017                code('num_functional_writes += $vid->functionalWrite(pkt);')
1018
1019        for var in self.config_parameters:
1020            vtype = var.type_ast.type
1021            if vtype.isBuffer:
1022                vid = "m_%s_ptr" % var.ident
1023                code('num_functional_writes += $vid->functionalWrite(pkt);')
1024
1025        code('''
1026    return num_functional_writes;
1027}
1028''')
1029
1030        code.write(path, "%s.cc" % c_ident)
1031
1032    def printCWakeup(self, path, includes):
1033        '''Output the wakeup loop for the events'''
1034
1035        code = self.symtab.codeFormatter()
1036        ident = self.ident
1037
1038        outputRequest_types = True
1039        if len(self.request_types) == 0:
1040            outputRequest_types = False
1041
1042        code('''
1043// Auto generated C++ code started by $__file__:$__line__
1044// ${ident}: ${{self.short}}
1045
1046#include <sys/types.h>
1047#include <unistd.h>
1048
1049#include <cassert>
1050#include <typeinfo>
1051
1052#include "base/misc.hh"
1053
1054''')
1055        for f in self.debug_flags:
1056            code('#include "debug/${{f}}.hh"')
1057        code('''
1058#include "mem/protocol/${ident}_Controller.hh"
1059#include "mem/protocol/${ident}_Event.hh"
1060#include "mem/protocol/${ident}_State.hh"
1061
1062''')
1063
1064        if outputRequest_types:
1065            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1066
1067        code('''
1068#include "mem/protocol/Types.hh"
1069#include "mem/ruby/system/RubySystem.hh"
1070
1071''')
1072
1073
1074        for include_path in includes:
1075            code('#include "${{include_path}}"')
1076
1077        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1078
1079        code('''
1080
1081using namespace std;
1082
1083void
1084${ident}_Controller::wakeup()
1085{
1086    int counter = 0;
1087    while (true) {
1088        unsigned char rejected[${{len(msg_bufs)}}];
1089        memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
1090        // Some cases will put us into an infinite loop without this limit
1091        assert(counter <= m_transitions_per_cycle);
1092        if (counter == m_transitions_per_cycle) {
1093            // Count how often we are fully utilized
1094            m_fully_busy_cycles++;
1095
1096            // Wakeup in another cycle and try again
1097            scheduleEvent(Cycles(1));
1098            break;
1099        }
1100''')
1101
1102        code.indent()
1103        code.indent()
1104
1105        # InPorts
1106        #
1107        for port in self.in_ports:
1108            code.indent()
1109            code('// ${ident}InPort $port')
1110            if port.pairs.has_key("rank"):
1111                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1112            else:
1113                code('m_cur_in_port = 0;')
1114            if port in port_to_buf_map:
1115                code('try {')
1116                code.indent()
1117            code('${{port["c_code_in_port"]}}')
1118
1119            if port in port_to_buf_map:
1120                code.dedent()
1121                code('''
1122            } catch (const RejectException & e) {
1123                rejected[${{port_to_buf_map[port]}}]++;
1124            }
1125''')
1126            code.dedent()
1127            code('')
1128
1129        code.dedent()
1130        code.dedent()
1131        code('''
1132        // If we got this far, we have nothing left todo or something went
1133        // wrong''')
1134        for buf_name, ports in in_msg_bufs.items():
1135            if len(ports) > 1:
1136                # only produce checks when a buffer is shared by multiple ports
1137                code('''
1138        if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
1139        {
1140            // no port claimed the message on the top of this buffer
1141            panic("Runtime Error at Ruby Time: %d. "
1142                  "All ports rejected a message. "
1143                  "You are probably sending a message type to this controller "
1144                  "over a virtual network that do not define an in_port for "
1145                  "the incoming message type.\\n",
1146                  Cycles(1));
1147        }
1148''')
1149        code('''
1150        break;
1151    }
1152}
1153''')
1154
1155        code.write(path, "%s_Wakeup.cc" % self.ident)
1156
1157    def printCSwitch(self, path):
1158        '''Output switch statement for transition table'''
1159
1160        code = self.symtab.codeFormatter()
1161        ident = self.ident
1162
1163        code('''
1164// Auto generated C++ code started by $__file__:$__line__
1165// ${ident}: ${{self.short}}
1166
1167#include <cassert>
1168
1169#include "base/misc.hh"
1170#include "base/trace.hh"
1171#include "debug/ProtocolTrace.hh"
1172#include "debug/RubyGenerated.hh"
1173#include "mem/protocol/${ident}_Controller.hh"
1174#include "mem/protocol/${ident}_Event.hh"
1175#include "mem/protocol/${ident}_State.hh"
1176#include "mem/protocol/Types.hh"
1177#include "mem/ruby/system/RubySystem.hh"
1178
1179#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1180
1181#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1182#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1183
1184TransitionResult
1185${ident}_Controller::doTransition(${ident}_Event event,
1186''')
1187        if self.EntryType != None:
1188            code('''
1189                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1190''')
1191        if self.TBEType != None:
1192            code('''
1193                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1194''')
1195        code('''
1196                                  Addr addr)
1197{
1198''')
1199        code.indent()
1200
1201        if self.TBEType != None and self.EntryType != None:
1202            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1203        elif self.TBEType != None:
1204            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1205        elif self.EntryType != None:
1206            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1207        else:
1208            code('${ident}_State state = getState(addr);')
1209
1210        code('''
1211${ident}_State next_state = state;
1212
1213DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n",
1214        *this, curCycle(), ${ident}_State_to_string(state),
1215        ${ident}_Event_to_string(event), addr);
1216
1217TransitionResult result =
1218''')
1219        if self.TBEType != None and self.EntryType != None:
1220            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1221        elif self.TBEType != None:
1222            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1223        elif self.EntryType != None:
1224            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1225        else:
1226            code('doTransitionWorker(event, state, next_state, addr);')
1227
1228        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1229
1230        code('''
1231
1232if (result == TransitionResult_Valid) {
1233    DPRINTF(RubyGenerated, "next_state: %s\\n",
1234            ${ident}_State_to_string(next_state));
1235    countTransition(state, event);
1236
1237    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n",
1238             curTick(), m_version, "${ident}",
1239             ${ident}_Event_to_string(event),
1240             ${ident}_State_to_string(state),
1241             ${ident}_State_to_string(next_state),
1242             printAddress(addr), GET_TRANSITION_COMMENT());
1243
1244    CLEAR_TRANSITION_COMMENT();
1245''')
1246        if self.TBEType != None and self.EntryType != None:
1247            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1248            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1249        elif self.TBEType != None:
1250            code('setState(m_tbe_ptr, addr, next_state);')
1251            code('setAccessPermission(addr, next_state);')
1252        elif self.EntryType != None:
1253            code('setState(m_cache_entry_ptr, addr, next_state);')
1254            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1255        else:
1256            code('setState(addr, next_state);')
1257            code('setAccessPermission(addr, next_state);')
1258
1259        code('''
1260} else if (result == TransitionResult_ResourceStall) {
1261    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1262             curTick(), m_version, "${ident}",
1263             ${ident}_Event_to_string(event),
1264             ${ident}_State_to_string(state),
1265             ${ident}_State_to_string(next_state),
1266             printAddress(addr), "Resource Stall");
1267} else if (result == TransitionResult_ProtocolStall) {
1268    DPRINTF(RubyGenerated, "stalling\\n");
1269    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1270             curTick(), m_version, "${ident}",
1271             ${ident}_Event_to_string(event),
1272             ${ident}_State_to_string(state),
1273             ${ident}_State_to_string(next_state),
1274             printAddress(addr), "Protocol Stall");
1275}
1276
1277return result;
1278''')
1279        code.dedent()
1280        code('''
1281}
1282
1283TransitionResult
1284${ident}_Controller::doTransitionWorker(${ident}_Event event,
1285                                        ${ident}_State state,
1286                                        ${ident}_State& next_state,
1287''')
1288
1289        if self.TBEType != None:
1290            code('''
1291                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1292''')
1293        if self.EntryType != None:
1294                  code('''
1295                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1296''')
1297        code('''
1298                                        Addr addr)
1299{
1300    switch(HASH_FUN(state, event)) {
1301''')
1302
1303        # This map will allow suppress generating duplicate code
1304        cases = orderdict()
1305
1306        for trans in self.transitions:
1307            case_string = "%s_State_%s, %s_Event_%s" % \
1308                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1309
1310            case = self.symtab.codeFormatter()
1311            # Only set next_state if it changes
1312            if trans.state != trans.nextState:
1313                if trans.nextState.isWildcard():
1314                    # When * is encountered as an end state of a transition,
1315                    # the next state is determined by calling the
1316                    # machine-specific getNextState function. The next state
1317                    # is determined before any actions of the transition
1318                    # execute, and therefore the next state calculation cannot
1319                    # depend on any of the transitionactions.
1320                    case('next_state = getNextState(addr);')
1321                else:
1322                    ns_ident = trans.nextState.ident
1323                    case('next_state = ${ident}_State_${ns_ident};')
1324
1325            actions = trans.actions
1326            request_types = trans.request_types
1327
1328            # Check for resources
1329            case_sorter = []
1330            res = trans.resources
1331            for key,val in res.iteritems():
1332                val = '''
1333if (!%s.areNSlotsAvailable(%s, clockEdge()))
1334    return TransitionResult_ResourceStall;
1335''' % (key.code, val)
1336                case_sorter.append(val)
1337
1338            # Check all of the request_types for resource constraints
1339            for request_type in request_types:
1340                val = '''
1341if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1342    return TransitionResult_ResourceStall;
1343}
1344''' % (self.ident, request_type.ident)
1345                case_sorter.append(val)
1346
1347            # Emit the code sequences in a sorted order.  This makes the
1348            # output deterministic (without this the output order can vary
1349            # since Map's keys() on a vector of pointers is not deterministic
1350            for c in sorted(case_sorter):
1351                case("$c")
1352
1353            # Record access types for this transition
1354            for request_type in request_types:
1355                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1356
1357            # Figure out if we stall
1358            stall = False
1359            for action in actions:
1360                if action.ident == "z_stall":
1361                    stall = True
1362                    break
1363
1364            if stall:
1365                case('return TransitionResult_ProtocolStall;')
1366            else:
1367                if self.TBEType != None and self.EntryType != None:
1368                    for action in actions:
1369                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1370                elif self.TBEType != None:
1371                    for action in actions:
1372                        case('${{action.ident}}(m_tbe_ptr, addr);')
1373                elif self.EntryType != None:
1374                    for action in actions:
1375                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1376                else:
1377                    for action in actions:
1378                        case('${{action.ident}}(addr);')
1379                case('return TransitionResult_Valid;')
1380
1381            case = str(case)
1382
1383            # Look to see if this transition code is unique.
1384            if case not in cases:
1385                cases[case] = []
1386
1387            cases[case].append(case_string)
1388
1389        # Walk through all of the unique code blocks and spit out the
1390        # corresponding case statement elements
1391        for case,transitions in cases.iteritems():
1392            # Iterative over all the multiple transitions that share
1393            # the same code
1394            for trans in transitions:
1395                code('  case HASH_FUN($trans):')
1396            code('    $case\n')
1397
1398        code('''
1399      default:
1400        panic("Invalid transition\\n"
1401              "%s time: %d addr: %s event: %s state: %s\\n",
1402              name(), curCycle(), addr, event, state);
1403    }
1404
1405    return TransitionResult_Valid;
1406}
1407''')
1408        code.write(path, "%s_Transitions.cc" % self.ident)
1409
1410
1411    # **************************
1412    # ******* HTML Files *******
1413    # **************************
1414    def frameRef(self, click_href, click_target, over_href, over_num, text):
1415        code = self.symtab.codeFormatter(fix_newlines=False)
1416        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1417    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1418        parent.frames[$over_num].location='$over_href'
1419    }\">
1420    ${{html.formatShorthand(text)}}
1421    </A>""")
1422        return str(code)
1423
1424    def writeHTMLFiles(self, path):
1425        # Create table with no row hilighted
1426        self.printHTMLTransitions(path, None)
1427
1428        # Generate transition tables
1429        for state in self.states.itervalues():
1430            self.printHTMLTransitions(path, state)
1431
1432        # Generate action descriptions
1433        for action in self.actions.itervalues():
1434            name = "%s_action_%s.html" % (self.ident, action.ident)
1435            code = html.createSymbol(action, "Action")
1436            code.write(path, name)
1437
1438        # Generate state descriptions
1439        for state in self.states.itervalues():
1440            name = "%s_State_%s.html" % (self.ident, state.ident)
1441            code = html.createSymbol(state, "State")
1442            code.write(path, name)
1443
1444        # Generate event descriptions
1445        for event in self.events.itervalues():
1446            name = "%s_Event_%s.html" % (self.ident, event.ident)
1447            code = html.createSymbol(event, "Event")
1448            code.write(path, name)
1449
1450    def printHTMLTransitions(self, path, active_state):
1451        code = self.symtab.codeFormatter()
1452
1453        code('''
1454<HTML>
1455<BODY link="blue" vlink="blue">
1456
1457<H1 align="center">${{html.formatShorthand(self.short)}}:
1458''')
1459        code.indent()
1460        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1461            mid = machine.ident
1462            if i != 0:
1463                extra = " - "
1464            else:
1465                extra = ""
1466            if machine == self:
1467                code('$extra$mid')
1468            else:
1469                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1470        code.dedent()
1471
1472        code("""
1473</H1>
1474
1475<TABLE border=1>
1476<TR>
1477  <TH> </TH>
1478""")
1479
1480        for event in self.events.itervalues():
1481            href = "%s_Event_%s.html" % (self.ident, event.ident)
1482            ref = self.frameRef(href, "Status", href, "1", event.short)
1483            code('<TH bgcolor=white>$ref</TH>')
1484
1485        code('</TR>')
1486        # -- Body of table
1487        for state in self.states.itervalues():
1488            # -- Each row
1489            if state == active_state:
1490                color = "yellow"
1491            else:
1492                color = "white"
1493
1494            click = "%s_table_%s.html" % (self.ident, state.ident)
1495            over = "%s_State_%s.html" % (self.ident, state.ident)
1496            text = html.formatShorthand(state.short)
1497            ref = self.frameRef(click, "Table", over, "1", state.short)
1498            code('''
1499<TR>
1500  <TH bgcolor=$color>$ref</TH>
1501''')
1502
1503            # -- One column for each event
1504            for event in self.events.itervalues():
1505                trans = self.table.get((state,event), None)
1506                if trans is None:
1507                    # This is the no transition case
1508                    if state == active_state:
1509                        color = "#C0C000"
1510                    else:
1511                        color = "lightgrey"
1512
1513                    code('<TD bgcolor=$color>&nbsp;</TD>')
1514                    continue
1515
1516                next = trans.nextState
1517                stall_action = False
1518
1519                # -- Get the actions
1520                for action in trans.actions:
1521                    if action.ident == "z_stall" or \
1522                       action.ident == "zz_recycleMandatoryQueue":
1523                        stall_action = True
1524
1525                # -- Print out "actions/next-state"
1526                if stall_action:
1527                    if state == active_state:
1528                        color = "#C0C000"
1529                    else:
1530                        color = "lightgrey"
1531
1532                elif active_state and next.ident == active_state.ident:
1533                    color = "aqua"
1534                elif state == active_state:
1535                    color = "yellow"
1536                else:
1537                    color = "white"
1538
1539                code('<TD bgcolor=$color>')
1540                for action in trans.actions:
1541                    href = "%s_action_%s.html" % (self.ident, action.ident)
1542                    ref = self.frameRef(href, "Status", href, "1",
1543                                        action.short)
1544                    code('  $ref')
1545                if next != state:
1546                    if trans.actions:
1547                        code('/')
1548                    click = "%s_table_%s.html" % (self.ident, next.ident)
1549                    over = "%s_State_%s.html" % (self.ident, next.ident)
1550                    ref = self.frameRef(click, "Table", over, "1", next.short)
1551                    code("$ref")
1552                code("</TD>")
1553
1554            # -- Each row
1555            if state == active_state:
1556                color = "yellow"
1557            else:
1558                color = "white"
1559
1560            click = "%s_table_%s.html" % (self.ident, state.ident)
1561            over = "%s_State_%s.html" % (self.ident, state.ident)
1562            ref = self.frameRef(click, "Table", over, "1", state.short)
1563            code('''
1564  <TH bgcolor=$color>$ref</TH>
1565</TR>
1566''')
1567        code('''
1568<!- Column footer->
1569<TR>
1570  <TH> </TH>
1571''')
1572
1573        for event in self.events.itervalues():
1574            href = "%s_Event_%s.html" % (self.ident, event.ident)
1575            ref = self.frameRef(href, "Status", href, "1", event.short)
1576            code('<TH bgcolor=white>$ref</TH>')
1577        code('''
1578</TR>
1579</TABLE>
1580</BODY></HTML>
1581''')
1582
1583
1584        if active_state:
1585            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1586        else:
1587            name = "%s_table.html" % self.ident
1588        code.write(path, name)
1589
1590__all__ = [ "StateMachine" ]
1591