StateMachine.py revision 11111:6da33e720481
12810Srdreslin@umich.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
28702Sandreas.hansson@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company
38702Sandreas.hansson@arm.com# Copyright (c) 2013 Advanced Micro Devices, Inc.
48702Sandreas.hansson@arm.com# All rights reserved.
58702Sandreas.hansson@arm.com#
68702Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without
78702Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are
88702Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright
98702Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer;
108702Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright
118702Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the
128702Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution;
138702Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its
142810Srdreslin@umich.edu# contributors may be used to endorse or promote products derived from
152810Srdreslin@umich.edu# this software without specific prior written permission.
162810Srdreslin@umich.edu#
172810Srdreslin@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182810Srdreslin@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192810Srdreslin@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202810Srdreslin@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212810Srdreslin@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222810Srdreslin@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232810Srdreslin@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242810Srdreslin@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252810Srdreslin@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262810Srdreslin@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272810Srdreslin@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282810Srdreslin@umich.edu
292810Srdreslin@umich.edufrom m5.util import orderdict
302810Srdreslin@umich.edu
312810Srdreslin@umich.edufrom slicc.symbols.Symbol import Symbol
322810Srdreslin@umich.edufrom slicc.symbols.Var import Var
332810Srdreslin@umich.eduimport slicc.generate.html as html
342810Srdreslin@umich.eduimport re
352810Srdreslin@umich.edu
362810Srdreslin@umich.edupython_class_map = {
372810Srdreslin@umich.edu                    "int": "Int",
382810Srdreslin@umich.edu                    "uint32_t" : "UInt32",
392810Srdreslin@umich.edu                    "std::string": "String",
402810Srdreslin@umich.edu                    "bool": "Bool",
412810Srdreslin@umich.edu                    "CacheMemory": "RubyCache",
422810Srdreslin@umich.edu                    "WireBuffer": "RubyWireBuffer",
434458Sstever@eecs.umich.edu                    "Sequencer": "RubySequencer",
448856Sandreas.hansson@arm.com                    "DirectoryMemory": "RubyDirectoryMemory",
452810Srdreslin@umich.edu                    "MemoryControl": "MemoryControl",
462810Srdreslin@umich.edu                    "MessageBuffer": "MessageBuffer",
472810Srdreslin@umich.edu                    "DMASequencer": "DMASequencer",
482810Srdreslin@umich.edu                    "Prefetcher":"Prefetcher",
492810Srdreslin@umich.edu                    "Cycles":"Cycles",
502810Srdreslin@umich.edu                   }
512810Srdreslin@umich.edu
522810Srdreslin@umich.educlass StateMachine(Symbol):
532810Srdreslin@umich.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
542810Srdreslin@umich.edu        super(StateMachine, self).__init__(symtab, ident, location, pairs)
552810Srdreslin@umich.edu        self.table = None
565338Sstever@gmail.com
575338Sstever@gmail.com        # Data members in the State Machine that have been declared before
585338Sstever@gmail.com        # the opening brace '{'  of the machine.  Note that these along with
594458Sstever@eecs.umich.edu        # the members in self.objects form the entire set of data members.
604458Sstever@eecs.umich.edu        self.config_parameters = config_parameters
612813Srdreslin@umich.edu
623861Sstever@eecs.umich.edu        self.prefetchers = []
632810Srdreslin@umich.edu
642810Srdreslin@umich.edu        for param in config_parameters:
652810Srdreslin@umich.edu            if param.pointer:
662810Srdreslin@umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
674672Sstever@eecs.umich.edu                          "(*m_%s_ptr)" % param.ident, {}, self)
682810Srdreslin@umich.edu            else:
694672Sstever@eecs.umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
702810Srdreslin@umich.edu                          "m_%s" % param.ident, {}, self)
712810Srdreslin@umich.edu
722810Srdreslin@umich.edu            self.symtab.registerSym(param.ident, var)
732810Srdreslin@umich.edu
742810Srdreslin@umich.edu            if str(param.type_ast.type) == "Prefetcher":
753860Sstever@eecs.umich.edu                self.prefetchers.append(var)
763860Sstever@eecs.umich.edu
772810Srdreslin@umich.edu        self.states = orderdict()
782810Srdreslin@umich.edu        self.events = orderdict()
792810Srdreslin@umich.edu        self.actions = orderdict()
808856Sandreas.hansson@arm.com        self.request_types = orderdict()
818856Sandreas.hansson@arm.com        self.transitions = []
828856Sandreas.hansson@arm.com        self.in_ports = []
838856Sandreas.hansson@arm.com        self.functions = []
848856Sandreas.hansson@arm.com
853738Sstever@eecs.umich.edu        # Data members in the State Machine that have been declared inside
868856Sandreas.hansson@arm.com        # the {} machine.  Note that these along with the config params
873738Sstever@eecs.umich.edu        # form the entire set of data members of the machine.
888856Sandreas.hansson@arm.com        self.objects = []
898856Sandreas.hansson@arm.com        self.TBEType   = None
903738Sstever@eecs.umich.edu        self.EntryType = None
918856Sandreas.hansson@arm.com        self.debug_flags = set()
924478Sstever@eecs.umich.edu        self.debug_flags.add('RubyGenerated')
938975Sandreas.hansson@arm.com        self.debug_flags.add('RubySlicc')
948948Sandreas.hansson@arm.com
958975Sandreas.hansson@arm.com    def __repr__(self):
963738Sstever@eecs.umich.edu        return "[StateMachine: %s]" % self.ident
973738Sstever@eecs.umich.edu
983738Sstever@eecs.umich.edu    def addState(self, state):
993738Sstever@eecs.umich.edu        assert self.table is None
1008856Sandreas.hansson@arm.com        self.states[state.ident] = state
1018856Sandreas.hansson@arm.com
1028856Sandreas.hansson@arm.com    def addEvent(self, event):
1038856Sandreas.hansson@arm.com        assert self.table is None
1049090Sandreas.hansson@arm.com        self.events[event.ident] = event
1058856Sandreas.hansson@arm.com
1068856Sandreas.hansson@arm.com    def addAction(self, action):
1078856Sandreas.hansson@arm.com        assert self.table is None
1088856Sandreas.hansson@arm.com
1098856Sandreas.hansson@arm.com        # Check for duplicate action
1108856Sandreas.hansson@arm.com        for other in self.actions.itervalues():
1113738Sstever@eecs.umich.edu            if action.ident == other.ident:
1123738Sstever@eecs.umich.edu                action.warning("Duplicate action definition: %s" % action.ident)
1138856Sandreas.hansson@arm.com                action.error("Duplicate action definition: %s" % action.ident)
1148914Sandreas.hansson@arm.com            if action.short == other.short:
1158914Sandreas.hansson@arm.com                other.warning("Duplicate action shorthand: %s" % other.ident)
1168914Sandreas.hansson@arm.com                other.warning("    shorthand = %s" % other.short)
1178914Sandreas.hansson@arm.com                action.warning("Duplicate action shorthand: %s" % action.ident)
1188914Sandreas.hansson@arm.com                action.error("    shorthand = %s" % action.short)
1198975Sandreas.hansson@arm.com
1208914Sandreas.hansson@arm.com        self.actions[action.ident] = action
1218914Sandreas.hansson@arm.com
1228914Sandreas.hansson@arm.com    def addDebugFlag(self, flag):
1238914Sandreas.hansson@arm.com        self.debug_flags.add(flag)
1248914Sandreas.hansson@arm.com
1258914Sandreas.hansson@arm.com    def addRequestType(self, request_type):
1268914Sandreas.hansson@arm.com        assert self.table is None
1278914Sandreas.hansson@arm.com        self.request_types[request_type.ident] = request_type
1288975Sandreas.hansson@arm.com
1298914Sandreas.hansson@arm.com    def addTransition(self, trans):
1308975Sandreas.hansson@arm.com        assert self.table is None
1318914Sandreas.hansson@arm.com        self.transitions.append(trans)
1328914Sandreas.hansson@arm.com
1338914Sandreas.hansson@arm.com    def addInPort(self, var):
1348914Sandreas.hansson@arm.com        self.in_ports.append(var)
1358914Sandreas.hansson@arm.com
1368914Sandreas.hansson@arm.com    def addFunc(self, func):
1378914Sandreas.hansson@arm.com        # register func in the symbol table
1388914Sandreas.hansson@arm.com        self.symtab.registerSym(str(func), func)
1398914Sandreas.hansson@arm.com        self.functions.append(func)
1408914Sandreas.hansson@arm.com
1418914Sandreas.hansson@arm.com    def addObject(self, obj):
1428856Sandreas.hansson@arm.com        self.symtab.registerSym(str(obj), obj)
1438856Sandreas.hansson@arm.com        self.objects.append(obj)
1448856Sandreas.hansson@arm.com
1458856Sandreas.hansson@arm.com    def addType(self, type):
1463738Sstever@eecs.umich.edu        type_ident = '%s' % type.c_ident
1478856Sandreas.hansson@arm.com
1483738Sstever@eecs.umich.edu        if type_ident == "%s_TBE" %self.ident:
1498914Sandreas.hansson@arm.com            if self.TBEType != None:
1508914Sandreas.hansson@arm.com                self.error("Multiple Transaction Buffer types in a " \
1518914Sandreas.hansson@arm.com                           "single machine.");
1528856Sandreas.hansson@arm.com            self.TBEType = type
1538856Sandreas.hansson@arm.com
1543738Sstever@eecs.umich.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1558856Sandreas.hansson@arm.com            if "main" in type and "false" == type["main"].lower():
1564478Sstever@eecs.umich.edu                pass # this isn't the EntryType
1578975Sandreas.hansson@arm.com            else:
1588948Sandreas.hansson@arm.com                if self.EntryType != None:
1598975Sandreas.hansson@arm.com                    self.error("Multiple AbstractCacheEntry types in a " \
1603738Sstever@eecs.umich.edu                               "single machine.");
1618948Sandreas.hansson@arm.com                self.EntryType = type
1623738Sstever@eecs.umich.edu
1638948Sandreas.hansson@arm.com    # Needs to be called before accessing the table
1644458Sstever@eecs.umich.edu    def buildTable(self):
1658856Sandreas.hansson@arm.com        assert self.table is None
1668856Sandreas.hansson@arm.com
1678856Sandreas.hansson@arm.com        table = {}
1688856Sandreas.hansson@arm.com
1698856Sandreas.hansson@arm.com        for trans in self.transitions:
1708856Sandreas.hansson@arm.com            # Track which actions we touch so we know if we use them
1718856Sandreas.hansson@arm.com            # all -- really this should be done for all symbols as
1723738Sstever@eecs.umich.edu            # part of the symbol table, then only trigger it for
1733738Sstever@eecs.umich.edu            # Actions, States, Events, etc.
1742810Srdreslin@umich.edu
1752810Srdreslin@umich.edu            for action in trans.actions:
1764626Sstever@eecs.umich.edu                action.used = True
1772810Srdreslin@umich.edu
1783861Sstever@eecs.umich.edu            index = (trans.state, trans.event)
1792810Srdreslin@umich.edu            if index in table:
1804671Sstever@eecs.umich.edu                table[index].warning("Duplicate transition: %s" % table[index])
1814671Sstever@eecs.umich.edu                trans.error("Duplicate transition: %s" % trans)
1824671Sstever@eecs.umich.edu            table[index] = trans
1832810Srdreslin@umich.edu
1845707Shsul@eecs.umich.edu        # Look at all actions to make sure we used them all
1853860Sstever@eecs.umich.edu        for action in self.actions.itervalues():
1863860Sstever@eecs.umich.edu            if not action.used:
1873860Sstever@eecs.umich.edu                error_msg = "Unused action: %s" % action.ident
1885875Ssteve.reinhardt@amd.com                if "desc" in action:
1895875Ssteve.reinhardt@amd.com                    error_msg += ", "  + action.desc
1905875Ssteve.reinhardt@amd.com                action.warning(error_msg)
1915875Ssteve.reinhardt@amd.com        self.table = table
1923860Sstever@eecs.umich.edu
1933860Sstever@eecs.umich.edu    # determine the port->msg buffer mappings
1949063SAli.Saidi@ARM.com    def getBufferMaps(self, ident):
1959063SAli.Saidi@ARM.com        msg_bufs = []
1969063SAli.Saidi@ARM.com        port_to_buf_map = {}
1979063SAli.Saidi@ARM.com        in_msg_bufs = {}
1989063SAli.Saidi@ARM.com        for port in self.in_ports:
1999063SAli.Saidi@ARM.com            buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name
2009063SAli.Saidi@ARM.com            msg_bufs.append(buf_name)
2013860Sstever@eecs.umich.edu            port_to_buf_map[port] = msg_bufs.index(buf_name)
2023860Sstever@eecs.umich.edu            if buf_name not in in_msg_bufs:
2033860Sstever@eecs.umich.edu                in_msg_bufs[buf_name] = [port]
2043860Sstever@eecs.umich.edu            else:
2053860Sstever@eecs.umich.edu                in_msg_bufs[buf_name].append(port)
2065707Shsul@eecs.umich.edu        return port_to_buf_map, in_msg_bufs, msg_bufs
2073860Sstever@eecs.umich.edu
2085388Sstever@gmail.com    def writeCodeFiles(self, path, includes):
2095388Sstever@gmail.com        self.printControllerPython(path)
2104219Srdreslin@umich.edu        self.printControllerHH(path)
2114219Srdreslin@umich.edu        self.printControllerCC(path, includes)
2124219Srdreslin@umich.edu        self.printCSwitch(path)
2134219Srdreslin@umich.edu        self.printCWakeup(path, includes)
2144626Sstever@eecs.umich.edu
2153860Sstever@eecs.umich.edu    def printControllerPython(self, path):
2163860Sstever@eecs.umich.edu        code = self.symtab.codeFormatter()
2175350Sstever@gmail.com        ident = self.ident
2185350Sstever@gmail.com
2195350Sstever@gmail.com        py_ident = "%s_Controller" % ident
2205350Sstever@gmail.com        c_ident = "%s_Controller" % self.ident
2215350Sstever@gmail.com
2225350Sstever@gmail.com        code('''
2235350Sstever@gmail.comfrom m5.params import *
2245350Sstever@gmail.comfrom m5.SimObject import SimObject
2253860Sstever@eecs.umich.edufrom Controller import RubyController
2263860Sstever@eecs.umich.edu
2273860Sstever@eecs.umich.educlass $py_ident(RubyController):
2284626Sstever@eecs.umich.edu    type = '$py_ident'
2293860Sstever@eecs.umich.edu    cxx_header = 'mem/protocol/${c_ident}.hh'
2303860Sstever@eecs.umich.edu''')
2313860Sstever@eecs.umich.edu        code.indent()
2323860Sstever@eecs.umich.edu        for param in self.config_parameters:
2334626Sstever@eecs.umich.edu            dflt_str = ''
2344626Sstever@eecs.umich.edu
2353860Sstever@eecs.umich.edu            if param.rvalue is not None:
2367667Ssteve.reinhardt@amd.com                dflt_str = str(param.rvalue.inline()) + ', '
2377667Ssteve.reinhardt@amd.com
2387667Ssteve.reinhardt@amd.com            if python_class_map.has_key(param.type_ast.type.c_ident):
2394628Sstever@eecs.umich.edu                python_type = python_class_map[param.type_ast.type.c_ident]
2404626Sstever@eecs.umich.edu                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
2414670Sstever@eecs.umich.edu
2425319Sstever@gmail.com            else:
2433860Sstever@eecs.umich.edu                self.error("Unknown c++ to python class conversion for c++ " \
2443860Sstever@eecs.umich.edu                           "type: '%s'. Please update the python_class_map " \
2453860Sstever@eecs.umich.edu                           "in StateMachine.py", param.type_ast.type.c_ident)
2463860Sstever@eecs.umich.edu
2473860Sstever@eecs.umich.edu        code.dedent()
2483860Sstever@eecs.umich.edu        code.write(path, '%s.py' % py_ident)
2494670Sstever@eecs.umich.edu
2505319Sstever@gmail.com
2513860Sstever@eecs.umich.edu    def printControllerHH(self, path):
2523860Sstever@eecs.umich.edu        '''Output the method declarations for the class declaration'''
2533860Sstever@eecs.umich.edu        code = self.symtab.codeFormatter()
2543860Sstever@eecs.umich.edu        ident = self.ident
2553860Sstever@eecs.umich.edu        c_ident = "%s_Controller" % self.ident
2563860Sstever@eecs.umich.edu
2573860Sstever@eecs.umich.edu        code('''
2583860Sstever@eecs.umich.edu/** \\file $c_ident.hh
2592810Srdreslin@umich.edu *
2602810Srdreslin@umich.edu * Auto generated C++ code started by $__file__:$__line__
2618831Smrinmoy.ghosh@arm.com * Created by slicc definition of Module "${{self.short}}"
2622810Srdreslin@umich.edu */
2632810Srdreslin@umich.edu
2642810Srdreslin@umich.edu#ifndef __${ident}_CONTROLLER_HH__
2652810Srdreslin@umich.edu#define __${ident}_CONTROLLER_HH__
2662810Srdreslin@umich.edu
2672982Sstever@eecs.umich.edu#include <iostream>
2682810Srdreslin@umich.edu#include <sstream>
2692810Srdreslin@umich.edu#include <string>
2704626Sstever@eecs.umich.edu
2712810Srdreslin@umich.edu#include "mem/protocol/TransitionResult.hh"
2722810Srdreslin@umich.edu#include "mem/protocol/Types.hh"
2734626Sstever@eecs.umich.edu#include "mem/ruby/common/Consumer.hh"
2744626Sstever@eecs.umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
2754626Sstever@eecs.umich.edu#include "params/$c_ident.hh"
2762810Srdreslin@umich.edu
2774626Sstever@eecs.umich.edu''')
2782810Srdreslin@umich.edu
2792810Srdreslin@umich.edu        seen_types = set()
2804626Sstever@eecs.umich.edu        for var in self.objects:
2814626Sstever@eecs.umich.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
2828702Sandreas.hansson@arm.com                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2832810Srdreslin@umich.edu                seen_types.add(var.type.ident)
2848702Sandreas.hansson@arm.com
2853293Srdreslin@umich.edu        # for adding information to the protocol debug trace
2863293Srdreslin@umich.edu        code('''
2872810Srdreslin@umich.eduextern std::stringstream ${ident}_transitionComment;
2882982Sstever@eecs.umich.edu
2892810Srdreslin@umich.educlass $c_ident : public AbstractController
2904626Sstever@eecs.umich.edu{
2912810Srdreslin@umich.edu  public:
2922810Srdreslin@umich.edu    typedef ${c_ident}Params Params;
2932810Srdreslin@umich.edu    $c_ident(const Params *p);
2942982Sstever@eecs.umich.edu    static int getNumControllers();
2952810Srdreslin@umich.edu    void init();
2964626Sstever@eecs.umich.edu
2972810Srdreslin@umich.edu    MessageBuffer *getMandatoryQueue() const;
2984626Sstever@eecs.umich.edu    MessageBuffer *getMemoryQueue() const;
2994626Sstever@eecs.umich.edu    void initNetQueues();
3004626Sstever@eecs.umich.edu
3014626Sstever@eecs.umich.edu    void print(std::ostream& out) const;
3024626Sstever@eecs.umich.edu    void wakeup();
3034626Sstever@eecs.umich.edu    void resetStats();
3044626Sstever@eecs.umich.edu    void regStats();
3052810Srdreslin@umich.edu    void collateStats();
3062810Srdreslin@umich.edu
3072982Sstever@eecs.umich.edu    void recordCacheTrace(int cntrl, CacheRecorder* tr);
3082810Srdreslin@umich.edu    Sequencer* getSequencer() const;
3092982Sstever@eecs.umich.edu
3102810Srdreslin@umich.edu    int functionalWriteBuffers(PacketPtr&);
3114626Sstever@eecs.umich.edu
3124626Sstever@eecs.umich.edu    void countTransition(${ident}_State state, ${ident}_Event event);
3134626Sstever@eecs.umich.edu    void possibleTransition(${ident}_State state, ${ident}_Event event);
3145365Sstever@gmail.com    uint64_t getEventCount(${ident}_Event event);
3155365Sstever@gmail.com    bool isPossible(${ident}_State state, ${ident}_Event event);
3165365Sstever@gmail.com    uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event);
3175365Sstever@gmail.com
3185365Sstever@gmail.comprivate:
3195365Sstever@gmail.com''')
3205365Sstever@gmail.com
3215365Sstever@gmail.com        code.indent()
3225365Sstever@gmail.com        # added by SS
3234626Sstever@eecs.umich.edu        for param in self.config_parameters:
3244628Sstever@eecs.umich.edu            if param.pointer:
3254628Sstever@eecs.umich.edu                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
3265365Sstever@gmail.com            else:
3275365Sstever@gmail.com                code('${{param.type_ast.type}} m_${{param.ident}};')
3285365Sstever@gmail.com
3295365Sstever@gmail.com        code('''
3305365Sstever@gmail.comTransitionResult doTransition(${ident}_Event event,
3315365Sstever@gmail.com''')
3325365Sstever@gmail.com
3334626Sstever@eecs.umich.edu        if self.EntryType != None:
3345365Sstever@gmail.com            code('''
3355365Sstever@gmail.com                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
3365365Sstever@gmail.com''')
3375365Sstever@gmail.com        if self.TBEType != None:
3385365Sstever@gmail.com            code('''
3395365Sstever@gmail.com                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
3404628Sstever@eecs.umich.edu''')
3414626Sstever@eecs.umich.edu
3424626Sstever@eecs.umich.edu        code('''
3434626Sstever@eecs.umich.edu                              Addr addr);
3444626Sstever@eecs.umich.edu
3454626Sstever@eecs.umich.eduTransitionResult doTransitionWorker(${ident}_Event event,
3464626Sstever@eecs.umich.edu                                    ${ident}_State state,
3474626Sstever@eecs.umich.edu                                    ${ident}_State& next_state,
3487667Ssteve.reinhardt@amd.com''')
3494626Sstever@eecs.umich.edu
3504626Sstever@eecs.umich.edu        if self.TBEType != None:
3514626Sstever@eecs.umich.edu            code('''
3524626Sstever@eecs.umich.edu                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
3534626Sstever@eecs.umich.edu''')
3542810Srdreslin@umich.edu        if self.EntryType != None:
3554626Sstever@eecs.umich.edu            code('''
3562810Srdreslin@umich.edu                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
3572810Srdreslin@umich.edu''')
3584626Sstever@eecs.umich.edu
3594626Sstever@eecs.umich.edu        code('''
3602810Srdreslin@umich.edu                                    Addr addr);
3612810Srdreslin@umich.edu
3623861Sstever@eecs.umich.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
3633861Sstever@eecs.umich.eduint m_event_counters[${ident}_Event_NUM];
3643861Sstever@eecs.umich.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
3653861Sstever@eecs.umich.edu
3663861Sstever@eecs.umich.edustatic std::vector<Stats::Vector *> eventVec;
3674626Sstever@eecs.umich.edustatic std::vector<std::vector<Stats::Vector *> > transVec;
3683861Sstever@eecs.umich.edustatic int m_num_controllers;
3695875Ssteve.reinhardt@amd.com
3705875Ssteve.reinhardt@amd.com// Internal functions
3715875Ssteve.reinhardt@amd.com''')
3725875Ssteve.reinhardt@amd.com
3735875Ssteve.reinhardt@amd.com        for func in self.functions:
3748985SAli.Saidi@ARM.com            proto = func.prototype
3758985SAli.Saidi@ARM.com            if proto:
3768985SAli.Saidi@ARM.com                code('$proto')
3778985SAli.Saidi@ARM.com
3788985SAli.Saidi@ARM.com        if self.EntryType != None:
3798985SAli.Saidi@ARM.com            code('''
3802810Srdreslin@umich.edu
3812810Srdreslin@umich.edu// Set and Reset for cache_entry variable
3822810Srdreslin@umich.eduvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
383void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
384''')
385
386        if self.TBEType != None:
387            code('''
388
389// Set and Reset for tbe variable
390void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
391void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
392''')
393
394        # Prototype the actions that the controller can take
395        code('''
396
397// Actions
398''')
399        if self.TBEType != None and self.EntryType != None:
400            for action in self.actions.itervalues():
401                code('/** \\brief ${{action.desc}} */')
402                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
403                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
404                     'm_cache_entry_ptr, Addr addr);')
405        elif self.TBEType != None:
406            for action in self.actions.itervalues():
407                code('/** \\brief ${{action.desc}} */')
408                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
409                     'm_tbe_ptr, Addr addr);')
410        elif self.EntryType != None:
411            for action in self.actions.itervalues():
412                code('/** \\brief ${{action.desc}} */')
413                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
414                     'm_cache_entry_ptr, Addr addr);')
415        else:
416            for action in self.actions.itervalues():
417                code('/** \\brief ${{action.desc}} */')
418                code('void ${{action.ident}}(Addr addr);')
419
420        # the controller internal variables
421        code('''
422
423// Objects
424''')
425        for var in self.objects:
426            th = var.get("template", "")
427            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
428
429        code.dedent()
430        code('};')
431        code('#endif // __${ident}_CONTROLLER_H__')
432        code.write(path, '%s.hh' % c_ident)
433
434    def printControllerCC(self, path, includes):
435        '''Output the actions for performing the actions'''
436
437        code = self.symtab.codeFormatter()
438        ident = self.ident
439        c_ident = "%s_Controller" % self.ident
440
441        code('''
442/** \\file $c_ident.cc
443 *
444 * Auto generated C++ code started by $__file__:$__line__
445 * Created by slicc definition of Module "${{self.short}}"
446 */
447
448#include <sys/types.h>
449#include <unistd.h>
450
451#include <cassert>
452#include <sstream>
453#include <string>
454#include <typeinfo>
455
456#include "base/compiler.hh"
457#include "base/cprintf.hh"
458
459''')
460        for f in self.debug_flags:
461            code('#include "debug/${{f}}.hh"')
462        code('''
463#include "mem/protocol/${ident}_Controller.hh"
464#include "mem/protocol/${ident}_Event.hh"
465#include "mem/protocol/${ident}_State.hh"
466#include "mem/protocol/Types.hh"
467#include "mem/ruby/system/RubySystem.hh"
468
469''')
470        for include_path in includes:
471            code('#include "${{include_path}}"')
472
473        code('''
474
475using namespace std;
476''')
477
478        # include object classes
479        seen_types = set()
480        for var in self.objects:
481            if var.type.ident not in seen_types and not var.type.isPrimitive:
482                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
483            seen_types.add(var.type.ident)
484
485        num_in_ports = len(self.in_ports)
486
487        code('''
488$c_ident *
489${c_ident}Params::create()
490{
491    return new $c_ident(this);
492}
493
494int $c_ident::m_num_controllers = 0;
495std::vector<Stats::Vector *>  $c_ident::eventVec;
496std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
497
498// for adding information to the protocol debug trace
499stringstream ${ident}_transitionComment;
500
501#ifndef NDEBUG
502#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
503#else
504#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
505#endif
506
507/** \\brief constructor */
508$c_ident::$c_ident(const Params *p)
509    : AbstractController(p)
510{
511    m_machineID.type = MachineType_${ident};
512    m_machineID.num = m_version;
513    m_num_controllers++;
514
515    m_in_ports = $num_in_ports;
516''')
517        code.indent()
518
519        #
520        # After initializing the universal machine parameters, initialize the
521        # this machines config parameters.  Also if these configuration params
522        # include a sequencer, connect the it to the controller.
523        #
524        for param in self.config_parameters:
525            if param.pointer:
526                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
527            else:
528                code('m_${{param.ident}} = p->${{param.ident}};')
529
530            if re.compile("sequencer").search(param.ident):
531                code('m_${{param.ident}}_ptr->setController(this);')
532
533        code('''
534
535for (int state = 0; state < ${ident}_State_NUM; state++) {
536    for (int event = 0; event < ${ident}_Event_NUM; event++) {
537        m_possible[state][event] = false;
538        m_counters[state][event] = 0;
539    }
540}
541for (int event = 0; event < ${ident}_Event_NUM; event++) {
542    m_event_counters[event] = 0;
543}
544''')
545        code.dedent()
546        code('''
547}
548
549void
550$c_ident::initNetQueues()
551{
552    MachineType machine_type = string_to_MachineType("${{self.ident}}");
553    int base M5_VAR_USED = MachineType_base_number(machine_type);
554
555''')
556        code.indent()
557
558        # set for maintaining the vnet, direction pairs already seen for this
559        # machine.  This map helps in implementing the check for avoiding
560        # multiple message buffers being mapped to the same vnet.
561        vnet_dir_set = set()
562
563        for var in self.config_parameters:
564            vid = "m_%s_ptr" % var.ident
565            if "network" in var:
566                vtype = var.type_ast.type
567                code('assert($vid != NULL);')
568
569                # Network port object
570                network = var["network"]
571
572                if "virtual_network" in var:
573                    vnet = var["virtual_network"]
574                    vnet_type = var["vnet_type"]
575
576                    assert (vnet, network) not in vnet_dir_set
577                    vnet_dir_set.add((vnet,network))
578
579                    code('''
580m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet,
581                                 "$vnet_type", $vid);
582''')
583                # Set Priority
584                if "rank" in var:
585                    code('$vid->setPriority(${{var["rank"]}})')
586
587        code.dedent()
588        code('''
589}
590
591void
592$c_ident::init()
593{
594    // initialize objects
595    initNetQueues();
596''')
597
598        code.indent()
599
600        for var in self.objects:
601            vtype = var.type
602            vid = "m_%s_ptr" % var.ident
603            if "network" not in var:
604                # Not a network port object
605                if "primitive" in vtype:
606                    code('$vid = new ${{vtype.c_ident}};')
607                    if "default" in var:
608                        code('(*$vid) = ${{var["default"]}};')
609                else:
610                    # Normal Object
611                    th = var.get("template", "")
612                    expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
613                    args = ""
614                    if "non_obj" not in vtype and not vtype.isEnumeration:
615                        args = var.get("constructor", "")
616
617                    code('$expr($args);')
618                    code('assert($vid != NULL);')
619
620                    if "default" in var:
621                        code('*$vid = ${{var["default"]}}; // Object default')
622                    elif "default" in vtype:
623                        comment = "Type %s default" % vtype.ident
624                        code('*$vid = ${{vtype["default"]}}; // $comment')
625
626        # Set the prefetchers
627        code()
628        for prefetcher in self.prefetchers:
629            code('${{prefetcher.code}}.setController(this);')
630
631        code()
632        for port in self.in_ports:
633            # Set the queue consumers
634            code('${{port.code}}.setConsumer(this);')
635
636        # Initialize the transition profiling
637        code()
638        for trans in self.transitions:
639            # Figure out if we stall
640            stall = False
641            for action in trans.actions:
642                if action.ident == "z_stall":
643                    stall = True
644
645            # Only possible if it is not a 'z' case
646            if not stall:
647                state = "%s_State_%s" % (self.ident, trans.state.ident)
648                event = "%s_Event_%s" % (self.ident, trans.event.ident)
649                code('possibleTransition($state, $event);')
650
651        code.dedent()
652        code('''
653    AbstractController::init();
654    resetStats();
655}
656''')
657
658        mq_ident = "NULL"
659        for port in self.in_ports:
660            if port.code.find("mandatoryQueue_ptr") >= 0:
661                mq_ident = "m_mandatoryQueue_ptr"
662
663        memq_ident = "NULL"
664        for port in self.in_ports:
665            if port.code.find("responseFromMemory_ptr") >= 0:
666                memq_ident = "m_responseFromMemory_ptr"
667
668        seq_ident = "NULL"
669        for param in self.config_parameters:
670            if param.ident == "sequencer":
671                assert(param.pointer)
672                seq_ident = "m_%s_ptr" % param.ident
673
674        code('''
675
676void
677$c_ident::regStats()
678{
679    AbstractController::regStats();
680
681    if (m_version == 0) {
682        for (${ident}_Event event = ${ident}_Event_FIRST;
683             event < ${ident}_Event_NUM; ++event) {
684            Stats::Vector *t = new Stats::Vector();
685            t->init(m_num_controllers);
686            t->name(params()->ruby_system->name() + ".${c_ident}." +
687                ${ident}_Event_to_string(event));
688            t->flags(Stats::pdf | Stats::total | Stats::oneline |
689                     Stats::nozero);
690
691            eventVec.push_back(t);
692        }
693
694        for (${ident}_State state = ${ident}_State_FIRST;
695             state < ${ident}_State_NUM; ++state) {
696
697            transVec.push_back(std::vector<Stats::Vector *>());
698
699            for (${ident}_Event event = ${ident}_Event_FIRST;
700                 event < ${ident}_Event_NUM; ++event) {
701
702                Stats::Vector *t = new Stats::Vector();
703                t->init(m_num_controllers);
704                t->name(params()->ruby_system->name() + ".${c_ident}." +
705                        ${ident}_State_to_string(state) +
706                        "." + ${ident}_Event_to_string(event));
707
708                t->flags(Stats::pdf | Stats::total | Stats::oneline |
709                         Stats::nozero);
710                transVec[state].push_back(t);
711            }
712        }
713    }
714}
715
716void
717$c_ident::collateStats()
718{
719    for (${ident}_Event event = ${ident}_Event_FIRST;
720         event < ${ident}_Event_NUM; ++event) {
721        for (unsigned int i = 0; i < m_num_controllers; ++i) {
722            RubySystem *rs = params()->ruby_system;
723            std::map<uint32_t, AbstractController *>::iterator it =
724                     rs->m_abstract_controls[MachineType_${ident}].find(i);
725            assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
726            (*eventVec[event])[i] =
727                (($c_ident *)(*it).second)->getEventCount(event);
728        }
729    }
730
731    for (${ident}_State state = ${ident}_State_FIRST;
732         state < ${ident}_State_NUM; ++state) {
733
734        for (${ident}_Event event = ${ident}_Event_FIRST;
735             event < ${ident}_Event_NUM; ++event) {
736
737            for (unsigned int i = 0; i < m_num_controllers; ++i) {
738                RubySystem *rs = params()->ruby_system;
739                std::map<uint32_t, AbstractController *>::iterator it =
740                         rs->m_abstract_controls[MachineType_${ident}].find(i);
741                assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
742                (*transVec[state][event])[i] =
743                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
744            }
745        }
746    }
747}
748
749void
750$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
751{
752    assert(m_possible[state][event]);
753    m_counters[state][event]++;
754    m_event_counters[event]++;
755}
756void
757$c_ident::possibleTransition(${ident}_State state,
758                             ${ident}_Event event)
759{
760    m_possible[state][event] = true;
761}
762
763uint64_t
764$c_ident::getEventCount(${ident}_Event event)
765{
766    return m_event_counters[event];
767}
768
769bool
770$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
771{
772    return m_possible[state][event];
773}
774
775uint64_t
776$c_ident::getTransitionCount(${ident}_State state,
777                             ${ident}_Event event)
778{
779    return m_counters[state][event];
780}
781
782int
783$c_ident::getNumControllers()
784{
785    return m_num_controllers;
786}
787
788MessageBuffer*
789$c_ident::getMandatoryQueue() const
790{
791    return $mq_ident;
792}
793
794MessageBuffer*
795$c_ident::getMemoryQueue() const
796{
797    return $memq_ident;
798}
799
800Sequencer*
801$c_ident::getSequencer() const
802{
803    return $seq_ident;
804}
805
806void
807$c_ident::print(ostream& out) const
808{
809    out << "[$c_ident " << m_version << "]";
810}
811
812void $c_ident::resetStats()
813{
814    for (int state = 0; state < ${ident}_State_NUM; state++) {
815        for (int event = 0; event < ${ident}_Event_NUM; event++) {
816            m_counters[state][event] = 0;
817        }
818    }
819
820    for (int event = 0; event < ${ident}_Event_NUM; event++) {
821        m_event_counters[event] = 0;
822    }
823
824    AbstractController::resetStats();
825}
826''')
827
828        if self.EntryType != None:
829            code('''
830
831// Set and Reset for cache_entry variable
832void
833$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
834{
835  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
836}
837
838void
839$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
840{
841  m_cache_entry_ptr = 0;
842}
843''')
844
845        if self.TBEType != None:
846            code('''
847
848// Set and Reset for tbe variable
849void
850$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
851{
852  m_tbe_ptr = m_new_tbe;
853}
854
855void
856$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
857{
858  m_tbe_ptr = NULL;
859}
860''')
861
862        code('''
863
864void
865$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
866{
867''')
868        #
869        # Record cache contents for all associated caches.
870        #
871        code.indent()
872        for param in self.config_parameters:
873            if param.type_ast.type.ident == "CacheMemory":
874                assert(param.pointer)
875                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
876
877        code.dedent()
878        code('''
879}
880
881// Actions
882''')
883        if self.TBEType != None and self.EntryType != None:
884            for action in self.actions.itervalues():
885                if "c_code" not in action:
886                 continue
887
888                code('''
889/** \\brief ${{action.desc}} */
890void
891$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
892{
893    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
894    try {
895       ${{action["c_code"]}}
896    } catch (const RejectException & e) {
897       fatal("Error in action ${{ident}}:${{action.ident}}: "
898             "executed a peek statement with the wrong message "
899             "type specified. ");
900    }
901}
902
903''')
904        elif self.TBEType != None:
905            for action in self.actions.itervalues():
906                if "c_code" not in action:
907                 continue
908
909                code('''
910/** \\brief ${{action.desc}} */
911void
912$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr)
913{
914    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
915    ${{action["c_code"]}}
916}
917
918''')
919        elif self.EntryType != None:
920            for action in self.actions.itervalues():
921                if "c_code" not in action:
922                 continue
923
924                code('''
925/** \\brief ${{action.desc}} */
926void
927$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
928{
929    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
930    ${{action["c_code"]}}
931}
932
933''')
934        else:
935            for action in self.actions.itervalues():
936                if "c_code" not in action:
937                 continue
938
939                code('''
940/** \\brief ${{action.desc}} */
941void
942$c_ident::${{action.ident}}(Addr addr)
943{
944    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
945    ${{action["c_code"]}}
946}
947
948''')
949        for func in self.functions:
950            code(func.generateCode())
951
952        # Function for functional writes to messages buffered in the controller
953        code('''
954int
955$c_ident::functionalWriteBuffers(PacketPtr& pkt)
956{
957    int num_functional_writes = 0;
958''')
959        for var in self.objects:
960            vtype = var.type
961            if vtype.isBuffer:
962                vid = "m_%s_ptr" % var.ident
963                code('num_functional_writes += $vid->functionalWrite(pkt);')
964
965        for var in self.config_parameters:
966            vtype = var.type_ast.type
967            if vtype.isBuffer:
968                vid = "m_%s_ptr" % var.ident
969                code('num_functional_writes += $vid->functionalWrite(pkt);')
970
971        code('''
972    return num_functional_writes;
973}
974''')
975
976        code.write(path, "%s.cc" % c_ident)
977
978    def printCWakeup(self, path, includes):
979        '''Output the wakeup loop for the events'''
980
981        code = self.symtab.codeFormatter()
982        ident = self.ident
983
984        outputRequest_types = True
985        if len(self.request_types) == 0:
986            outputRequest_types = False
987
988        code('''
989// Auto generated C++ code started by $__file__:$__line__
990// ${ident}: ${{self.short}}
991
992#include <sys/types.h>
993#include <unistd.h>
994
995#include <cassert>
996#include <typeinfo>
997
998#include "base/misc.hh"
999
1000''')
1001        for f in self.debug_flags:
1002            code('#include "debug/${{f}}.hh"')
1003        code('''
1004#include "mem/protocol/${ident}_Controller.hh"
1005#include "mem/protocol/${ident}_Event.hh"
1006#include "mem/protocol/${ident}_State.hh"
1007
1008''')
1009
1010        if outputRequest_types:
1011            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1012
1013        code('''
1014#include "mem/protocol/Types.hh"
1015#include "mem/ruby/system/RubySystem.hh"
1016
1017''')
1018
1019
1020        for include_path in includes:
1021            code('#include "${{include_path}}"')
1022
1023        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1024
1025        code('''
1026
1027using namespace std;
1028
1029void
1030${ident}_Controller::wakeup()
1031{
1032    int counter = 0;
1033    while (true) {
1034        unsigned char rejected[${{len(msg_bufs)}}];
1035        memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
1036        // Some cases will put us into an infinite loop without this limit
1037        assert(counter <= m_transitions_per_cycle);
1038        if (counter == m_transitions_per_cycle) {
1039            // Count how often we are fully utilized
1040            m_fully_busy_cycles++;
1041
1042            // Wakeup in another cycle and try again
1043            scheduleEvent(Cycles(1));
1044            break;
1045        }
1046''')
1047
1048        code.indent()
1049        code.indent()
1050
1051        # InPorts
1052        #
1053        for port in self.in_ports:
1054            code.indent()
1055            code('// ${ident}InPort $port')
1056            if port.pairs.has_key("rank"):
1057                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1058            else:
1059                code('m_cur_in_port = 0;')
1060            if port in port_to_buf_map:
1061                code('try {')
1062                code.indent()
1063            code('${{port["c_code_in_port"]}}')
1064
1065            if port in port_to_buf_map:
1066                code.dedent()
1067                code('''
1068            } catch (const RejectException & e) {
1069                rejected[${{port_to_buf_map[port]}}]++;
1070            }
1071''')
1072            code.dedent()
1073            code('')
1074
1075        code.dedent()
1076        code.dedent()
1077        code('''
1078        // If we got this far, we have nothing left todo or something went
1079        // wrong''')
1080        for buf_name, ports in in_msg_bufs.items():
1081            if len(ports) > 1:
1082                # only produce checks when a buffer is shared by multiple ports
1083                code('''
1084        if (${{buf_name}}->isReady() && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
1085        {
1086            // no port claimed the message on the top of this buffer
1087            panic("Runtime Error at Ruby Time: %d. "
1088                  "All ports rejected a message. "
1089                  "You are probably sending a message type to this controller "
1090                  "over a virtual network that do not define an in_port for "
1091                  "the incoming message type.\\n",
1092                  Cycles(1));
1093        }
1094''')
1095        code('''
1096        break;
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/system/RubySystem.hh"
1124
1125#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1126
1127#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1128#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1129
1130TransitionResult
1131${ident}_Controller::doTransition(${ident}_Event event,
1132''')
1133        if self.EntryType != None:
1134            code('''
1135                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1136''')
1137        if self.TBEType != None:
1138            code('''
1139                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1140''')
1141        code('''
1142                                  Addr addr)
1143{
1144''')
1145        code.indent()
1146
1147        if self.TBEType != None and self.EntryType != None:
1148            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1149        elif self.TBEType != None:
1150            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1151        elif self.EntryType != None:
1152            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1153        else:
1154            code('${ident}_State state = getState(addr);')
1155
1156        code('''
1157${ident}_State next_state = state;
1158
1159DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1160        *this, curCycle(), ${ident}_State_to_string(state),
1161        ${ident}_Event_to_string(event), addr);
1162
1163TransitionResult result =
1164''')
1165        if self.TBEType != None and self.EntryType != None:
1166            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1167        elif self.TBEType != None:
1168            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1169        elif self.EntryType != None:
1170            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1171        else:
1172            code('doTransitionWorker(event, state, next_state, addr);')
1173
1174        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1175
1176        code('''
1177
1178if (result == TransitionResult_Valid) {
1179    DPRINTF(RubyGenerated, "next_state: %s\\n",
1180            ${ident}_State_to_string(next_state));
1181    countTransition(state, event);
1182
1183    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n",
1184             curTick(), m_version, "${ident}",
1185             ${ident}_Event_to_string(event),
1186             ${ident}_State_to_string(state),
1187             ${ident}_State_to_string(next_state),
1188             addr, GET_TRANSITION_COMMENT());
1189
1190    CLEAR_TRANSITION_COMMENT();
1191''')
1192        if self.TBEType != None and self.EntryType != None:
1193            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1194            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1195        elif self.TBEType != None:
1196            code('setState(m_tbe_ptr, addr, next_state);')
1197            code('setAccessPermission(addr, next_state);')
1198        elif self.EntryType != None:
1199            code('setState(m_cache_entry_ptr, addr, next_state);')
1200            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1201        else:
1202            code('setState(addr, next_state);')
1203            code('setAccessPermission(addr, next_state);')
1204
1205        code('''
1206} else if (result == TransitionResult_ResourceStall) {
1207    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1208             curTick(), m_version, "${ident}",
1209             ${ident}_Event_to_string(event),
1210             ${ident}_State_to_string(state),
1211             ${ident}_State_to_string(next_state),
1212             addr, "Resource Stall");
1213} else if (result == TransitionResult_ProtocolStall) {
1214    DPRINTF(RubyGenerated, "stalling\\n");
1215    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1216             curTick(), m_version, "${ident}",
1217             ${ident}_Event_to_string(event),
1218             ${ident}_State_to_string(state),
1219             ${ident}_State_to_string(next_state),
1220             addr, "Protocol Stall");
1221}
1222
1223return result;
1224''')
1225        code.dedent()
1226        code('''
1227}
1228
1229TransitionResult
1230${ident}_Controller::doTransitionWorker(${ident}_Event event,
1231                                        ${ident}_State state,
1232                                        ${ident}_State& next_state,
1233''')
1234
1235        if self.TBEType != None:
1236            code('''
1237                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1238''')
1239        if self.EntryType != None:
1240                  code('''
1241                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1242''')
1243        code('''
1244                                        Addr addr)
1245{
1246    switch(HASH_FUN(state, event)) {
1247''')
1248
1249        # This map will allow suppress generating duplicate code
1250        cases = orderdict()
1251
1252        for trans in self.transitions:
1253            case_string = "%s_State_%s, %s_Event_%s" % \
1254                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1255
1256            case = self.symtab.codeFormatter()
1257            # Only set next_state if it changes
1258            if trans.state != trans.nextState:
1259                if trans.nextState.isWildcard():
1260                    # When * is encountered as an end state of a transition,
1261                    # the next state is determined by calling the
1262                    # machine-specific getNextState function. The next state
1263                    # is determined before any actions of the transition
1264                    # execute, and therefore the next state calculation cannot
1265                    # depend on any of the transitionactions.
1266                    case('next_state = getNextState(addr);')
1267                else:
1268                    ns_ident = trans.nextState.ident
1269                    case('next_state = ${ident}_State_${ns_ident};')
1270
1271            actions = trans.actions
1272            request_types = trans.request_types
1273
1274            # Check for resources
1275            case_sorter = []
1276            res = trans.resources
1277            for key,val in res.iteritems():
1278                val = '''
1279if (!%s.areNSlotsAvailable(%s, clockEdge()))
1280    return TransitionResult_ResourceStall;
1281''' % (key.code, val)
1282                case_sorter.append(val)
1283
1284            # Check all of the request_types for resource constraints
1285            for request_type in request_types:
1286                val = '''
1287if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1288    return TransitionResult_ResourceStall;
1289}
1290''' % (self.ident, request_type.ident)
1291                case_sorter.append(val)
1292
1293            # Emit the code sequences in a sorted order.  This makes the
1294            # output deterministic (without this the output order can vary
1295            # since Map's keys() on a vector of pointers is not deterministic
1296            for c in sorted(case_sorter):
1297                case("$c")
1298
1299            # Record access types for this transition
1300            for request_type in request_types:
1301                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1302
1303            # Figure out if we stall
1304            stall = False
1305            for action in actions:
1306                if action.ident == "z_stall":
1307                    stall = True
1308                    break
1309
1310            if stall:
1311                case('return TransitionResult_ProtocolStall;')
1312            else:
1313                if self.TBEType != None and self.EntryType != None:
1314                    for action in actions:
1315                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1316                elif self.TBEType != None:
1317                    for action in actions:
1318                        case('${{action.ident}}(m_tbe_ptr, addr);')
1319                elif self.EntryType != None:
1320                    for action in actions:
1321                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1322                else:
1323                    for action in actions:
1324                        case('${{action.ident}}(addr);')
1325                case('return TransitionResult_Valid;')
1326
1327            case = str(case)
1328
1329            # Look to see if this transition code is unique.
1330            if case not in cases:
1331                cases[case] = []
1332
1333            cases[case].append(case_string)
1334
1335        # Walk through all of the unique code blocks and spit out the
1336        # corresponding case statement elements
1337        for case,transitions in cases.iteritems():
1338            # Iterative over all the multiple transitions that share
1339            # the same code
1340            for trans in transitions:
1341                code('  case HASH_FUN($trans):')
1342            code('    $case\n')
1343
1344        code('''
1345      default:
1346        panic("Invalid transition\\n"
1347              "%s time: %d addr: %s event: %s state: %s\\n",
1348              name(), curCycle(), addr, event, state);
1349    }
1350
1351    return TransitionResult_Valid;
1352}
1353''')
1354        code.write(path, "%s_Transitions.cc" % self.ident)
1355
1356
1357    # **************************
1358    # ******* HTML Files *******
1359    # **************************
1360    def frameRef(self, click_href, click_target, over_href, over_num, text):
1361        code = self.symtab.codeFormatter(fix_newlines=False)
1362        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1363    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1364        parent.frames[$over_num].location='$over_href'
1365    }\">
1366    ${{html.formatShorthand(text)}}
1367    </A>""")
1368        return str(code)
1369
1370    def writeHTMLFiles(self, path):
1371        # Create table with no row hilighted
1372        self.printHTMLTransitions(path, None)
1373
1374        # Generate transition tables
1375        for state in self.states.itervalues():
1376            self.printHTMLTransitions(path, state)
1377
1378        # Generate action descriptions
1379        for action in self.actions.itervalues():
1380            name = "%s_action_%s.html" % (self.ident, action.ident)
1381            code = html.createSymbol(action, "Action")
1382            code.write(path, name)
1383
1384        # Generate state descriptions
1385        for state in self.states.itervalues():
1386            name = "%s_State_%s.html" % (self.ident, state.ident)
1387            code = html.createSymbol(state, "State")
1388            code.write(path, name)
1389
1390        # Generate event descriptions
1391        for event in self.events.itervalues():
1392            name = "%s_Event_%s.html" % (self.ident, event.ident)
1393            code = html.createSymbol(event, "Event")
1394            code.write(path, name)
1395
1396    def printHTMLTransitions(self, path, active_state):
1397        code = self.symtab.codeFormatter()
1398
1399        code('''
1400<HTML>
1401<BODY link="blue" vlink="blue">
1402
1403<H1 align="center">${{html.formatShorthand(self.short)}}:
1404''')
1405        code.indent()
1406        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1407            mid = machine.ident
1408            if i != 0:
1409                extra = " - "
1410            else:
1411                extra = ""
1412            if machine == self:
1413                code('$extra$mid')
1414            else:
1415                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1416        code.dedent()
1417
1418        code("""
1419</H1>
1420
1421<TABLE border=1>
1422<TR>
1423  <TH> </TH>
1424""")
1425
1426        for event in self.events.itervalues():
1427            href = "%s_Event_%s.html" % (self.ident, event.ident)
1428            ref = self.frameRef(href, "Status", href, "1", event.short)
1429            code('<TH bgcolor=white>$ref</TH>')
1430
1431        code('</TR>')
1432        # -- Body of table
1433        for state in self.states.itervalues():
1434            # -- Each row
1435            if state == active_state:
1436                color = "yellow"
1437            else:
1438                color = "white"
1439
1440            click = "%s_table_%s.html" % (self.ident, state.ident)
1441            over = "%s_State_%s.html" % (self.ident, state.ident)
1442            text = html.formatShorthand(state.short)
1443            ref = self.frameRef(click, "Table", over, "1", state.short)
1444            code('''
1445<TR>
1446  <TH bgcolor=$color>$ref</TH>
1447''')
1448
1449            # -- One column for each event
1450            for event in self.events.itervalues():
1451                trans = self.table.get((state,event), None)
1452                if trans is None:
1453                    # This is the no transition case
1454                    if state == active_state:
1455                        color = "#C0C000"
1456                    else:
1457                        color = "lightgrey"
1458
1459                    code('<TD bgcolor=$color>&nbsp;</TD>')
1460                    continue
1461
1462                next = trans.nextState
1463                stall_action = False
1464
1465                # -- Get the actions
1466                for action in trans.actions:
1467                    if action.ident == "z_stall" or \
1468                       action.ident == "zz_recycleMandatoryQueue":
1469                        stall_action = True
1470
1471                # -- Print out "actions/next-state"
1472                if stall_action:
1473                    if state == active_state:
1474                        color = "#C0C000"
1475                    else:
1476                        color = "lightgrey"
1477
1478                elif active_state and next.ident == active_state.ident:
1479                    color = "aqua"
1480                elif state == active_state:
1481                    color = "yellow"
1482                else:
1483                    color = "white"
1484
1485                code('<TD bgcolor=$color>')
1486                for action in trans.actions:
1487                    href = "%s_action_%s.html" % (self.ident, action.ident)
1488                    ref = self.frameRef(href, "Status", href, "1",
1489                                        action.short)
1490                    code('  $ref')
1491                if next != state:
1492                    if trans.actions:
1493                        code('/')
1494                    click = "%s_table_%s.html" % (self.ident, next.ident)
1495                    over = "%s_State_%s.html" % (self.ident, next.ident)
1496                    ref = self.frameRef(click, "Table", over, "1", next.short)
1497                    code("$ref")
1498                code("</TD>")
1499
1500            # -- Each row
1501            if state == active_state:
1502                color = "yellow"
1503            else:
1504                color = "white"
1505
1506            click = "%s_table_%s.html" % (self.ident, state.ident)
1507            over = "%s_State_%s.html" % (self.ident, state.ident)
1508            ref = self.frameRef(click, "Table", over, "1", state.short)
1509            code('''
1510  <TH bgcolor=$color>$ref</TH>
1511</TR>
1512''')
1513        code('''
1514<!- Column footer->
1515<TR>
1516  <TH> </TH>
1517''')
1518
1519        for event in self.events.itervalues():
1520            href = "%s_Event_%s.html" % (self.ident, event.ident)
1521            ref = self.frameRef(href, "Status", href, "1", event.short)
1522            code('<TH bgcolor=white>$ref</TH>')
1523        code('''
1524</TR>
1525</TABLE>
1526</BODY></HTML>
1527''')
1528
1529
1530        if active_state:
1531            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1532        else:
1533            name = "%s_table.html" % self.ident
1534        code.write(path, name)
1535
1536__all__ = [ "StateMachine" ]
1537