StateMachine.py revision 10919
12292SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
22292SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company
32292SN/A# All rights reserved.
42292SN/A#
52292SN/A# Redistribution and use in source and binary forms, with or without
62292SN/A# modification, are permitted provided that the following conditions are
72292SN/A# met: redistributions of source code must retain the above copyright
82292SN/A# notice, this list of conditions and the following disclaimer;
92292SN/A# redistributions in binary form must reproduce the above copyright
102292SN/A# notice, this list of conditions and the following disclaimer in the
112292SN/A# documentation and/or other materials provided with the distribution;
122292SN/A# neither the name of the copyright holders nor the names of its
132292SN/A# contributors may be used to endorse or promote products derived from
142292SN/A# this software without specific prior written permission.
152292SN/A#
162292SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272689Sktlim@umich.edu
282689Sktlim@umich.edufrom m5.util import orderdict
292689Sktlim@umich.edu
302292SN/Afrom slicc.symbols.Symbol import Symbol
312292SN/Afrom slicc.symbols.Var import Var
322316SN/Aimport slicc.generate.html as html
332292SN/Aimport re
342292SN/A
352669Sktlim@umich.edupython_class_map = {
362292SN/A                    "int": "Int",
372669Sktlim@umich.edu                    "uint32_t" : "UInt32",
382678Sktlim@umich.edu                    "std::string": "String",
392678Sktlim@umich.edu                    "bool": "Bool",
402678Sktlim@umich.edu                    "CacheMemory": "RubyCache",
412292SN/A                    "WireBuffer": "RubyWireBuffer",
422678Sktlim@umich.edu                    "Sequencer": "RubySequencer",
432292SN/A                    "DirectoryMemory": "RubyDirectoryMemory",
442292SN/A                    "MemoryControl": "MemoryControl",
452669Sktlim@umich.edu                    "DMASequencer": "DMASequencer",
462292SN/A                    "Prefetcher":"Prefetcher",
472678Sktlim@umich.edu                    "Cycles":"Cycles",
482292SN/A                   }
492678Sktlim@umich.edu
502678Sktlim@umich.educlass StateMachine(Symbol):
512678Sktlim@umich.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
522678Sktlim@umich.edu        super(StateMachine, self).__init__(symtab, ident, location, pairs)
532678Sktlim@umich.edu        self.table = None
542292SN/A
552678Sktlim@umich.edu        # Data members in the State Machine that have been declared before
562678Sktlim@umich.edu        # the opening brace '{'  of the machine.  Note that these along with
572678Sktlim@umich.edu        # the members in self.objects form the entire set of data members.
582678Sktlim@umich.edu        self.config_parameters = config_parameters
592678Sktlim@umich.edu
602678Sktlim@umich.edu        self.prefetchers = []
612292SN/A
622678Sktlim@umich.edu        for param in config_parameters:
632678Sktlim@umich.edu            if param.pointer:
642678Sktlim@umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
652678Sktlim@umich.edu                          "(*m_%s_ptr)" % param.ident, {}, self)
662678Sktlim@umich.edu            else:
672678Sktlim@umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
682678Sktlim@umich.edu                          "m_%s" % param.ident, {}, self)
692678Sktlim@umich.edu
702344SN/A            self.symtab.registerSym(param.ident, var)
712678Sktlim@umich.edu
722678Sktlim@umich.edu            if str(param.type_ast.type) == "Prefetcher":
732678Sktlim@umich.edu                self.prefetchers.append(var)
742678Sktlim@umich.edu
752678Sktlim@umich.edu        self.states = orderdict()
762307SN/A        self.events = orderdict()
772678Sktlim@umich.edu        self.actions = orderdict()
782678Sktlim@umich.edu        self.request_types = orderdict()
792678Sktlim@umich.edu        self.transitions = []
802678Sktlim@umich.edu        self.in_ports = []
812678Sktlim@umich.edu        self.functions = []
822678Sktlim@umich.edu
832678Sktlim@umich.edu        # Data members in the State Machine that have been declared inside
842678Sktlim@umich.edu        # the {} machine.  Note that these along with the config params
852344SN/A        # form the entire set of data members of the machine.
862307SN/A        self.objects = []
872678Sktlim@umich.edu        self.TBEType   = None
882678Sktlim@umich.edu        self.EntryType = None
892292SN/A
902292SN/A    def __repr__(self):
912292SN/A        return "[StateMachine: %s]" % self.ident
922669Sktlim@umich.edu
932669Sktlim@umich.edu    def addState(self, state):
942292SN/A        assert self.table is None
952669Sktlim@umich.edu        self.states[state.ident] = state
962669Sktlim@umich.edu
972669Sktlim@umich.edu    def addEvent(self, event):
982669Sktlim@umich.edu        assert self.table is None
992669Sktlim@umich.edu        self.events[event.ident] = event
1002669Sktlim@umich.edu
1012669Sktlim@umich.edu    def addAction(self, action):
1022669Sktlim@umich.edu        assert self.table is None
1032669Sktlim@umich.edu
1042669Sktlim@umich.edu        # Check for duplicate action
1052669Sktlim@umich.edu        for other in self.actions.itervalues():
1062669Sktlim@umich.edu            if action.ident == other.ident:
1072669Sktlim@umich.edu                action.warning("Duplicate action definition: %s" % action.ident)
1082669Sktlim@umich.edu                action.error("Duplicate action definition: %s" % action.ident)
1092669Sktlim@umich.edu            if action.short == other.short:
1102669Sktlim@umich.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
1112669Sktlim@umich.edu                other.warning("    shorthand = %s" % other.short)
1122669Sktlim@umich.edu                action.warning("Duplicate action shorthand: %s" % action.ident)
1132669Sktlim@umich.edu                action.error("    shorthand = %s" % action.short)
1142669Sktlim@umich.edu
1152669Sktlim@umich.edu        self.actions[action.ident] = action
1162669Sktlim@umich.edu
1172669Sktlim@umich.edu    def addRequestType(self, request_type):
1182669Sktlim@umich.edu        assert self.table is None
1192669Sktlim@umich.edu        self.request_types[request_type.ident] = request_type
1202669Sktlim@umich.edu
1212669Sktlim@umich.edu    def addTransition(self, trans):
1222669Sktlim@umich.edu        assert self.table is None
1232669Sktlim@umich.edu        self.transitions.append(trans)
1242669Sktlim@umich.edu
1252669Sktlim@umich.edu    def addInPort(self, var):
1262669Sktlim@umich.edu        self.in_ports.append(var)
1272669Sktlim@umich.edu
1282669Sktlim@umich.edu    def addFunc(self, func):
1292669Sktlim@umich.edu        # register func in the symbol table
1302669Sktlim@umich.edu        self.symtab.registerSym(str(func), func)
1312669Sktlim@umich.edu        self.functions.append(func)
1322669Sktlim@umich.edu
1332669Sktlim@umich.edu    def addObject(self, obj):
1342669Sktlim@umich.edu        self.symtab.registerSym(str(obj), obj)
1352669Sktlim@umich.edu        self.objects.append(obj)
1362669Sktlim@umich.edu
1372669Sktlim@umich.edu    def addType(self, type):
1382669Sktlim@umich.edu        type_ident = '%s' % type.c_ident
1392669Sktlim@umich.edu
1402292SN/A        if type_ident == "%s_TBE" %self.ident:
1412292SN/A            if self.TBEType != None:
1422292SN/A                self.error("Multiple Transaction Buffer types in a " \
1432292SN/A                           "single machine.");
1442678Sktlim@umich.edu            self.TBEType = type
1452678Sktlim@umich.edu
1462292SN/A        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1472292SN/A            if self.EntryType != None:
1482292SN/A                self.error("Multiple AbstractCacheEntry types in a " \
1492292SN/A                           "single machine.");
1502292SN/A            self.EntryType = type
1512292SN/A
1522292SN/A    # Needs to be called before accessing the table
1532292SN/A    def buildTable(self):
1542292SN/A        assert self.table is None
1552292SN/A
1562292SN/A        table = {}
1572307SN/A
1582307SN/A        for trans in self.transitions:
1592292SN/A            # Track which actions we touch so we know if we use them
1602292SN/A            # all -- really this should be done for all symbols as
1612329SN/A            # part of the symbol table, then only trigger it for
1622329SN/A            # Actions, States, Events, etc.
1632329SN/A
1642292SN/A            for action in trans.actions:
1652292SN/A                action.used = True
1662292SN/A
1672292SN/A            index = (trans.state, trans.event)
1682292SN/A            if index in table:
1692292SN/A                table[index].warning("Duplicate transition: %s" % table[index])
1702292SN/A                trans.error("Duplicate transition: %s" % trans)
1712292SN/A            table[index] = trans
1722292SN/A
1732292SN/A        # Look at all actions to make sure we used them all
1742292SN/A        for action in self.actions.itervalues():
1752678Sktlim@umich.edu            if not action.used:
1762292SN/A                error_msg = "Unused action: %s" % action.ident
1772329SN/A                if "desc" in action:
1782292SN/A                    error_msg += ", "  + action.desc
1792292SN/A                action.warning(error_msg)
1802292SN/A        self.table = table
1812292SN/A
1822292SN/A    def writeCodeFiles(self, path, includes):
1832669Sktlim@umich.edu        self.printControllerPython(path)
1842669Sktlim@umich.edu        self.printControllerHH(path)
1852669Sktlim@umich.edu        self.printControllerCC(path, includes)
1862669Sktlim@umich.edu        self.printCSwitch(path)
1872669Sktlim@umich.edu        self.printCWakeup(path, includes)
1882678Sktlim@umich.edu
1892678Sktlim@umich.edu    def printControllerPython(self, path):
1902678Sktlim@umich.edu        code = self.symtab.codeFormatter()
1912678Sktlim@umich.edu        ident = self.ident
1922679Sktlim@umich.edu
1932679Sktlim@umich.edu        py_ident = "%s_Controller" % ident
1942679Sktlim@umich.edu        c_ident = "%s_Controller" % self.ident
1952679Sktlim@umich.edu
1962669Sktlim@umich.edu        code('''
1972669Sktlim@umich.edufrom m5.params import *
1982669Sktlim@umich.edufrom m5.SimObject import SimObject
1992292SN/Afrom Controller import RubyController
2002292SN/A
2012292SN/Aclass $py_ident(RubyController):
2022292SN/A    type = '$py_ident'
2032292SN/A    cxx_header = 'mem/protocol/${c_ident}.hh'
2042292SN/A''')
2052292SN/A        code.indent()
2062292SN/A        for param in self.config_parameters:
2072292SN/A            dflt_str = ''
2082292SN/A
2092292SN/A            if param.rvalue is not None:
2102292SN/A                dflt_str = str(param.rvalue.inline()) + ', '
2112292SN/A
2122292SN/A            if param.type_ast.type.c_ident == "MessageBuffer":
2132292SN/A                if param["network"] == "To":
2142292SN/A                    code('${{param.ident}} = MasterPort(${dflt_str}"")')
2152292SN/A                else:
2162292SN/A                    code('${{param.ident}} = SlavePort(${dflt_str}"")')
2172292SN/A
2182292SN/A            elif python_class_map.has_key(param.type_ast.type.c_ident):
2192292SN/A                python_type = python_class_map[param.type_ast.type.c_ident]
2202292SN/A                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
2212292SN/A
2222292SN/A            else:
2232292SN/A                self.error("Unknown c++ to python class conversion for c++ " \
2242292SN/A                           "type: '%s'. Please update the python_class_map " \
2252292SN/A                           "in StateMachine.py", param.type_ast.type.c_ident)
2262292SN/A        code.dedent()
2272292SN/A        code.write(path, '%s.py' % py_ident)
2282292SN/A
2292292SN/A
2302292SN/A    def printControllerHH(self, path):
2312292SN/A        '''Output the method declarations for the class declaration'''
2322292SN/A        code = self.symtab.codeFormatter()
2332292SN/A        ident = self.ident
2342292SN/A        c_ident = "%s_Controller" % self.ident
2352307SN/A
2362307SN/A        code('''
2372307SN/A/** \\file $c_ident.hh
2382307SN/A *
2392307SN/A * Auto generated C++ code started by $__file__:$__line__
2402307SN/A * Created by slicc definition of Module "${{self.short}}"
2412329SN/A */
2422307SN/A
2432307SN/A#ifndef __${ident}_CONTROLLER_HH__
2442307SN/A#define __${ident}_CONTROLLER_HH__
2452307SN/A
2462307SN/A#include <iostream>
2472307SN/A#include <sstream>
2482307SN/A#include <string>
2492307SN/A
2502307SN/A#include "mem/protocol/TransitionResult.hh"
2512307SN/A#include "mem/protocol/Types.hh"
2522307SN/A#include "mem/ruby/common/Consumer.hh"
2532307SN/A#include "mem/ruby/common/Global.hh"
2542307SN/A#include "mem/ruby/slicc_interface/AbstractController.hh"
2552307SN/A#include "params/$c_ident.hh"
2562307SN/A''')
2572329SN/A
2582307SN/A        seen_types = set()
2592307SN/A        for var in self.objects:
2602307SN/A            if var.type.ident not in seen_types and not var.type.isPrimitive:
2612307SN/A                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2622307SN/A                seen_types.add(var.type.ident)
2632307SN/A
2642307SN/A        # for adding information to the protocol debug trace
2652307SN/A        code('''
2662307SN/Aextern std::stringstream ${ident}_transitionComment;
2672307SN/A
2682292SN/Aclass $c_ident : public AbstractController
2692292SN/A{
2702329SN/A  public:
2712329SN/A    typedef ${c_ident}Params Params;
2722292SN/A    $c_ident(const Params *p);
2732329SN/A    static int getNumControllers();
2742329SN/A    void init();
2752292SN/A
2762292SN/A    MessageBuffer* getMandatoryQueue() const;
2772292SN/A    void setNetQueue(const std::string& name, MessageBuffer *b);
2782292SN/A
2792292SN/A    void print(std::ostream& out) const;
2802329SN/A    void wakeup();
2812292SN/A    void resetStats();
2822292SN/A    void regStats();
2832292SN/A    void collateStats();
2842292SN/A
2852292SN/A    void recordCacheTrace(int cntrl, CacheRecorder* tr);
2862292SN/A    Sequencer* getSequencer() const;
2872292SN/A
2882292SN/A    int functionalWriteBuffers(PacketPtr&);
2892329SN/A
2902329SN/A    void countTransition(${ident}_State state, ${ident}_Event event);
2912329SN/A    void possibleTransition(${ident}_State state, ${ident}_Event event);
2922292SN/A    uint64 getEventCount(${ident}_Event event);
2932292SN/A    bool isPossible(${ident}_State state, ${ident}_Event event);
2942292SN/A    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
2952292SN/A
2962292SN/Aprivate:
2972329SN/A''')
2982292SN/A
2992292SN/A        code.indent()
3002292SN/A        # added by SS
3012292SN/A        for param in self.config_parameters:
3022292SN/A            if param.pointer:
3032292SN/A                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
3042292SN/A            else:
3052292SN/A                code('${{param.type_ast.type}} m_${{param.ident}};')
3062292SN/A
3072292SN/A        code('''
3082292SN/ATransitionResult doTransition(${ident}_Event event,
3092292SN/A''')
3102292SN/A
3112292SN/A        if self.EntryType != None:
3122292SN/A            code('''
3132292SN/A                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
3142292SN/A''')
3152292SN/A        if self.TBEType != None:
3162292SN/A            code('''
3172292SN/A                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
3182292SN/A''')
3192292SN/A
3202292SN/A        code('''
3212292SN/A                              const Address addr);
3222329SN/A
3232329SN/ATransitionResult doTransitionWorker(${ident}_Event event,
3242292SN/A                                    ${ident}_State state,
3252292SN/A                                    ${ident}_State& next_state,
3262292SN/A''')
3272292SN/A
3282292SN/A        if self.TBEType != None:
3292292SN/A            code('''
3302292SN/A                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
3312292SN/A''')
3322292SN/A        if self.EntryType != None:
3332292SN/A            code('''
3342292SN/A                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
3352292SN/A''')
3362292SN/A
3372292SN/A        code('''
3382292SN/A                                    const Address& addr);
3392292SN/A
3402292SN/Aint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
3412292SN/Aint m_event_counters[${ident}_Event_NUM];
3422292SN/Abool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
3432292SN/A
3442292SN/Astatic std::vector<Stats::Vector *> eventVec;
3452292SN/Astatic std::vector<std::vector<Stats::Vector *> > transVec;
3462292SN/Astatic int m_num_controllers;
3472292SN/A
3482292SN/A// Internal functions
3492292SN/A''')
3502292SN/A
3512292SN/A        for func in self.functions:
3522292SN/A            proto = func.prototype
3532292SN/A            if proto:
3542292SN/A                code('$proto')
3552292SN/A
3562292SN/A        if self.EntryType != None:
3572292SN/A            code('''
3582292SN/A
3592292SN/A// Set and Reset for cache_entry variable
3602292SN/Avoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
3612292SN/Avoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
3622292SN/A''')
3632292SN/A
3642292SN/A        if self.TBEType != None:
3652292SN/A            code('''
3662292SN/A
3672292SN/A// Set and Reset for tbe variable
3682292SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3692292SN/Avoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3702292SN/A''')
3712292SN/A
3722292SN/A        # Prototype the actions that the controller can take
3732292SN/A        code('''
3742292SN/A
3752292SN/A// Actions
3762292SN/A''')
3772292SN/A        if self.TBEType != None and self.EntryType != None:
3782292SN/A            for action in self.actions.itervalues():
3792292SN/A                code('/** \\brief ${{action.desc}} */')
3802292SN/A                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
3812292SN/A                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
3822292SN/A                     'm_cache_entry_ptr, const Address& addr);')
3832292SN/A        elif self.TBEType != None:
3842292SN/A            for action in self.actions.itervalues():
3852292SN/A                code('/** \\brief ${{action.desc}} */')
3862292SN/A                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
3872292SN/A                     'm_tbe_ptr, const Address& addr);')
3882292SN/A        elif self.EntryType != None:
3892292SN/A            for action in self.actions.itervalues():
3902292SN/A                code('/** \\brief ${{action.desc}} */')
3912292SN/A                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
3922292SN/A                     'm_cache_entry_ptr, const Address& addr);')
3932292SN/A        else:
3942292SN/A            for action in self.actions.itervalues():
3952292SN/A                code('/** \\brief ${{action.desc}} */')
3962292SN/A                code('void ${{action.ident}}(const Address& addr);')
3972292SN/A
3982292SN/A        # the controller internal variables
3992292SN/A        code('''
4002292SN/A
4012292SN/A// Objects
4022292SN/A''')
4032292SN/A        for var in self.objects:
4042292SN/A            th = var.get("template", "")
4052292SN/A            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
4062292SN/A
4072292SN/A        code.dedent()
4082292SN/A        code('};')
4092292SN/A        code('#endif // __${ident}_CONTROLLER_H__')
4102292SN/A        code.write(path, '%s.hh' % c_ident)
4112292SN/A
4122292SN/A    def printControllerCC(self, path, includes):
4132292SN/A        '''Output the actions for performing the actions'''
4142292SN/A
4152292SN/A        code = self.symtab.codeFormatter()
4162292SN/A        ident = self.ident
4172292SN/A        c_ident = "%s_Controller" % self.ident
4182292SN/A
4192669Sktlim@umich.edu        code('''
4202292SN/A/** \\file $c_ident.cc
4212292SN/A *
4222292SN/A * Auto generated C++ code started by $__file__:$__line__
4232292SN/A * Created by slicc definition of Module "${{self.short}}"
4242329SN/A */
4252329SN/A
4262292SN/A#include <sys/types.h>
4272292SN/A#include <unistd.h>
4282292SN/A
4292292SN/A#include <cassert>
4302292SN/A#include <sstream>
4312292SN/A#include <string>
4322292SN/A
4332292SN/A#include "base/compiler.hh"
4342292SN/A#include "base/cprintf.hh"
4352292SN/A#include "debug/RubyGenerated.hh"
4362292SN/A#include "debug/RubySlicc.hh"
4372292SN/A#include "mem/protocol/${ident}_Controller.hh"
4382292SN/A#include "mem/protocol/${ident}_Event.hh"
4392292SN/A#include "mem/protocol/${ident}_State.hh"
4402292SN/A#include "mem/protocol/Types.hh"
4412292SN/A#include "mem/ruby/common/Global.hh"
4422292SN/A#include "mem/ruby/system/System.hh"
4432292SN/A''')
4442292SN/A        for include_path in includes:
4452292SN/A            code('#include "${{include_path}}"')
4462292SN/A
4472292SN/A        code('''
4482292SN/A
4492292SN/Ausing namespace std;
4502292SN/A''')
4512292SN/A
4522329SN/A        # include object classes
4532292SN/A        seen_types = set()
4542292SN/A        for var in self.objects:
4552292SN/A            if var.type.ident not in seen_types and not var.type.isPrimitive:
4562292SN/A                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
4572292SN/A            seen_types.add(var.type.ident)
4582292SN/A
4592292SN/A        num_in_ports = len(self.in_ports)
4602292SN/A
4612336SN/A        code('''
4622336SN/A$c_ident *
4632336SN/A${c_ident}Params::create()
4642329SN/A{
4652292SN/A    return new $c_ident(this);
4662329SN/A}
4672292SN/A
4682292SN/Aint $c_ident::m_num_controllers = 0;
4692292SN/Astd::vector<Stats::Vector *>  $c_ident::eventVec;
4702292SN/Astd::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
4712329SN/A
4722329SN/A// for adding information to the protocol debug trace
4732329SN/Astringstream ${ident}_transitionComment;
4742292SN/A
4752329SN/A#ifndef NDEBUG
4762329SN/A#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
4772329SN/A#else
4782329SN/A#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
4792292SN/A#endif
4802292SN/A
4812292SN/A/** \\brief constructor */
4822292SN/A$c_ident::$c_ident(const Params *p)
4832292SN/A    : AbstractController(p)
4842292SN/A{
4852292SN/A    m_machineID.type = MachineType_${ident};
4862292SN/A    m_machineID.num = m_version;
4872292SN/A    m_num_controllers++;
4882292SN/A
4892292SN/A    m_in_ports = $num_in_ports;
4902292SN/A''')
4912292SN/A        code.indent()
4922292SN/A
4932292SN/A        #
4942292SN/A        # After initializing the universal machine parameters, initialize the
4952292SN/A        # this machines config parameters.  Also if these configuration params
4962292SN/A        # include a sequencer, connect the it to the controller.
4972292SN/A        #
4982292SN/A        for param in self.config_parameters:
4992292SN/A
5002292SN/A            # Do not initialize messgage buffers since they are initialized
5012292SN/A            # when the port based connections are made.
5022292SN/A            if param.type_ast.type.c_ident == "MessageBuffer":
5032292SN/A                continue
5042292SN/A
5052292SN/A            if param.pointer:
5062292SN/A                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
5072292SN/A            else:
5082292SN/A                code('m_${{param.ident}} = p->${{param.ident}};')
5092292SN/A
5102292SN/A            if re.compile("sequencer").search(param.ident):
5112292SN/A                code('m_${{param.ident}}_ptr->setController(this);')
5122292SN/A
5132292SN/A        for var in self.objects:
5142292SN/A            if var.ident.find("mandatoryQueue") >= 0:
5152292SN/A                code('''
5162292SN/Am_${{var.ident}}_ptr = new ${{var.type.c_ident}}();
5172292SN/Am_${{var.ident}}_ptr->setReceiver(this);
5182292SN/A''')
5192292SN/A
5202292SN/A        code('''
5212292SN/A
5222292SN/Afor (int state = 0; state < ${ident}_State_NUM; state++) {
5232292SN/A    for (int event = 0; event < ${ident}_Event_NUM; event++) {
5242292SN/A        m_possible[state][event] = false;
5252292SN/A        m_counters[state][event] = 0;
5262292SN/A    }
5272292SN/A}
5282292SN/Afor (int event = 0; event < ${ident}_Event_NUM; event++) {
5292292SN/A    m_event_counters[event] = 0;
5302292SN/A}
5312292SN/A''')
5322292SN/A        code.dedent()
5332292SN/A        code('''
5342292SN/A}
5352292SN/A
5362329SN/Avoid
5372329SN/A$c_ident::setNetQueue(const std::string& name, MessageBuffer *b)
5382292SN/A{
5392292SN/A    MachineType machine_type = string_to_MachineType("${{self.ident}}");
5402292SN/A    int base M5_VAR_USED = MachineType_base_number(machine_type);
5412292SN/A
5422292SN/A''')
5432292SN/A        code.indent()
5442292SN/A
5452292SN/A        # set for maintaining the vnet, direction pairs already seen for this
5462292SN/A        # machine.  This map helps in implementing the check for avoiding
5472292SN/A        # multiple message buffers being mapped to the same vnet.
5482292SN/A        vnet_dir_set = set()
5492292SN/A
5502292SN/A        for var in self.config_parameters:
5512292SN/A            if "network" in var:
5522292SN/A                vtype = var.type_ast.type
5532292SN/A                vid = "m_%s_ptr" % var.ident
5542292SN/A
5552292SN/A                code('''
5562292SN/Aif ("${{var.ident}}" == name) {
5572292SN/A    $vid = b;
5582292SN/A    assert($vid != NULL);
5592292SN/A''')
5602292SN/A                code.indent()
5612292SN/A                # Network port object
5622292SN/A                network = var["network"]
5632292SN/A                ordered =  var["ordered"]
5642292SN/A
5652292SN/A                if "virtual_network" in var:
5662678Sktlim@umich.edu                    vnet = var["virtual_network"]
5672678Sktlim@umich.edu                    vnet_type = var["vnet_type"]
5682678Sktlim@umich.edu
5692678Sktlim@umich.edu                    assert (vnet, network) not in vnet_dir_set
5702678Sktlim@umich.edu                    vnet_dir_set.add((vnet,network))
5712678Sktlim@umich.edu
5722329SN/A                    code('''
5732329SN/Am_net_ptr->set${network}NetQueue(m_version + base, $ordered, $vnet,
5742292SN/A                                 "$vnet_type", b);
5752292SN/A''')
5762292SN/A                # Set the end
5772292SN/A                if network == "To":
5782292SN/A                    code('$vid->setSender(this);')
5792292SN/A                else:
5802292SN/A                    code('$vid->setReceiver(this);')
5812678Sktlim@umich.edu
5822292SN/A                # Set ordering
5832292SN/A                code('$vid->setOrdering(${{var["ordered"]}});')
5842292SN/A
5852292SN/A                # Set randomization
5862292SN/A                if "random" in var:
5872292SN/A                    # A buffer
5882292SN/A                    code('$vid->setRandomization(${{var["random"]}});')
5892292SN/A
5902292SN/A                # Set Priority
5912292SN/A                if "rank" in var:
5922292SN/A                    code('$vid->setPriority(${{var["rank"]}})')
5932669Sktlim@umich.edu
5942669Sktlim@umich.edu                # Set buffer size
5952669Sktlim@umich.edu                code('$vid->resize(m_buffer_size);')
5962292SN/A
5972292SN/A                if "recycle_latency" in var:
5982669Sktlim@umich.edu                    code('$vid->setRecycleLatency( ' \
5992669Sktlim@umich.edu                         'Cycles(${{var["recycle_latency"]}}));')
6002678Sktlim@umich.edu                else:
6012678Sktlim@umich.edu                    code('$vid->setRecycleLatency(m_recycle_latency);')
6022669Sktlim@umich.edu
6032669Sktlim@umich.edu                # set description (may be overriden later by port def)
6042669Sktlim@umich.edu                code('''
6052292SN/A$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.ident}}]");
6062678Sktlim@umich.edu''')
6072678Sktlim@umich.edu                code.dedent()
6082678Sktlim@umich.edu                code('}\n')
6092678Sktlim@umich.edu
6102678Sktlim@umich.edu        code.dedent()
6112678Sktlim@umich.edu        code('''
6122292SN/A}
6132292SN/A
6142669Sktlim@umich.eduvoid
6152669Sktlim@umich.edu$c_ident::init()
6162292SN/A{
6172292SN/A    // initialize objects
6182669Sktlim@umich.edu
6192669Sktlim@umich.edu''')
6202678Sktlim@umich.edu
6212669Sktlim@umich.edu        code.indent()
6222292SN/A
6232292SN/A        for var in self.objects:
6242292SN/A            vtype = var.type
6252292SN/A            vid = "m_%s_ptr" % var.ident
6262292SN/A            if "network" not in var:
6272292SN/A                # Not a network port object
6282292SN/A                if "primitive" in vtype:
6292292SN/A                    code('$vid = new ${{vtype.c_ident}};')
6302292SN/A                    if "default" in var:
6312678Sktlim@umich.edu                        code('(*$vid) = ${{var["default"]}};')
6322678Sktlim@umich.edu                else:
6332678Sktlim@umich.edu                    # Normal Object
6342678Sktlim@umich.edu                    if var.ident.find("mandatoryQueue") < 0:
6352678Sktlim@umich.edu                        th = var.get("template", "")
6362329SN/A                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
6372678Sktlim@umich.edu                        args = ""
6382669Sktlim@umich.edu                        if "non_obj" not in vtype and not vtype.isEnumeration:
6392329SN/A                            args = var.get("constructor", "")
6402329SN/A                        code('$expr($args);')
6412292SN/A
6422292SN/A                    code('assert($vid != NULL);')
6432292SN/A
6442292SN/A                    if "default" in var:
6452292SN/A                        code('*$vid = ${{var["default"]}}; // Object default')
6462292SN/A                    elif "default" in vtype:
6472292SN/A                        comment = "Type %s default" % vtype.ident
6482292SN/A                        code('*$vid = ${{vtype["default"]}}; // $comment')
6492329SN/A
6502292SN/A                    # Set ordering
6512292SN/A                    if "ordered" in var:
6522292SN/A                        # A buffer
6532292SN/A                        code('$vid->setOrdering(${{var["ordered"]}});')
6542292SN/A
6552292SN/A                    # Set randomization
6562292SN/A                    if "random" in var:
6572292SN/A                        # A buffer
6582292SN/A                        code('$vid->setRandomization(${{var["random"]}});')
6592292SN/A
6602292SN/A                    # Set Priority
6612292SN/A                    if vtype.isBuffer and "rank" in var:
6622292SN/A                        code('$vid->setPriority(${{var["rank"]}});')
6632292SN/A
6642292SN/A                    # Set sender and receiver for trigger queue
6652292SN/A                    if var.ident.find("triggerQueue") >= 0:
6662292SN/A                        code('$vid->setSender(this);')
6672292SN/A                        code('$vid->setReceiver(this);')
6682292SN/A                    elif vtype.c_ident == "TimerTable":
6692292SN/A                        code('$vid->setClockObj(this);')
6702292SN/A                    elif var.ident.find("optionalQueue") >= 0:
6712292SN/A                        code('$vid->setSender(this);')
6722292SN/A                        code('$vid->setReceiver(this);')
6732292SN/A
6742292SN/A            if vtype.isBuffer:
6752292SN/A                if "recycle_latency" in var:
6762292SN/A                    code('$vid->setRecycleLatency( ' \
6772292SN/A                         'Cycles(${{var["recycle_latency"]}}));')
6782292SN/A                else:
6792292SN/A                    code('$vid->setRecycleLatency(m_recycle_latency);')
6802292SN/A
6812292SN/A        # Set the prefetchers
6822292SN/A        code()
6832292SN/A        for prefetcher in self.prefetchers:
6842292SN/A            code('${{prefetcher.code}}.setController(this);')
6852292SN/A
6862292SN/A        code()
6872329SN/A        for port in self.in_ports:
6882292SN/A            # Set the queue consumers
6892292SN/A            code('${{port.code}}.setConsumer(this);')
6902292SN/A            # Set the queue descriptions
6912292SN/A            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
6922292SN/A
6932292SN/A        # Initialize the transition profiling
6942292SN/A        code()
6952292SN/A        for trans in self.transitions:
6962292SN/A            # Figure out if we stall
6972292SN/A            stall = False
6982292SN/A            for action in trans.actions:
6992292SN/A                if action.ident == "z_stall":
7002292SN/A                    stall = True
7012292SN/A
7022292SN/A            # Only possible if it is not a 'z' case
7032292SN/A            if not stall:
7042329SN/A                state = "%s_State_%s" % (self.ident, trans.state.ident)
7052292SN/A                event = "%s_Event_%s" % (self.ident, trans.event.ident)
7062292SN/A                code('possibleTransition($state, $event);')
7072292SN/A
7082292SN/A        code.dedent()
7092292SN/A        code('''
7102292SN/A    AbstractController::init();
7112292SN/A    resetStats();
7122292SN/A}
7132292SN/A''')
7142292SN/A
7152292SN/A        mq_ident = "NULL"
7162292SN/A        for port in self.in_ports:
7172292SN/A            if port.code.find("mandatoryQueue_ptr") >= 0:
7182292SN/A                mq_ident = "m_mandatoryQueue_ptr"
7192292SN/A
7202292SN/A        seq_ident = "NULL"
7212292SN/A        for param in self.config_parameters:
7222292SN/A            if param.ident == "sequencer":
7232292SN/A                assert(param.pointer)
7242292SN/A                seq_ident = "m_%s_ptr" % param.ident
7252292SN/A
7262292SN/A        code('''
7272292SN/A
7282329SN/Avoid
7292292SN/A$c_ident::regStats()
7302292SN/A{
7312292SN/A    AbstractController::regStats();
7322292SN/A
7332292SN/A    if (m_version == 0) {
7342292SN/A        for (${ident}_Event event = ${ident}_Event_FIRST;
7352292SN/A             event < ${ident}_Event_NUM; ++event) {
7362292SN/A            Stats::Vector *t = new Stats::Vector();
7372292SN/A            t->init(m_num_controllers);
7382329SN/A            t->name(params()->ruby_system->name() + ".${c_ident}." +
7392329SN/A                ${ident}_Event_to_string(event));
7402292SN/A            t->flags(Stats::pdf | Stats::total | Stats::oneline |
7412292SN/A                     Stats::nozero);
7422292SN/A
7432292SN/A            eventVec.push_back(t);
7442292SN/A        }
7452292SN/A
7462292SN/A        for (${ident}_State state = ${ident}_State_FIRST;
7472329SN/A             state < ${ident}_State_NUM; ++state) {
7482292SN/A
7492292SN/A            transVec.push_back(std::vector<Stats::Vector *>());
7502292SN/A
7512292SN/A            for (${ident}_Event event = ${ident}_Event_FIRST;
7522292SN/A                 event < ${ident}_Event_NUM; ++event) {
7532292SN/A
7542292SN/A                Stats::Vector *t = new Stats::Vector();
7552292SN/A                t->init(m_num_controllers);
7562292SN/A                t->name(params()->ruby_system->name() + ".${c_ident}." +
7572292SN/A                        ${ident}_State_to_string(state) +
7582292SN/A                        "." + ${ident}_Event_to_string(event));
7592292SN/A
7602292SN/A                t->flags(Stats::pdf | Stats::total | Stats::oneline |
7612292SN/A                         Stats::nozero);
7622292SN/A                transVec[state].push_back(t);
7632292SN/A            }
7642678Sktlim@umich.edu        }
7652678Sktlim@umich.edu    }
7662678Sktlim@umich.edu}
7672678Sktlim@umich.edu
7682678Sktlim@umich.eduvoid
7692678Sktlim@umich.edu$c_ident::collateStats()
7702678Sktlim@umich.edu{
7712678Sktlim@umich.edu    for (${ident}_Event event = ${ident}_Event_FIRST;
7722678Sktlim@umich.edu         event < ${ident}_Event_NUM; ++event) {
7732678Sktlim@umich.edu        for (unsigned int i = 0; i < m_num_controllers; ++i) {
7742678Sktlim@umich.edu            std::map<uint32_t, AbstractController *>::iterator it =
7752678Sktlim@umich.edu                                g_abs_controls[MachineType_${ident}].find(i);
7762678Sktlim@umich.edu            assert(it != g_abs_controls[MachineType_${ident}].end());
7772678Sktlim@umich.edu            (*eventVec[event])[i] =
7782678Sktlim@umich.edu                (($c_ident *)(*it).second)->getEventCount(event);
7792678Sktlim@umich.edu        }
7802678Sktlim@umich.edu    }
7812678Sktlim@umich.edu
7822678Sktlim@umich.edu    for (${ident}_State state = ${ident}_State_FIRST;
7832678Sktlim@umich.edu         state < ${ident}_State_NUM; ++state) {
7842678Sktlim@umich.edu
7852678Sktlim@umich.edu        for (${ident}_Event event = ${ident}_Event_FIRST;
7862678Sktlim@umich.edu             event < ${ident}_Event_NUM; ++event) {
7872678Sktlim@umich.edu
7882678Sktlim@umich.edu            for (unsigned int i = 0; i < m_num_controllers; ++i) {
7892292SN/A                std::map<uint32_t, AbstractController *>::iterator it =
7902292SN/A                                g_abs_controls[MachineType_${ident}].find(i);
7912292SN/A                assert(it != g_abs_controls[MachineType_${ident}].end());
7922292SN/A                (*transVec[state][event])[i] =
7932292SN/A                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
7942292SN/A            }
7952292SN/A        }
7962292SN/A    }
7972292SN/A}
7982292SN/A
7992292SN/Avoid
8002292SN/A$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
8012292SN/A{
8022292SN/A    assert(m_possible[state][event]);
8032292SN/A    m_counters[state][event]++;
8042292SN/A    m_event_counters[event]++;
8052292SN/A}
8062292SN/Avoid
8072292SN/A$c_ident::possibleTransition(${ident}_State state,
8082292SN/A                             ${ident}_Event event)
8092292SN/A{
8102329SN/A    m_possible[state][event] = true;
8112329SN/A}
8122329SN/A
8132292SN/Auint64
8142292SN/A$c_ident::getEventCount(${ident}_Event event)
8152292SN/A{
8162292SN/A    return m_event_counters[event];
8172292SN/A}
8182292SN/A
8192292SN/Abool
8202292SN/A$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
8212292SN/A{
8222292SN/A    return m_possible[state][event];
8232316SN/A}
8242316SN/A
8252329SN/Auint64
8262329SN/A$c_ident::getTransitionCount(${ident}_State state,
8272329SN/A                             ${ident}_Event event)
8282329SN/A{
8292316SN/A    return m_counters[state][event];
8302316SN/A}
8312316SN/A
8322292SN/Aint
8332292SN/A$c_ident::getNumControllers()
8342292SN/A{
8352292SN/A    return m_num_controllers;
8362292SN/A}
8372292SN/A
8382292SN/AMessageBuffer*
8392292SN/A$c_ident::getMandatoryQueue() const
8402292SN/A{
8412292SN/A    return $mq_ident;
8422292SN/A}
8432292SN/A
8442292SN/ASequencer*
8452292SN/A$c_ident::getSequencer() const
8462292SN/A{
8472292SN/A    return $seq_ident;
8482292SN/A}
8492292SN/A
8502292SN/Avoid
8512292SN/A$c_ident::print(ostream& out) const
8522292SN/A{
8532292SN/A    out << "[$c_ident " << m_version << "]";
8542292SN/A}
8552292SN/A
8562292SN/Avoid $c_ident::resetStats()
8572292SN/A{
8582292SN/A    for (int state = 0; state < ${ident}_State_NUM; state++) {
8592292SN/A        for (int event = 0; event < ${ident}_Event_NUM; event++) {
8602292SN/A            m_counters[state][event] = 0;
8612292SN/A        }
8622292SN/A    }
8632292SN/A
8642292SN/A    for (int event = 0; event < ${ident}_Event_NUM; event++) {
8652329SN/A        m_event_counters[event] = 0;
8662329SN/A    }
8672329SN/A
8682329SN/A    AbstractController::resetStats();
8692329SN/A}
8702329SN/A''')
8712329SN/A
8722329SN/A        if self.EntryType != None:
8732329SN/A            code('''
8742329SN/A
8752329SN/A// Set and Reset for cache_entry variable
8762329SN/Avoid
8772329SN/A$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
8782329SN/A{
8792329SN/A  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
8802329SN/A}
8812329SN/A
8822329SN/Avoid
8832329SN/A$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
8842329SN/A{
8852329SN/A  m_cache_entry_ptr = 0;
8862329SN/A}
8872329SN/A''')
8882329SN/A
8892329SN/A        if self.TBEType != None:
8902329SN/A            code('''
8912329SN/A
8922329SN/A// Set and Reset for tbe variable
8932329SN/Avoid
8942329SN/A$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
895{
896  m_tbe_ptr = m_new_tbe;
897}
898
899void
900$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
901{
902  m_tbe_ptr = NULL;
903}
904''')
905
906        code('''
907
908void
909$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
910{
911''')
912        #
913        # Record cache contents for all associated caches.
914        #
915        code.indent()
916        for param in self.config_parameters:
917            if param.type_ast.type.ident == "CacheMemory":
918                assert(param.pointer)
919                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
920
921        code.dedent()
922        code('''
923}
924
925// Actions
926''')
927        if self.TBEType != None and self.EntryType != None:
928            for action in self.actions.itervalues():
929                if "c_code" not in action:
930                 continue
931
932                code('''
933/** \\brief ${{action.desc}} */
934void
935$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
936{
937    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
938    ${{action["c_code"]}}
939}
940
941''')
942        elif self.TBEType != None:
943            for action in self.actions.itervalues():
944                if "c_code" not in action:
945                 continue
946
947                code('''
948/** \\brief ${{action.desc}} */
949void
950$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
951{
952    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
953    ${{action["c_code"]}}
954}
955
956''')
957        elif self.EntryType != None:
958            for action in self.actions.itervalues():
959                if "c_code" not in action:
960                 continue
961
962                code('''
963/** \\brief ${{action.desc}} */
964void
965$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
966{
967    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
968    ${{action["c_code"]}}
969}
970
971''')
972        else:
973            for action in self.actions.itervalues():
974                if "c_code" not in action:
975                 continue
976
977                code('''
978/** \\brief ${{action.desc}} */
979void
980$c_ident::${{action.ident}}(const Address& addr)
981{
982    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
983    ${{action["c_code"]}}
984}
985
986''')
987        for func in self.functions:
988            code(func.generateCode())
989
990        # Function for functional writes to messages buffered in the controller
991        code('''
992int
993$c_ident::functionalWriteBuffers(PacketPtr& pkt)
994{
995    int num_functional_writes = 0;
996''')
997        for var in self.objects:
998            vtype = var.type
999            if vtype.isBuffer:
1000                vid = "m_%s_ptr" % var.ident
1001                code('num_functional_writes += $vid->functionalWrite(pkt);')
1002
1003        for var in self.config_parameters:
1004            vtype = var.type_ast.type
1005            if vtype.isBuffer:
1006                vid = "m_%s_ptr" % var.ident
1007                code('num_functional_writes += $vid->functionalWrite(pkt);')
1008
1009        code('''
1010    return num_functional_writes;
1011}
1012''')
1013
1014        code.write(path, "%s.cc" % c_ident)
1015
1016    def printCWakeup(self, path, includes):
1017        '''Output the wakeup loop for the events'''
1018
1019        code = self.symtab.codeFormatter()
1020        ident = self.ident
1021
1022        outputRequest_types = True
1023        if len(self.request_types) == 0:
1024            outputRequest_types = False
1025
1026        code('''
1027// Auto generated C++ code started by $__file__:$__line__
1028// ${ident}: ${{self.short}}
1029
1030#include <sys/types.h>
1031#include <unistd.h>
1032
1033#include <cassert>
1034
1035#include "base/misc.hh"
1036#include "debug/RubySlicc.hh"
1037#include "mem/protocol/${ident}_Controller.hh"
1038#include "mem/protocol/${ident}_Event.hh"
1039#include "mem/protocol/${ident}_State.hh"
1040''')
1041
1042        if outputRequest_types:
1043            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1044
1045        code('''
1046#include "mem/protocol/Types.hh"
1047#include "mem/ruby/common/Global.hh"
1048#include "mem/ruby/system/System.hh"
1049''')
1050
1051
1052        for include_path in includes:
1053            code('#include "${{include_path}}"')
1054
1055        code('''
1056
1057using namespace std;
1058
1059void
1060${ident}_Controller::wakeup()
1061{
1062    int counter = 0;
1063    while (true) {
1064        // Some cases will put us into an infinite loop without this limit
1065        assert(counter <= m_transitions_per_cycle);
1066        if (counter == m_transitions_per_cycle) {
1067            // Count how often we are fully utilized
1068            m_fully_busy_cycles++;
1069
1070            // Wakeup in another cycle and try again
1071            scheduleEvent(Cycles(1));
1072            break;
1073        }
1074''')
1075
1076        code.indent()
1077        code.indent()
1078
1079        # InPorts
1080        #
1081        for port in self.in_ports:
1082            code.indent()
1083            code('// ${ident}InPort $port')
1084            if port.pairs.has_key("rank"):
1085                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1086            else:
1087                code('m_cur_in_port = 0;')
1088            code('${{port["c_code_in_port"]}}')
1089            code.dedent()
1090
1091            code('')
1092
1093        code.dedent()
1094        code.dedent()
1095        code('''
1096        break;  // If we got this far, we have nothing left todo
1097    }
1098}
1099''')
1100
1101        code.write(path, "%s_Wakeup.cc" % self.ident)
1102
1103    def printCSwitch(self, path):
1104        '''Output switch statement for transition table'''
1105
1106        code = self.symtab.codeFormatter()
1107        ident = self.ident
1108
1109        code('''
1110// Auto generated C++ code started by $__file__:$__line__
1111// ${ident}: ${{self.short}}
1112
1113#include <cassert>
1114
1115#include "base/misc.hh"
1116#include "base/trace.hh"
1117#include "debug/ProtocolTrace.hh"
1118#include "debug/RubyGenerated.hh"
1119#include "mem/protocol/${ident}_Controller.hh"
1120#include "mem/protocol/${ident}_Event.hh"
1121#include "mem/protocol/${ident}_State.hh"
1122#include "mem/protocol/Types.hh"
1123#include "mem/ruby/common/Global.hh"
1124#include "mem/ruby/system/System.hh"
1125
1126#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1127
1128#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1129#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1130
1131TransitionResult
1132${ident}_Controller::doTransition(${ident}_Event event,
1133''')
1134        if self.EntryType != None:
1135            code('''
1136                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1137''')
1138        if self.TBEType != None:
1139            code('''
1140                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1141''')
1142        code('''
1143                                  const Address addr)
1144{
1145''')
1146        code.indent()
1147
1148        if self.TBEType != None and self.EntryType != None:
1149            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1150        elif self.TBEType != None:
1151            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1152        elif self.EntryType != None:
1153            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1154        else:
1155            code('${ident}_State state = getState(addr);')
1156
1157        code('''
1158${ident}_State next_state = state;
1159
1160DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1161        *this, curCycle(), ${ident}_State_to_string(state),
1162        ${ident}_Event_to_string(event), addr);
1163
1164TransitionResult result =
1165''')
1166        if self.TBEType != None and self.EntryType != None:
1167            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1168        elif self.TBEType != None:
1169            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1170        elif self.EntryType != None:
1171            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1172        else:
1173            code('doTransitionWorker(event, state, next_state, addr);')
1174
1175        code('''
1176
1177if (result == TransitionResult_Valid) {
1178    DPRINTF(RubyGenerated, "next_state: %s\\n",
1179            ${ident}_State_to_string(next_state));
1180    countTransition(state, event);
1181
1182    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1183             curTick(), m_version, "${ident}",
1184             ${ident}_Event_to_string(event),
1185             ${ident}_State_to_string(state),
1186             ${ident}_State_to_string(next_state),
1187             addr, GET_TRANSITION_COMMENT());
1188
1189    CLEAR_TRANSITION_COMMENT();
1190''')
1191        if self.TBEType != None and self.EntryType != None:
1192            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1193            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1194        elif self.TBEType != None:
1195            code('setState(m_tbe_ptr, addr, next_state);')
1196            code('setAccessPermission(addr, next_state);')
1197        elif self.EntryType != None:
1198            code('setState(m_cache_entry_ptr, addr, next_state);')
1199            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1200        else:
1201            code('setState(addr, next_state);')
1202            code('setAccessPermission(addr, next_state);')
1203
1204        code('''
1205} else if (result == TransitionResult_ResourceStall) {
1206    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1207             curTick(), m_version, "${ident}",
1208             ${ident}_Event_to_string(event),
1209             ${ident}_State_to_string(state),
1210             ${ident}_State_to_string(next_state),
1211             addr, "Resource Stall");
1212} else if (result == TransitionResult_ProtocolStall) {
1213    DPRINTF(RubyGenerated, "stalling\\n");
1214    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1215             curTick(), m_version, "${ident}",
1216             ${ident}_Event_to_string(event),
1217             ${ident}_State_to_string(state),
1218             ${ident}_State_to_string(next_state),
1219             addr, "Protocol Stall");
1220}
1221
1222return result;
1223''')
1224        code.dedent()
1225        code('''
1226}
1227
1228TransitionResult
1229${ident}_Controller::doTransitionWorker(${ident}_Event event,
1230                                        ${ident}_State state,
1231                                        ${ident}_State& next_state,
1232''')
1233
1234        if self.TBEType != None:
1235            code('''
1236                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1237''')
1238        if self.EntryType != None:
1239                  code('''
1240                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1241''')
1242        code('''
1243                                        const Address& addr)
1244{
1245    switch(HASH_FUN(state, event)) {
1246''')
1247
1248        # This map will allow suppress generating duplicate code
1249        cases = orderdict()
1250
1251        for trans in self.transitions:
1252            case_string = "%s_State_%s, %s_Event_%s" % \
1253                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1254
1255            case = self.symtab.codeFormatter()
1256            # Only set next_state if it changes
1257            if trans.state != trans.nextState:
1258                ns_ident = trans.nextState.ident
1259                case('next_state = ${ident}_State_${ns_ident};')
1260
1261            actions = trans.actions
1262            request_types = trans.request_types
1263
1264            # Check for resources
1265            case_sorter = []
1266            res = trans.resources
1267            for key,val in res.iteritems():
1268                val = '''
1269if (!%s.areNSlotsAvailable(%s))
1270    return TransitionResult_ResourceStall;
1271''' % (key.code, val)
1272                case_sorter.append(val)
1273
1274            # Check all of the request_types for resource constraints
1275            for request_type in request_types:
1276                val = '''
1277if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1278    return TransitionResult_ResourceStall;
1279}
1280''' % (self.ident, request_type.ident)
1281                case_sorter.append(val)
1282
1283            # Emit the code sequences in a sorted order.  This makes the
1284            # output deterministic (without this the output order can vary
1285            # since Map's keys() on a vector of pointers is not deterministic
1286            for c in sorted(case_sorter):
1287                case("$c")
1288
1289            # Record access types for this transition
1290            for request_type in request_types:
1291                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1292
1293            # Figure out if we stall
1294            stall = False
1295            for action in actions:
1296                if action.ident == "z_stall":
1297                    stall = True
1298                    break
1299
1300            if stall:
1301                case('return TransitionResult_ProtocolStall;')
1302            else:
1303                if self.TBEType != None and self.EntryType != None:
1304                    for action in actions:
1305                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1306                elif self.TBEType != None:
1307                    for action in actions:
1308                        case('${{action.ident}}(m_tbe_ptr, addr);')
1309                elif self.EntryType != None:
1310                    for action in actions:
1311                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1312                else:
1313                    for action in actions:
1314                        case('${{action.ident}}(addr);')
1315                case('return TransitionResult_Valid;')
1316
1317            case = str(case)
1318
1319            # Look to see if this transition code is unique.
1320            if case not in cases:
1321                cases[case] = []
1322
1323            cases[case].append(case_string)
1324
1325        # Walk through all of the unique code blocks and spit out the
1326        # corresponding case statement elements
1327        for case,transitions in cases.iteritems():
1328            # Iterative over all the multiple transitions that share
1329            # the same code
1330            for trans in transitions:
1331                code('  case HASH_FUN($trans):')
1332            code('    $case\n')
1333
1334        code('''
1335      default:
1336        fatal("Invalid transition\\n"
1337              "%s time: %d addr: %s event: %s state: %s\\n",
1338              name(), curCycle(), addr, event, state);
1339    }
1340
1341    return TransitionResult_Valid;
1342}
1343''')
1344        code.write(path, "%s_Transitions.cc" % self.ident)
1345
1346
1347    # **************************
1348    # ******* HTML Files *******
1349    # **************************
1350    def frameRef(self, click_href, click_target, over_href, over_num, text):
1351        code = self.symtab.codeFormatter(fix_newlines=False)
1352        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1353    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1354        parent.frames[$over_num].location='$over_href'
1355    }\">
1356    ${{html.formatShorthand(text)}}
1357    </A>""")
1358        return str(code)
1359
1360    def writeHTMLFiles(self, path):
1361        # Create table with no row hilighted
1362        self.printHTMLTransitions(path, None)
1363
1364        # Generate transition tables
1365        for state in self.states.itervalues():
1366            self.printHTMLTransitions(path, state)
1367
1368        # Generate action descriptions
1369        for action in self.actions.itervalues():
1370            name = "%s_action_%s.html" % (self.ident, action.ident)
1371            code = html.createSymbol(action, "Action")
1372            code.write(path, name)
1373
1374        # Generate state descriptions
1375        for state in self.states.itervalues():
1376            name = "%s_State_%s.html" % (self.ident, state.ident)
1377            code = html.createSymbol(state, "State")
1378            code.write(path, name)
1379
1380        # Generate event descriptions
1381        for event in self.events.itervalues():
1382            name = "%s_Event_%s.html" % (self.ident, event.ident)
1383            code = html.createSymbol(event, "Event")
1384            code.write(path, name)
1385
1386    def printHTMLTransitions(self, path, active_state):
1387        code = self.symtab.codeFormatter()
1388
1389        code('''
1390<HTML>
1391<BODY link="blue" vlink="blue">
1392
1393<H1 align="center">${{html.formatShorthand(self.short)}}:
1394''')
1395        code.indent()
1396        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1397            mid = machine.ident
1398            if i != 0:
1399                extra = " - "
1400            else:
1401                extra = ""
1402            if machine == self:
1403                code('$extra$mid')
1404            else:
1405                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1406        code.dedent()
1407
1408        code("""
1409</H1>
1410
1411<TABLE border=1>
1412<TR>
1413  <TH> </TH>
1414""")
1415
1416        for event in self.events.itervalues():
1417            href = "%s_Event_%s.html" % (self.ident, event.ident)
1418            ref = self.frameRef(href, "Status", href, "1", event.short)
1419            code('<TH bgcolor=white>$ref</TH>')
1420
1421        code('</TR>')
1422        # -- Body of table
1423        for state in self.states.itervalues():
1424            # -- Each row
1425            if state == active_state:
1426                color = "yellow"
1427            else:
1428                color = "white"
1429
1430            click = "%s_table_%s.html" % (self.ident, state.ident)
1431            over = "%s_State_%s.html" % (self.ident, state.ident)
1432            text = html.formatShorthand(state.short)
1433            ref = self.frameRef(click, "Table", over, "1", state.short)
1434            code('''
1435<TR>
1436  <TH bgcolor=$color>$ref</TH>
1437''')
1438
1439            # -- One column for each event
1440            for event in self.events.itervalues():
1441                trans = self.table.get((state,event), None)
1442                if trans is None:
1443                    # This is the no transition case
1444                    if state == active_state:
1445                        color = "#C0C000"
1446                    else:
1447                        color = "lightgrey"
1448
1449                    code('<TD bgcolor=$color>&nbsp;</TD>')
1450                    continue
1451
1452                next = trans.nextState
1453                stall_action = False
1454
1455                # -- Get the actions
1456                for action in trans.actions:
1457                    if action.ident == "z_stall" or \
1458                       action.ident == "zz_recycleMandatoryQueue":
1459                        stall_action = True
1460
1461                # -- Print out "actions/next-state"
1462                if stall_action:
1463                    if state == active_state:
1464                        color = "#C0C000"
1465                    else:
1466                        color = "lightgrey"
1467
1468                elif active_state and next.ident == active_state.ident:
1469                    color = "aqua"
1470                elif state == active_state:
1471                    color = "yellow"
1472                else:
1473                    color = "white"
1474
1475                code('<TD bgcolor=$color>')
1476                for action in trans.actions:
1477                    href = "%s_action_%s.html" % (self.ident, action.ident)
1478                    ref = self.frameRef(href, "Status", href, "1",
1479                                        action.short)
1480                    code('  $ref')
1481                if next != state:
1482                    if trans.actions:
1483                        code('/')
1484                    click = "%s_table_%s.html" % (self.ident, next.ident)
1485                    over = "%s_State_%s.html" % (self.ident, next.ident)
1486                    ref = self.frameRef(click, "Table", over, "1", next.short)
1487                    code("$ref")
1488                code("</TD>")
1489
1490            # -- Each row
1491            if state == active_state:
1492                color = "yellow"
1493            else:
1494                color = "white"
1495
1496            click = "%s_table_%s.html" % (self.ident, state.ident)
1497            over = "%s_State_%s.html" % (self.ident, state.ident)
1498            ref = self.frameRef(click, "Table", over, "1", state.short)
1499            code('''
1500  <TH bgcolor=$color>$ref</TH>
1501</TR>
1502''')
1503        code('''
1504<!- Column footer->
1505<TR>
1506  <TH> </TH>
1507''')
1508
1509        for event in self.events.itervalues():
1510            href = "%s_Event_%s.html" % (self.ident, event.ident)
1511            ref = self.frameRef(href, "Status", href, "1", event.short)
1512            code('<TH bgcolor=white>$ref</TH>')
1513        code('''
1514</TR>
1515</TABLE>
1516</BODY></HTML>
1517''')
1518
1519
1520        if active_state:
1521            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1522        else:
1523            name = "%s_table.html" % self.ident
1524        code.write(path, name)
1525
1526__all__ = [ "StateMachine" ]
1527