StateMachine.py revision 10121
16019Shines@cs.fsu.edu# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
26019Shines@cs.fsu.edu# Copyright (c) 2009 The Hewlett-Packard Development Company
37178Sgblack@eecs.umich.edu# All rights reserved.
47178Sgblack@eecs.umich.edu#
57178Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
67178Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
77178Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
87178Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
97178Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
107178Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
117178Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
127178Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
137178Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
147178Sgblack@eecs.umich.edu# this software without specific prior written permission.
156019Shines@cs.fsu.edu#
166019Shines@cs.fsu.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176019Shines@cs.fsu.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186019Shines@cs.fsu.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196019Shines@cs.fsu.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206019Shines@cs.fsu.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216019Shines@cs.fsu.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226019Shines@cs.fsu.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236019Shines@cs.fsu.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246019Shines@cs.fsu.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256019Shines@cs.fsu.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266019Shines@cs.fsu.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276019Shines@cs.fsu.edu
286019Shines@cs.fsu.edufrom m5.util import orderdict
296019Shines@cs.fsu.edu
306019Shines@cs.fsu.edufrom slicc.symbols.Symbol import Symbol
316019Shines@cs.fsu.edufrom slicc.symbols.Var import Var
326019Shines@cs.fsu.eduimport slicc.generate.html as html
336019Shines@cs.fsu.eduimport re
346019Shines@cs.fsu.edu
356019Shines@cs.fsu.edupython_class_map = {
366019Shines@cs.fsu.edu                    "int": "Int",
376019Shines@cs.fsu.edu                    "uint32_t" : "UInt32",
386019Shines@cs.fsu.edu                    "std::string": "String",
396019Shines@cs.fsu.edu                    "bool": "Bool",
406019Shines@cs.fsu.edu                    "CacheMemory": "RubyCache",
416019Shines@cs.fsu.edu                    "WireBuffer": "RubyWireBuffer",
426019Shines@cs.fsu.edu                    "Sequencer": "RubySequencer",
436019Shines@cs.fsu.edu                    "DirectoryMemory": "RubyDirectoryMemory",
446019Shines@cs.fsu.edu                    "MemoryControl": "MemoryControl",
456019Shines@cs.fsu.edu                    "DMASequencer": "DMASequencer",
466019Shines@cs.fsu.edu                    "Prefetcher":"Prefetcher",
476019Shines@cs.fsu.edu                    "Cycles":"Cycles",
486019Shines@cs.fsu.edu                   }
496019Shines@cs.fsu.edu
506019Shines@cs.fsu.educlass StateMachine(Symbol):
516019Shines@cs.fsu.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
526019Shines@cs.fsu.edu        super(StateMachine, self).__init__(symtab, ident, location, pairs)
536019Shines@cs.fsu.edu        self.table = None
546019Shines@cs.fsu.edu        self.config_parameters = config_parameters
556019Shines@cs.fsu.edu        self.prefetchers = []
566019Shines@cs.fsu.edu
576019Shines@cs.fsu.edu        for param in config_parameters:
586243Sgblack@eecs.umich.edu            if param.pointer:
596243Sgblack@eecs.umich.edu                var = Var(symtab, param.name, location, param.type_ast.type,
606243Sgblack@eecs.umich.edu                          "(*m_%s_ptr)" % param.name, {}, self)
616243Sgblack@eecs.umich.edu            else:
626243Sgblack@eecs.umich.edu                var = Var(symtab, param.name, location, param.type_ast.type,
636019Shines@cs.fsu.edu                          "m_%s" % param.name, {}, self)
646019Shines@cs.fsu.edu            self.symtab.registerSym(param.name, var)
656019Shines@cs.fsu.edu            if str(param.type_ast.type) == "Prefetcher":
666019Shines@cs.fsu.edu                self.prefetchers.append(var)
676019Shines@cs.fsu.edu
686019Shines@cs.fsu.edu        self.states = orderdict()
696019Shines@cs.fsu.edu        self.events = orderdict()
706019Shines@cs.fsu.edu        self.actions = orderdict()
716019Shines@cs.fsu.edu        self.request_types = orderdict()
726019Shines@cs.fsu.edu        self.transitions = []
736019Shines@cs.fsu.edu        self.in_ports = []
746019Shines@cs.fsu.edu        self.functions = []
756019Shines@cs.fsu.edu        self.objects = []
766019Shines@cs.fsu.edu        self.TBEType   = None
776019Shines@cs.fsu.edu        self.EntryType = None
786019Shines@cs.fsu.edu
796019Shines@cs.fsu.edu    def __repr__(self):
806019Shines@cs.fsu.edu        return "[StateMachine: %s]" % self.ident
816019Shines@cs.fsu.edu
826019Shines@cs.fsu.edu    def addState(self, state):
836019Shines@cs.fsu.edu        assert self.table is None
846019Shines@cs.fsu.edu        self.states[state.ident] = state
856019Shines@cs.fsu.edu
866019Shines@cs.fsu.edu    def addEvent(self, event):
876019Shines@cs.fsu.edu        assert self.table is None
886019Shines@cs.fsu.edu        self.events[event.ident] = event
896019Shines@cs.fsu.edu
906019Shines@cs.fsu.edu    def addAction(self, action):
916019Shines@cs.fsu.edu        assert self.table is None
926019Shines@cs.fsu.edu
936019Shines@cs.fsu.edu        # Check for duplicate action
946252Sgblack@eecs.umich.edu        for other in self.actions.itervalues():
956243Sgblack@eecs.umich.edu            if action.ident == other.ident:
966243Sgblack@eecs.umich.edu                action.warning("Duplicate action definition: %s" % action.ident)
976243Sgblack@eecs.umich.edu                action.error("Duplicate action definition: %s" % action.ident)
986019Shines@cs.fsu.edu            if action.short == other.short:
996019Shines@cs.fsu.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
1006019Shines@cs.fsu.edu                other.warning("    shorthand = %s" % other.short)
1016019Shines@cs.fsu.edu                action.warning("Duplicate action shorthand: %s" % action.ident)
1026019Shines@cs.fsu.edu                action.error("    shorthand = %s" % action.short)
1036252Sgblack@eecs.umich.edu
1046243Sgblack@eecs.umich.edu        self.actions[action.ident] = action
1056243Sgblack@eecs.umich.edu
1066243Sgblack@eecs.umich.edu    def addRequestType(self, request_type):
1076019Shines@cs.fsu.edu        assert self.table is None
1086019Shines@cs.fsu.edu        self.request_types[request_type.ident] = request_type
1096019Shines@cs.fsu.edu
1106019Shines@cs.fsu.edu    def addTransition(self, trans):
1116019Shines@cs.fsu.edu        assert self.table is None
1126019Shines@cs.fsu.edu        self.transitions.append(trans)
1136019Shines@cs.fsu.edu
1146252Sgblack@eecs.umich.edu    def addInPort(self, var):
1156243Sgblack@eecs.umich.edu        self.in_ports.append(var)
1166243Sgblack@eecs.umich.edu
1176243Sgblack@eecs.umich.edu    def addFunc(self, func):
1186019Shines@cs.fsu.edu        # register func in the symbol table
1196019Shines@cs.fsu.edu        self.symtab.registerSym(str(func), func)
1206019Shines@cs.fsu.edu        self.functions.append(func)
1216019Shines@cs.fsu.edu
1226019Shines@cs.fsu.edu    def addObject(self, obj):
1236019Shines@cs.fsu.edu        self.objects.append(obj)
1246019Shines@cs.fsu.edu
1256019Shines@cs.fsu.edu    def addType(self, type):
1266019Shines@cs.fsu.edu        type_ident = '%s' % type.c_ident
1276019Shines@cs.fsu.edu
1286019Shines@cs.fsu.edu        if type_ident == "%s_TBE" %self.ident:
1296019Shines@cs.fsu.edu            if self.TBEType != None:
1306019Shines@cs.fsu.edu                self.error("Multiple Transaction Buffer types in a " \
1316019Shines@cs.fsu.edu                           "single machine.");
1326019Shines@cs.fsu.edu            self.TBEType = type
1336019Shines@cs.fsu.edu
1346724Sgblack@eecs.umich.edu        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1356724Sgblack@eecs.umich.edu            if self.EntryType != None:
1366019Shines@cs.fsu.edu                self.error("Multiple AbstractCacheEntry types in a " \
1376019Shines@cs.fsu.edu                           "single machine.");
1386019Shines@cs.fsu.edu            self.EntryType = type
1396019Shines@cs.fsu.edu
1406019Shines@cs.fsu.edu    # Needs to be called before accessing the table
1416252Sgblack@eecs.umich.edu    def buildTable(self):
1426243Sgblack@eecs.umich.edu        assert self.table is None
1436243Sgblack@eecs.umich.edu
1446243Sgblack@eecs.umich.edu        table = {}
1456019Shines@cs.fsu.edu
1466019Shines@cs.fsu.edu        for trans in self.transitions:
1476019Shines@cs.fsu.edu            # Track which actions we touch so we know if we use them
1486019Shines@cs.fsu.edu            # all -- really this should be done for all symbols as
1496019Shines@cs.fsu.edu            # part of the symbol table, then only trigger it for
1506019Shines@cs.fsu.edu            # Actions, States, Events, etc.
1517356Sgblack@eecs.umich.edu
1527356Sgblack@eecs.umich.edu            for action in trans.actions:
1537356Sgblack@eecs.umich.edu                action.used = True
1547356Sgblack@eecs.umich.edu
1557356Sgblack@eecs.umich.edu            index = (trans.state, trans.event)
1567356Sgblack@eecs.umich.edu            if index in table:
1577356Sgblack@eecs.umich.edu                table[index].warning("Duplicate transition: %s" % table[index])
1587356Sgblack@eecs.umich.edu                trans.error("Duplicate transition: %s" % trans)
1597178Sgblack@eecs.umich.edu            table[index] = trans
1607178Sgblack@eecs.umich.edu
1617178Sgblack@eecs.umich.edu        # Look at all actions to make sure we used them all
1627337Sgblack@eecs.umich.edu        for action in self.actions.itervalues():
1637178Sgblack@eecs.umich.edu            if not action.used:
1647178Sgblack@eecs.umich.edu                error_msg = "Unused action: %s" % action.ident
1657178Sgblack@eecs.umich.edu                if "desc" in action:
1667178Sgblack@eecs.umich.edu                    error_msg += ", "  + action.desc
1677178Sgblack@eecs.umich.edu                action.warning(error_msg)
1687178Sgblack@eecs.umich.edu        self.table = table
1697178Sgblack@eecs.umich.edu
1707178Sgblack@eecs.umich.edu    def writeCodeFiles(self, path, includes):
1717178Sgblack@eecs.umich.edu        self.printControllerPython(path)
1727178Sgblack@eecs.umich.edu        self.printControllerHH(path)
1737178Sgblack@eecs.umich.edu        self.printControllerCC(path, includes)
1747335Sgblack@eecs.umich.edu        self.printCSwitch(path)
1757335Sgblack@eecs.umich.edu        self.printCWakeup(path, includes)
1767335Sgblack@eecs.umich.edu
1777335Sgblack@eecs.umich.edu    def printControllerPython(self, path):
1787335Sgblack@eecs.umich.edu        code = self.symtab.codeFormatter()
1797335Sgblack@eecs.umich.edu        ident = self.ident
1807335Sgblack@eecs.umich.edu        py_ident = "%s_Controller" % ident
1817335Sgblack@eecs.umich.edu        c_ident = "%s_Controller" % self.ident
1827335Sgblack@eecs.umich.edu        code('''
1837335Sgblack@eecs.umich.edufrom m5.params import *
1847335Sgblack@eecs.umich.edufrom m5.SimObject import SimObject
1857335Sgblack@eecs.umich.edufrom Controller import RubyController
1867337Sgblack@eecs.umich.edu
1877335Sgblack@eecs.umich.educlass $py_ident(RubyController):
1887335Sgblack@eecs.umich.edu    type = '$py_ident'
1897335Sgblack@eecs.umich.edu    cxx_header = 'mem/protocol/${c_ident}.hh'
1907335Sgblack@eecs.umich.edu''')
1917335Sgblack@eecs.umich.edu        code.indent()
1927335Sgblack@eecs.umich.edu        for param in self.config_parameters:
1937335Sgblack@eecs.umich.edu            dflt_str = ''
1947335Sgblack@eecs.umich.edu            if param.default is not None:
1957335Sgblack@eecs.umich.edu                dflt_str = str(param.default) + ', '
1967335Sgblack@eecs.umich.edu            if python_class_map.has_key(param.type_ast.type.c_ident):
1977335Sgblack@eecs.umich.edu                python_type = python_class_map[param.type_ast.type.c_ident]
1987335Sgblack@eecs.umich.edu                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
1997178Sgblack@eecs.umich.edu            else:
2007178Sgblack@eecs.umich.edu                self.error("Unknown c++ to python class conversion for c++ " \
2017178Sgblack@eecs.umich.edu                           "type: '%s'. Please update the python_class_map " \
2027178Sgblack@eecs.umich.edu                           "in StateMachine.py", param.type_ast.type.c_ident)
2037178Sgblack@eecs.umich.edu        code.dedent()
2047178Sgblack@eecs.umich.edu        code.write(path, '%s.py' % py_ident)
2057178Sgblack@eecs.umich.edu
2067178Sgblack@eecs.umich.edu
2077178Sgblack@eecs.umich.edu    def printControllerHH(self, path):
2087178Sgblack@eecs.umich.edu        '''Output the method declarations for the class declaration'''
2097178Sgblack@eecs.umich.edu        code = self.symtab.codeFormatter()
2107178Sgblack@eecs.umich.edu        ident = self.ident
2117178Sgblack@eecs.umich.edu        c_ident = "%s_Controller" % self.ident
2127178Sgblack@eecs.umich.edu
2137178Sgblack@eecs.umich.edu        code('''
2147178Sgblack@eecs.umich.edu/** \\file $c_ident.hh
2157178Sgblack@eecs.umich.edu *
2167178Sgblack@eecs.umich.edu * Auto generated C++ code started by $__file__:$__line__
2177178Sgblack@eecs.umich.edu * Created by slicc definition of Module "${{self.short}}"
2187178Sgblack@eecs.umich.edu */
2197178Sgblack@eecs.umich.edu
2207178Sgblack@eecs.umich.edu#ifndef __${ident}_CONTROLLER_HH__
2217178Sgblack@eecs.umich.edu#define __${ident}_CONTROLLER_HH__
2227178Sgblack@eecs.umich.edu
2237178Sgblack@eecs.umich.edu#include <iostream>
2247178Sgblack@eecs.umich.edu#include <sstream>
2257178Sgblack@eecs.umich.edu#include <string>
2267178Sgblack@eecs.umich.edu
2277178Sgblack@eecs.umich.edu#include "mem/protocol/TransitionResult.hh"
2287346Sgblack@eecs.umich.edu#include "mem/protocol/Types.hh"
2297346Sgblack@eecs.umich.edu#include "mem/ruby/common/Consumer.hh"
2307346Sgblack@eecs.umich.edu#include "mem/ruby/common/Global.hh"
2317346Sgblack@eecs.umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
2327346Sgblack@eecs.umich.edu#include "params/$c_ident.hh"
2337346Sgblack@eecs.umich.edu''')
2347346Sgblack@eecs.umich.edu
2357346Sgblack@eecs.umich.edu        seen_types = set()
2367346Sgblack@eecs.umich.edu        has_peer = False
2377346Sgblack@eecs.umich.edu        for var in self.objects:
2387178Sgblack@eecs.umich.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
2397346Sgblack@eecs.umich.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2407346Sgblack@eecs.umich.edu            if "network" in var and "physical_network" in var:
2417346Sgblack@eecs.umich.edu                has_peer = True
2427346Sgblack@eecs.umich.edu            seen_types.add(var.type.ident)
2437346Sgblack@eecs.umich.edu
2447346Sgblack@eecs.umich.edu        # for adding information to the protocol debug trace
2457346Sgblack@eecs.umich.edu        code('''
2467346Sgblack@eecs.umich.eduextern std::stringstream ${ident}_transitionComment;
2477346Sgblack@eecs.umich.edu
2487346Sgblack@eecs.umich.educlass $c_ident : public AbstractController
2497346Sgblack@eecs.umich.edu{
2507346Sgblack@eecs.umich.edu  public:
2517346Sgblack@eecs.umich.edu    typedef ${c_ident}Params Params;
2527346Sgblack@eecs.umich.edu    $c_ident(const Params *p);
2537346Sgblack@eecs.umich.edu    static int getNumControllers();
2547178Sgblack@eecs.umich.edu    void init();
2557337Sgblack@eecs.umich.edu    MessageBuffer* getMandatoryQueue() const;
2567337Sgblack@eecs.umich.edu    const std::string toString() const;
2577337Sgblack@eecs.umich.edu
2587337Sgblack@eecs.umich.edu    void print(std::ostream& out) const;
2597337Sgblack@eecs.umich.edu    void wakeup();
2607337Sgblack@eecs.umich.edu    void resetStats();
2617337Sgblack@eecs.umich.edu    void regStats();
2627337Sgblack@eecs.umich.edu    void collateStats();
2637337Sgblack@eecs.umich.edu
2647337Sgblack@eecs.umich.edu    void recordCacheTrace(int cntrl, CacheRecorder* tr);
2657337Sgblack@eecs.umich.edu    Sequencer* getSequencer() const;
2667337Sgblack@eecs.umich.edu
2677337Sgblack@eecs.umich.edu    bool functionalReadBuffers(PacketPtr&);
2687337Sgblack@eecs.umich.edu    uint32_t functionalWriteBuffers(PacketPtr&);
2697337Sgblack@eecs.umich.edu
2707178Sgblack@eecs.umich.edu    void countTransition(${ident}_State state, ${ident}_Event event);
2717178Sgblack@eecs.umich.edu    void possibleTransition(${ident}_State state, ${ident}_Event event);
2727178Sgblack@eecs.umich.edu    uint64 getEventCount(${ident}_Event event);
2737178Sgblack@eecs.umich.edu    bool isPossible(${ident}_State state, ${ident}_Event event);
2747337Sgblack@eecs.umich.edu    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
2757337Sgblack@eecs.umich.edu
2767337Sgblack@eecs.umich.eduprivate:
2777337Sgblack@eecs.umich.edu''')
2787346Sgblack@eecs.umich.edu
2797346Sgblack@eecs.umich.edu        code.indent()
2807346Sgblack@eecs.umich.edu        # added by SS
2817346Sgblack@eecs.umich.edu        for param in self.config_parameters:
2827346Sgblack@eecs.umich.edu            if param.pointer:
2837337Sgblack@eecs.umich.edu                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
2847178Sgblack@eecs.umich.edu            else:
2857321Sgblack@eecs.umich.edu                code('${{param.type_ast.type}} m_${{param.ident}};')
2867356Sgblack@eecs.umich.edu
2877321Sgblack@eecs.umich.edu        code('''
2887356Sgblack@eecs.umich.eduTransitionResult doTransition(${ident}_Event event,
2897356Sgblack@eecs.umich.edu''')
2907356Sgblack@eecs.umich.edu
2917356Sgblack@eecs.umich.edu        if self.EntryType != None:
2927356Sgblack@eecs.umich.edu            code('''
2937356Sgblack@eecs.umich.edu                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
2947356Sgblack@eecs.umich.edu''')
2957356Sgblack@eecs.umich.edu        if self.TBEType != None:
2967356Sgblack@eecs.umich.edu            code('''
2977356Sgblack@eecs.umich.edu                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
2987356Sgblack@eecs.umich.edu''')
2997356Sgblack@eecs.umich.edu
3007321Sgblack@eecs.umich.edu        code('''
3017321Sgblack@eecs.umich.edu                              const Address addr);
3027321Sgblack@eecs.umich.edu
3037321Sgblack@eecs.umich.eduTransitionResult doTransitionWorker(${ident}_Event event,
3047321Sgblack@eecs.umich.edu                                    ${ident}_State state,
3057321Sgblack@eecs.umich.edu                                    ${ident}_State& next_state,
3067321Sgblack@eecs.umich.edu''')
3077321Sgblack@eecs.umich.edu
3087321Sgblack@eecs.umich.edu        if self.TBEType != None:
3097321Sgblack@eecs.umich.edu            code('''
3107321Sgblack@eecs.umich.edu                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
3117335Sgblack@eecs.umich.edu''')
3127335Sgblack@eecs.umich.edu        if self.EntryType != None:
3137335Sgblack@eecs.umich.edu            code('''
3147335Sgblack@eecs.umich.edu                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
3157335Sgblack@eecs.umich.edu''')
3167335Sgblack@eecs.umich.edu
3177335Sgblack@eecs.umich.edu        code('''
3187335Sgblack@eecs.umich.edu                                    const Address& addr);
3197335Sgblack@eecs.umich.edu
3207321Sgblack@eecs.umich.eduint m_counters[${ident}_State_NUM][${ident}_Event_NUM];
3217323Sgblack@eecs.umich.eduint m_event_counters[${ident}_Event_NUM];
3227323Sgblack@eecs.umich.edubool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
3237323Sgblack@eecs.umich.edu
3247323Sgblack@eecs.umich.edustatic std::vector<Stats::Vector *> eventVec;
3257323Sgblack@eecs.umich.edustatic std::vector<std::vector<Stats::Vector *> > transVec;
3267323Sgblack@eecs.umich.edustatic int m_num_controllers;
3277323Sgblack@eecs.umich.edu
3287323Sgblack@eecs.umich.edu// Internal functions
3297323Sgblack@eecs.umich.edu''')
3307323Sgblack@eecs.umich.edu
3317394Sgblack@eecs.umich.edu        for func in self.functions:
3327394Sgblack@eecs.umich.edu            proto = func.prototype
3337394Sgblack@eecs.umich.edu            if proto:
3347394Sgblack@eecs.umich.edu                code('$proto')
3357394Sgblack@eecs.umich.edu
3367394Sgblack@eecs.umich.edu        if has_peer:
3377323Sgblack@eecs.umich.edu            code('void getQueuesFromPeer(AbstractController *);')
3387323Sgblack@eecs.umich.edu        if self.EntryType != None:
3397323Sgblack@eecs.umich.edu            code('''
3407323Sgblack@eecs.umich.edu
3417323Sgblack@eecs.umich.edu// Set and Reset for cache_entry variable
3427323Sgblack@eecs.umich.eduvoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
3437323Sgblack@eecs.umich.eduvoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
3447321Sgblack@eecs.umich.edu''')
3457321Sgblack@eecs.umich.edu
3467321Sgblack@eecs.umich.edu        if self.TBEType != None:
3477335Sgblack@eecs.umich.edu            code('''
3487335Sgblack@eecs.umich.edu
3497335Sgblack@eecs.umich.edu// Set and Reset for tbe variable
3507335Sgblack@eecs.umich.eduvoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3517335Sgblack@eecs.umich.eduvoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3527335Sgblack@eecs.umich.edu''')
3537335Sgblack@eecs.umich.edu
3547335Sgblack@eecs.umich.edu        # Prototype the actions that the controller can take
3557335Sgblack@eecs.umich.edu        code('''
3567335Sgblack@eecs.umich.edu
3577335Sgblack@eecs.umich.edu// Actions
3587335Sgblack@eecs.umich.edu''')
3597335Sgblack@eecs.umich.edu        if self.TBEType != None and self.EntryType != None:
3607335Sgblack@eecs.umich.edu            for action in self.actions.itervalues():
3617335Sgblack@eecs.umich.edu                code('/** \\brief ${{action.desc}} */')
3627335Sgblack@eecs.umich.edu                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
3637335Sgblack@eecs.umich.edu                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
3647335Sgblack@eecs.umich.edu                     'm_cache_entry_ptr, const Address& addr);')
3657335Sgblack@eecs.umich.edu        elif self.TBEType != None:
3667335Sgblack@eecs.umich.edu            for action in self.actions.itervalues():
3677335Sgblack@eecs.umich.edu                code('/** \\brief ${{action.desc}} */')
3687335Sgblack@eecs.umich.edu                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
3697335Sgblack@eecs.umich.edu                     'm_tbe_ptr, const Address& addr);')
3707335Sgblack@eecs.umich.edu        elif self.EntryType != None:
3717335Sgblack@eecs.umich.edu            for action in self.actions.itervalues():
3727335Sgblack@eecs.umich.edu                code('/** \\brief ${{action.desc}} */')
3737335Sgblack@eecs.umich.edu                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
3747335Sgblack@eecs.umich.edu                     'm_cache_entry_ptr, const Address& addr);')
3757335Sgblack@eecs.umich.edu        else:
3767335Sgblack@eecs.umich.edu            for action in self.actions.itervalues():
3777335Sgblack@eecs.umich.edu                code('/** \\brief ${{action.desc}} */')
3787335Sgblack@eecs.umich.edu                code('void ${{action.ident}}(const Address& addr);')
3797335Sgblack@eecs.umich.edu
3807321Sgblack@eecs.umich.edu        # the controller internal variables
3817321Sgblack@eecs.umich.edu        code('''
3827321Sgblack@eecs.umich.edu
3837321Sgblack@eecs.umich.edu// Objects
3847321Sgblack@eecs.umich.edu''')
3857321Sgblack@eecs.umich.edu        for var in self.objects:
3867335Sgblack@eecs.umich.edu            th = var.get("template", "")
3877335Sgblack@eecs.umich.edu            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
3887335Sgblack@eecs.umich.edu
3897335Sgblack@eecs.umich.edu        code.dedent()
3907335Sgblack@eecs.umich.edu        code('};')
3917335Sgblack@eecs.umich.edu        code('#endif // __${ident}_CONTROLLER_H__')
3927335Sgblack@eecs.umich.edu        code.write(path, '%s.hh' % c_ident)
3937335Sgblack@eecs.umich.edu
3947335Sgblack@eecs.umich.edu    def printControllerCC(self, path, includes):
3957321Sgblack@eecs.umich.edu        '''Output the actions for performing the actions'''
3967326Sgblack@eecs.umich.edu
3977326Sgblack@eecs.umich.edu        code = self.symtab.codeFormatter()
3987326Sgblack@eecs.umich.edu        ident = self.ident
3997326Sgblack@eecs.umich.edu        c_ident = "%s_Controller" % self.ident
4007326Sgblack@eecs.umich.edu        has_peer = False
4017326Sgblack@eecs.umich.edu
4027326Sgblack@eecs.umich.edu        code('''
4037326Sgblack@eecs.umich.edu/** \\file $c_ident.cc
4047326Sgblack@eecs.umich.edu *
4057326Sgblack@eecs.umich.edu * Auto generated C++ code started by $__file__:$__line__
4067326Sgblack@eecs.umich.edu * Created by slicc definition of Module "${{self.short}}"
4077326Sgblack@eecs.umich.edu */
4087326Sgblack@eecs.umich.edu
4097326Sgblack@eecs.umich.edu#include <sys/types.h>
4107326Sgblack@eecs.umich.edu#include <unistd.h>
4117326Sgblack@eecs.umich.edu
4127326Sgblack@eecs.umich.edu#include <cassert>
4137326Sgblack@eecs.umich.edu#include <sstream>
4147326Sgblack@eecs.umich.edu#include <string>
4157326Sgblack@eecs.umich.edu
4167326Sgblack@eecs.umich.edu#include "base/compiler.hh"
4177326Sgblack@eecs.umich.edu#include "base/cprintf.hh"
4187392Sgblack@eecs.umich.edu#include "debug/RubyGenerated.hh"
4197392Sgblack@eecs.umich.edu#include "debug/RubySlicc.hh"
4207392Sgblack@eecs.umich.edu#include "mem/protocol/${ident}_Controller.hh"
4217392Sgblack@eecs.umich.edu#include "mem/protocol/${ident}_Event.hh"
4227392Sgblack@eecs.umich.edu#include "mem/protocol/${ident}_State.hh"
4237392Sgblack@eecs.umich.edu#include "mem/protocol/Types.hh"
4247392Sgblack@eecs.umich.edu#include "mem/ruby/common/Global.hh"
4257392Sgblack@eecs.umich.edu#include "mem/ruby/system/System.hh"
4267392Sgblack@eecs.umich.edu''')
4277392Sgblack@eecs.umich.edu        for include_path in includes:
4287392Sgblack@eecs.umich.edu            code('#include "${{include_path}}"')
4297321Sgblack@eecs.umich.edu
4307321Sgblack@eecs.umich.edu        code('''
4317335Sgblack@eecs.umich.edu
4327335Sgblack@eecs.umich.eduusing namespace std;
4337335Sgblack@eecs.umich.edu''')
4347335Sgblack@eecs.umich.edu
4357335Sgblack@eecs.umich.edu        # include object classes
4367335Sgblack@eecs.umich.edu        seen_types = set()
4377335Sgblack@eecs.umich.edu        for var in self.objects:
4387335Sgblack@eecs.umich.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
4397335Sgblack@eecs.umich.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
4407335Sgblack@eecs.umich.edu            seen_types.add(var.type.ident)
4417335Sgblack@eecs.umich.edu
4427335Sgblack@eecs.umich.edu        num_in_ports = len(self.in_ports)
4437335Sgblack@eecs.umich.edu
4447335Sgblack@eecs.umich.edu        code('''
4457335Sgblack@eecs.umich.edu$c_ident *
4467335Sgblack@eecs.umich.edu${c_ident}Params::create()
4477335Sgblack@eecs.umich.edu{
4487335Sgblack@eecs.umich.edu    return new $c_ident(this);
4497335Sgblack@eecs.umich.edu}
4507335Sgblack@eecs.umich.edu
4517335Sgblack@eecs.umich.eduint $c_ident::m_num_controllers = 0;
4527335Sgblack@eecs.umich.edustd::vector<Stats::Vector *>  $c_ident::eventVec;
4537335Sgblack@eecs.umich.edustd::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
4547335Sgblack@eecs.umich.edu
4557335Sgblack@eecs.umich.edu// for adding information to the protocol debug trace
4567335Sgblack@eecs.umich.edustringstream ${ident}_transitionComment;
4577335Sgblack@eecs.umich.edu
4587335Sgblack@eecs.umich.edu#ifndef NDEBUG
4597335Sgblack@eecs.umich.edu#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
4607335Sgblack@eecs.umich.edu#else
4617335Sgblack@eecs.umich.edu#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
4627335Sgblack@eecs.umich.edu#endif
4637335Sgblack@eecs.umich.edu
4647335Sgblack@eecs.umich.edu/** \\brief constructor */
4657335Sgblack@eecs.umich.edu$c_ident::$c_ident(const Params *p)
4667335Sgblack@eecs.umich.edu    : AbstractController(p)
4677335Sgblack@eecs.umich.edu{
4687335Sgblack@eecs.umich.edu    m_machineID.type = MachineType_${ident};
4697335Sgblack@eecs.umich.edu    m_machineID.num = m_version;
4707335Sgblack@eecs.umich.edu    m_num_controllers++;
4717335Sgblack@eecs.umich.edu
4727335Sgblack@eecs.umich.edu    m_in_ports = $num_in_ports;
4737335Sgblack@eecs.umich.edu''')
4747335Sgblack@eecs.umich.edu        code.indent()
4757321Sgblack@eecs.umich.edu
4767321Sgblack@eecs.umich.edu        #
4777321Sgblack@eecs.umich.edu        # After initializing the universal machine parameters, initialize the
4787321Sgblack@eecs.umich.edu        # this machines config parameters.  Also if these configuration params
4797321Sgblack@eecs.umich.edu        # include a sequencer, connect the it to the controller.
4807356Sgblack@eecs.umich.edu        #
4817356Sgblack@eecs.umich.edu        for param in self.config_parameters:
4827356Sgblack@eecs.umich.edu            if param.pointer:
4837356Sgblack@eecs.umich.edu                code('m_${{param.name}}_ptr = p->${{param.name}};')
4847356Sgblack@eecs.umich.edu            else:
4857356Sgblack@eecs.umich.edu                code('m_${{param.name}} = p->${{param.name}};')
4867363Sgblack@eecs.umich.edu            if re.compile("sequencer").search(param.name):
4877363Sgblack@eecs.umich.edu                code('m_${{param.name}}_ptr->setController(this);')
4887363Sgblack@eecs.umich.edu
4897363Sgblack@eecs.umich.edu        for var in self.objects:
4907363Sgblack@eecs.umich.edu            if var.ident.find("mandatoryQueue") >= 0:
4917363Sgblack@eecs.umich.edu                code('''
4927363Sgblack@eecs.umich.edum_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
4937363Sgblack@eecs.umich.edum_${{var.c_ident}}_ptr->setReceiver(this);
4947363Sgblack@eecs.umich.edu''')
4957363Sgblack@eecs.umich.edu            else:
4967363Sgblack@eecs.umich.edu                if "network" in var and "physical_network" in var and \
4977363Sgblack@eecs.umich.edu                   var["network"] == "To":
4987363Sgblack@eecs.umich.edu                    has_peer = True
4997363Sgblack@eecs.umich.edu                    code('''
5007372Sgblack@eecs.umich.edum_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
5017389Sgblack@eecs.umich.edupeerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
5027389Sgblack@eecs.umich.edum_${{var.c_ident}}_ptr->setSender(this);
5037372Sgblack@eecs.umich.edu''')
5047372Sgblack@eecs.umich.edu
5057372Sgblack@eecs.umich.edu        code('''
5067372Sgblack@eecs.umich.eduif (p->peer != NULL)
5077372Sgblack@eecs.umich.edu    connectWithPeer(p->peer);
5087372Sgblack@eecs.umich.edu
5097372Sgblack@eecs.umich.edufor (int state = 0; state < ${ident}_State_NUM; state++) {
5107372Sgblack@eecs.umich.edu    for (int event = 0; event < ${ident}_Event_NUM; event++) {
5117372Sgblack@eecs.umich.edu        m_possible[state][event] = false;
5127372Sgblack@eecs.umich.edu        m_counters[state][event] = 0;
5137372Sgblack@eecs.umich.edu    }
5147372Sgblack@eecs.umich.edu}
5157372Sgblack@eecs.umich.edufor (int event = 0; event < ${ident}_Event_NUM; event++) {
5167372Sgblack@eecs.umich.edu    m_event_counters[event] = 0;
5177372Sgblack@eecs.umich.edu}
5187372Sgblack@eecs.umich.edu''')
5197372Sgblack@eecs.umich.edu        code.dedent()
5207372Sgblack@eecs.umich.edu        code('''
5217363Sgblack@eecs.umich.edu}
5227363Sgblack@eecs.umich.edu
5237370Sgblack@eecs.umich.eduvoid
5247372Sgblack@eecs.umich.edu$c_ident::init()
5257376Sgblack@eecs.umich.edu{
5267376Sgblack@eecs.umich.edu    MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
5277370Sgblack@eecs.umich.edu    int base M5_VAR_USED = MachineType_base_number(machine_type);
5287376Sgblack@eecs.umich.edu
5297376Sgblack@eecs.umich.edu    // initialize objects
5307370Sgblack@eecs.umich.edu
5317370Sgblack@eecs.umich.edu''')
5327372Sgblack@eecs.umich.edu
5337376Sgblack@eecs.umich.edu        code.indent()
5347376Sgblack@eecs.umich.edu        for var in self.objects:
5357370Sgblack@eecs.umich.edu            vtype = var.type
5367376Sgblack@eecs.umich.edu            vid = "m_%s_ptr" % var.c_ident
5377376Sgblack@eecs.umich.edu            if "network" not in var:
5387370Sgblack@eecs.umich.edu                # Not a network port object
5397370Sgblack@eecs.umich.edu                if "primitive" in vtype:
5407371Sgblack@eecs.umich.edu                    code('$vid = new ${{vtype.c_ident}};')
5417371Sgblack@eecs.umich.edu                    if "default" in var:
5427372Sgblack@eecs.umich.edu                        code('(*$vid) = ${{var["default"]}};')
5437376Sgblack@eecs.umich.edu                else:
5447376Sgblack@eecs.umich.edu                    # Normal Object
5457371Sgblack@eecs.umich.edu                    if var.ident.find("mandatoryQueue") < 0:
5467376Sgblack@eecs.umich.edu                        th = var.get("template", "")
5477376Sgblack@eecs.umich.edu                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
5487371Sgblack@eecs.umich.edu                        args = ""
5497371Sgblack@eecs.umich.edu                        if "non_obj" not in vtype and not vtype.isEnumeration:
5507372Sgblack@eecs.umich.edu                            args = var.get("constructor", "")
5517376Sgblack@eecs.umich.edu                        code('$expr($args);')
5527376Sgblack@eecs.umich.edu
5537371Sgblack@eecs.umich.edu                    code('assert($vid != NULL);')
5547376Sgblack@eecs.umich.edu
5557376Sgblack@eecs.umich.edu                    if "default" in var:
5567371Sgblack@eecs.umich.edu                        code('*$vid = ${{var["default"]}}; // Object default')
5577371Sgblack@eecs.umich.edu                    elif "default" in vtype:
5587363Sgblack@eecs.umich.edu                        comment = "Type %s default" % vtype.ident
5597363Sgblack@eecs.umich.edu                        code('*$vid = ${{vtype["default"]}}; // $comment')
5607372Sgblack@eecs.umich.edu
5617376Sgblack@eecs.umich.edu                    # Set ordering
5627376Sgblack@eecs.umich.edu                    if "ordered" in var:
5637364Sgblack@eecs.umich.edu                        # A buffer
5647376Sgblack@eecs.umich.edu                        code('$vid->setOrdering(${{var["ordered"]}});')
5657376Sgblack@eecs.umich.edu
5667364Sgblack@eecs.umich.edu                    # Set randomization
5677371Sgblack@eecs.umich.edu                    if "random" in var:
5687372Sgblack@eecs.umich.edu                        # A buffer
5697376Sgblack@eecs.umich.edu                        code('$vid->setRandomization(${{var["random"]}});')
5707376Sgblack@eecs.umich.edu
5717371Sgblack@eecs.umich.edu                    # Set Priority
5727376Sgblack@eecs.umich.edu                    if vtype.isBuffer and "rank" in var:
5737376Sgblack@eecs.umich.edu                        code('$vid->setPriority(${{var["rank"]}});')
5747371Sgblack@eecs.umich.edu
5757363Sgblack@eecs.umich.edu                    # Set sender and receiver for trigger queue
5767363Sgblack@eecs.umich.edu                    if var.ident.find("triggerQueue") >= 0:
5777363Sgblack@eecs.umich.edu                        code('$vid->setSender(this);')
5787372Sgblack@eecs.umich.edu                        code('$vid->setReceiver(this);')
5797376Sgblack@eecs.umich.edu                    elif vtype.c_ident == "TimerTable":
5807376Sgblack@eecs.umich.edu                        code('$vid->setClockObj(this);')
5817367Sgblack@eecs.umich.edu                    elif var.ident.find("optionalQueue") >= 0:
5827376Sgblack@eecs.umich.edu                        code('$vid->setSender(this);')
5837376Sgblack@eecs.umich.edu                        code('$vid->setReceiver(this);')
5847367Sgblack@eecs.umich.edu
5857363Sgblack@eecs.umich.edu            else:
5867372Sgblack@eecs.umich.edu                # Network port object
5877376Sgblack@eecs.umich.edu                network = var["network"]
5887376Sgblack@eecs.umich.edu                ordered =  var["ordered"]
5897368Sgblack@eecs.umich.edu
5907376Sgblack@eecs.umich.edu                if "virtual_network" in var:
5917376Sgblack@eecs.umich.edu                    vnet = var["virtual_network"]
5927368Sgblack@eecs.umich.edu                    vnet_type = var["vnet_type"]
5937363Sgblack@eecs.umich.edu
5947363Sgblack@eecs.umich.edu                    assert var.machine is not None
5957363Sgblack@eecs.umich.edu                    code('''
5967372Sgblack@eecs.umich.edu$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
5977376Sgblack@eecs.umich.eduassert($vid != NULL);
5987376Sgblack@eecs.umich.edu''')
5997369Sgblack@eecs.umich.edu
6007376Sgblack@eecs.umich.edu                    # Set the end
6017376Sgblack@eecs.umich.edu                    if network == "To":
6027369Sgblack@eecs.umich.edu                        code('$vid->setSender(this);')
6037363Sgblack@eecs.umich.edu                    else:
6047363Sgblack@eecs.umich.edu                        code('$vid->setReceiver(this);')
6057363Sgblack@eecs.umich.edu
6067363Sgblack@eecs.umich.edu                # Set ordering
6077363Sgblack@eecs.umich.edu                if "ordered" in var:
6087363Sgblack@eecs.umich.edu                    # A buffer
6097372Sgblack@eecs.umich.edu                    code('$vid->setOrdering(${{var["ordered"]}});')
6107363Sgblack@eecs.umich.edu
6117376Sgblack@eecs.umich.edu                # Set randomization
6127376Sgblack@eecs.umich.edu                if "random" in var:
6137363Sgblack@eecs.umich.edu                    # A buffer
6147363Sgblack@eecs.umich.edu                    code('$vid->setRandomization(${{var["random"]}});')
6157376Sgblack@eecs.umich.edu
6167376Sgblack@eecs.umich.edu                # Set Priority
6177363Sgblack@eecs.umich.edu                if "rank" in var:
6187363Sgblack@eecs.umich.edu                    code('$vid->setPriority(${{var["rank"]}})')
6197363Sgblack@eecs.umich.edu
6207363Sgblack@eecs.umich.edu                # Set buffer size
6217363Sgblack@eecs.umich.edu                if vtype.isBuffer:
6227372Sgblack@eecs.umich.edu                    code('''
6237376Sgblack@eecs.umich.eduif (m_buffer_size > 0) {
6247376Sgblack@eecs.umich.edu    $vid->resize(m_buffer_size);
6257363Sgblack@eecs.umich.edu}
6267376Sgblack@eecs.umich.edu''')
6277376Sgblack@eecs.umich.edu
6287363Sgblack@eecs.umich.edu                # set description (may be overriden later by port def)
6297363Sgblack@eecs.umich.edu                code('''
6307372Sgblack@eecs.umich.edu$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
6317376Sgblack@eecs.umich.edu
6327376Sgblack@eecs.umich.edu''')
6337366Sgblack@eecs.umich.edu
6347376Sgblack@eecs.umich.edu            if vtype.isBuffer:
6357376Sgblack@eecs.umich.edu                if "recycle_latency" in var:
6367366Sgblack@eecs.umich.edu                    code('$vid->setRecycleLatency( ' \
6377363Sgblack@eecs.umich.edu                         'Cycles(${{var["recycle_latency"]}}));')
6387363Sgblack@eecs.umich.edu                else:
6397363Sgblack@eecs.umich.edu                    code('$vid->setRecycleLatency(m_recycle_latency);')
6407372Sgblack@eecs.umich.edu
6417376Sgblack@eecs.umich.edu        # Set the prefetchers
6427376Sgblack@eecs.umich.edu        code()
6437365Sgblack@eecs.umich.edu        for prefetcher in self.prefetchers:
6447376Sgblack@eecs.umich.edu            code('${{prefetcher.code}}.setController(this);')
6457376Sgblack@eecs.umich.edu
6467365Sgblack@eecs.umich.edu        code()
6477363Sgblack@eecs.umich.edu        for port in self.in_ports:
6487372Sgblack@eecs.umich.edu            # Set the queue consumers
6497376Sgblack@eecs.umich.edu            code('${{port.code}}.setConsumer(this);')
6507376Sgblack@eecs.umich.edu            # Set the queue descriptions
6517369Sgblack@eecs.umich.edu            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
6527376Sgblack@eecs.umich.edu
6537376Sgblack@eecs.umich.edu        # Initialize the transition profiling
6547369Sgblack@eecs.umich.edu        code()
6557363Sgblack@eecs.umich.edu        for trans in self.transitions:
6567363Sgblack@eecs.umich.edu            # Figure out if we stall
6577363Sgblack@eecs.umich.edu            stall = False
6587398Sgblack@eecs.umich.edu            for action in trans.actions:
6597398Sgblack@eecs.umich.edu                if action.ident == "z_stall":
6607398Sgblack@eecs.umich.edu                    stall = True
6617398Sgblack@eecs.umich.edu
6627398Sgblack@eecs.umich.edu            # Only possible if it is not a 'z' case
6637398Sgblack@eecs.umich.edu            if not stall:
6647398Sgblack@eecs.umich.edu                state = "%s_State_%s" % (self.ident, trans.state.ident)
6657398Sgblack@eecs.umich.edu                event = "%s_Event_%s" % (self.ident, trans.event.ident)
6667398Sgblack@eecs.umich.edu                code('possibleTransition($state, $event);')
6677398Sgblack@eecs.umich.edu
6687398Sgblack@eecs.umich.edu        code.dedent()
6697398Sgblack@eecs.umich.edu        code('''
6707398Sgblack@eecs.umich.edu    AbstractController::init();
6717398Sgblack@eecs.umich.edu    resetStats();
6727398Sgblack@eecs.umich.edu}
6737398Sgblack@eecs.umich.edu''')
6747398Sgblack@eecs.umich.edu
6757363Sgblack@eecs.umich.edu        mq_ident = "NULL"
6767377Sgblack@eecs.umich.edu        for port in self.in_ports:
6777389Sgblack@eecs.umich.edu            if port.code.find("mandatoryQueue_ptr") >= 0:
6787389Sgblack@eecs.umich.edu                mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
6797389Sgblack@eecs.umich.edu
6807389Sgblack@eecs.umich.edu        seq_ident = "NULL"
6817389Sgblack@eecs.umich.edu        for param in self.config_parameters:
6827377Sgblack@eecs.umich.edu            if param.name == "sequencer":
6837389Sgblack@eecs.umich.edu                assert(param.pointer)
6847389Sgblack@eecs.umich.edu                seq_ident = "m_%s_ptr" % param.name
6857389Sgblack@eecs.umich.edu
6867389Sgblack@eecs.umich.edu        code('''
6877389Sgblack@eecs.umich.edu
6887377Sgblack@eecs.umich.eduvoid
6897363Sgblack@eecs.umich.edu$c_ident::regStats()
6907377Sgblack@eecs.umich.edu{
6917389Sgblack@eecs.umich.edu    AbstractController::regStats();
6927389Sgblack@eecs.umich.edu
6937389Sgblack@eecs.umich.edu    if (m_version == 0) {
6947389Sgblack@eecs.umich.edu        for (${ident}_Event event = ${ident}_Event_FIRST;
6957389Sgblack@eecs.umich.edu             event < ${ident}_Event_NUM; ++event) {
6967377Sgblack@eecs.umich.edu            Stats::Vector *t = new Stats::Vector();
6977389Sgblack@eecs.umich.edu            t->init(m_num_controllers);
6987389Sgblack@eecs.umich.edu            t->name(g_system_ptr->name() + ".${c_ident}." +
6997389Sgblack@eecs.umich.edu                ${ident}_Event_to_string(event));
7007389Sgblack@eecs.umich.edu            t->flags(Stats::pdf | Stats::total | Stats::oneline |
7017389Sgblack@eecs.umich.edu                     Stats::nozero);
7027377Sgblack@eecs.umich.edu
7037363Sgblack@eecs.umich.edu            eventVec.push_back(t);
7047363Sgblack@eecs.umich.edu        }
7057374Sgblack@eecs.umich.edu
7067374Sgblack@eecs.umich.edu        for (${ident}_State state = ${ident}_State_FIRST;
7077374Sgblack@eecs.umich.edu             state < ${ident}_State_NUM; ++state) {
7087374Sgblack@eecs.umich.edu
7097374Sgblack@eecs.umich.edu            transVec.push_back(std::vector<Stats::Vector *>());
7107374Sgblack@eecs.umich.edu
7117374Sgblack@eecs.umich.edu            for (${ident}_Event event = ${ident}_Event_FIRST;
7127374Sgblack@eecs.umich.edu                 event < ${ident}_Event_NUM; ++event) {
7137374Sgblack@eecs.umich.edu
7147363Sgblack@eecs.umich.edu                Stats::Vector *t = new Stats::Vector();
7157363Sgblack@eecs.umich.edu                t->init(m_num_controllers);
7167363Sgblack@eecs.umich.edu                t->name(g_system_ptr->name() + ".${c_ident}." +
7177373Sgblack@eecs.umich.edu                        ${ident}_State_to_string(state) +
7187373Sgblack@eecs.umich.edu                        "." + ${ident}_Event_to_string(event));
7197373Sgblack@eecs.umich.edu
7207373Sgblack@eecs.umich.edu                t->flags(Stats::pdf | Stats::total | Stats::oneline |
7217373Sgblack@eecs.umich.edu                         Stats::nozero);
7227373Sgblack@eecs.umich.edu                transVec[state].push_back(t);
7237373Sgblack@eecs.umich.edu            }
7247373Sgblack@eecs.umich.edu        }
7257373Sgblack@eecs.umich.edu    }
7267373Sgblack@eecs.umich.edu}
7277373Sgblack@eecs.umich.edu
7287373Sgblack@eecs.umich.eduvoid
7297373Sgblack@eecs.umich.edu$c_ident::collateStats()
7307373Sgblack@eecs.umich.edu{
7317373Sgblack@eecs.umich.edu    for (${ident}_Event event = ${ident}_Event_FIRST;
7327373Sgblack@eecs.umich.edu         event < ${ident}_Event_NUM; ++event) {
7337373Sgblack@eecs.umich.edu        for (unsigned int i = 0; i < m_num_controllers; ++i) {
7347363Sgblack@eecs.umich.edu            std::map<uint32_t, AbstractController *>::iterator it =
7357379Sgblack@eecs.umich.edu                                g_abs_controls[MachineType_${ident}].find(i);
7367379Sgblack@eecs.umich.edu            assert(it != g_abs_controls[MachineType_${ident}].end());
7377379Sgblack@eecs.umich.edu            (*eventVec[event])[i] =
7387379Sgblack@eecs.umich.edu                (($c_ident *)(*it).second)->getEventCount(event);
7397379Sgblack@eecs.umich.edu        }
7407379Sgblack@eecs.umich.edu    }
7417379Sgblack@eecs.umich.edu
7427379Sgblack@eecs.umich.edu    for (${ident}_State state = ${ident}_State_FIRST;
7437379Sgblack@eecs.umich.edu         state < ${ident}_State_NUM; ++state) {
7447379Sgblack@eecs.umich.edu
7457379Sgblack@eecs.umich.edu        for (${ident}_Event event = ${ident}_Event_FIRST;
7467379Sgblack@eecs.umich.edu             event < ${ident}_Event_NUM; ++event) {
7477379Sgblack@eecs.umich.edu
7487379Sgblack@eecs.umich.edu            for (unsigned int i = 0; i < m_num_controllers; ++i) {
7497379Sgblack@eecs.umich.edu                std::map<uint32_t, AbstractController *>::iterator it =
7507379Sgblack@eecs.umich.edu                                g_abs_controls[MachineType_${ident}].find(i);
7517379Sgblack@eecs.umich.edu                assert(it != g_abs_controls[MachineType_${ident}].end());
7527379Sgblack@eecs.umich.edu                (*transVec[state][event])[i] =
7537379Sgblack@eecs.umich.edu                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
7547379Sgblack@eecs.umich.edu            }
7557363Sgblack@eecs.umich.edu        }
7567379Sgblack@eecs.umich.edu    }
7577379Sgblack@eecs.umich.edu}
7587379Sgblack@eecs.umich.edu
7597379Sgblack@eecs.umich.eduvoid
7607379Sgblack@eecs.umich.edu$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
7617379Sgblack@eecs.umich.edu{
7627379Sgblack@eecs.umich.edu    assert(m_possible[state][event]);
7637379Sgblack@eecs.umich.edu    m_counters[state][event]++;
7647379Sgblack@eecs.umich.edu    m_event_counters[event]++;
7657379Sgblack@eecs.umich.edu}
7667379Sgblack@eecs.umich.eduvoid
7677379Sgblack@eecs.umich.edu$c_ident::possibleTransition(${ident}_State state,
7687379Sgblack@eecs.umich.edu                             ${ident}_Event event)
7697379Sgblack@eecs.umich.edu{
7707379Sgblack@eecs.umich.edu    m_possible[state][event] = true;
7717379Sgblack@eecs.umich.edu}
7727379Sgblack@eecs.umich.edu
7737379Sgblack@eecs.umich.eduuint64
7747379Sgblack@eecs.umich.edu$c_ident::getEventCount(${ident}_Event event)
7757379Sgblack@eecs.umich.edu{
7767363Sgblack@eecs.umich.edu    return m_event_counters[event];
7777380Sgblack@eecs.umich.edu}
7787380Sgblack@eecs.umich.edu
7797380Sgblack@eecs.umich.edubool
7807380Sgblack@eecs.umich.edu$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
7817380Sgblack@eecs.umich.edu{
7827380Sgblack@eecs.umich.edu    return m_possible[state][event];
7837380Sgblack@eecs.umich.edu}
7847380Sgblack@eecs.umich.edu
7857373Sgblack@eecs.umich.eduuint64
7867380Sgblack@eecs.umich.edu$c_ident::getTransitionCount(${ident}_State state,
7877380Sgblack@eecs.umich.edu                             ${ident}_Event event)
7887380Sgblack@eecs.umich.edu{
7897380Sgblack@eecs.umich.edu    return m_counters[state][event];
7907380Sgblack@eecs.umich.edu}
7917380Sgblack@eecs.umich.edu
7927380Sgblack@eecs.umich.eduint
7937373Sgblack@eecs.umich.edu$c_ident::getNumControllers()
7947363Sgblack@eecs.umich.edu{
7957380Sgblack@eecs.umich.edu    return m_num_controllers;
7967380Sgblack@eecs.umich.edu}
7977380Sgblack@eecs.umich.edu
7987380Sgblack@eecs.umich.eduMessageBuffer*
7997380Sgblack@eecs.umich.edu$c_ident::getMandatoryQueue() const
8007380Sgblack@eecs.umich.edu{
8017380Sgblack@eecs.umich.edu    return $mq_ident;
8027380Sgblack@eecs.umich.edu}
8037373Sgblack@eecs.umich.edu
8047380Sgblack@eecs.umich.eduSequencer*
8057380Sgblack@eecs.umich.edu$c_ident::getSequencer() const
8067380Sgblack@eecs.umich.edu{
8077380Sgblack@eecs.umich.edu    return $seq_ident;
8087380Sgblack@eecs.umich.edu}
8097380Sgblack@eecs.umich.edu
8107380Sgblack@eecs.umich.educonst string
8117373Sgblack@eecs.umich.edu$c_ident::toString() const
8127363Sgblack@eecs.umich.edu{
8137379Sgblack@eecs.umich.edu    return "$c_ident";
8147379Sgblack@eecs.umich.edu}
8157379Sgblack@eecs.umich.edu
8167379Sgblack@eecs.umich.eduvoid
8177379Sgblack@eecs.umich.edu$c_ident::print(ostream& out) const
8187379Sgblack@eecs.umich.edu{
8197379Sgblack@eecs.umich.edu    out << "[$c_ident " << m_version << "]";
8207379Sgblack@eecs.umich.edu}
8217379Sgblack@eecs.umich.edu
8227379Sgblack@eecs.umich.eduvoid $c_ident::resetStats()
8237379Sgblack@eecs.umich.edu{
8247379Sgblack@eecs.umich.edu    for (int state = 0; state < ${ident}_State_NUM; state++) {
8257379Sgblack@eecs.umich.edu        for (int event = 0; event < ${ident}_Event_NUM; event++) {
8267379Sgblack@eecs.umich.edu            m_counters[state][event] = 0;
8277379Sgblack@eecs.umich.edu        }
8287379Sgblack@eecs.umich.edu    }
8297379Sgblack@eecs.umich.edu
8307379Sgblack@eecs.umich.edu    for (int event = 0; event < ${ident}_Event_NUM; event++) {
8317379Sgblack@eecs.umich.edu        m_event_counters[event] = 0;
8327379Sgblack@eecs.umich.edu    }
8337363Sgblack@eecs.umich.edu
8347379Sgblack@eecs.umich.edu    AbstractController::resetStats();
8357379Sgblack@eecs.umich.edu}
8367379Sgblack@eecs.umich.edu''')
8377379Sgblack@eecs.umich.edu
8387379Sgblack@eecs.umich.edu        if self.EntryType != None:
8397379Sgblack@eecs.umich.edu            code('''
8407379Sgblack@eecs.umich.edu
8417379Sgblack@eecs.umich.edu// Set and Reset for cache_entry variable
8427379Sgblack@eecs.umich.eduvoid
8437379Sgblack@eecs.umich.edu$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
8447379Sgblack@eecs.umich.edu{
8457379Sgblack@eecs.umich.edu  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
8467379Sgblack@eecs.umich.edu}
8477379Sgblack@eecs.umich.edu
8487379Sgblack@eecs.umich.eduvoid
8497379Sgblack@eecs.umich.edu$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
8507379Sgblack@eecs.umich.edu{
8517379Sgblack@eecs.umich.edu  m_cache_entry_ptr = 0;
8527379Sgblack@eecs.umich.edu}
8537379Sgblack@eecs.umich.edu''')
8547363Sgblack@eecs.umich.edu
8557363Sgblack@eecs.umich.edu        if self.TBEType != None:
8567363Sgblack@eecs.umich.edu            code('''
8577363Sgblack@eecs.umich.edu
8587363Sgblack@eecs.umich.edu// Set and Reset for tbe variable
8597363Sgblack@eecs.umich.eduvoid
8607363Sgblack@eecs.umich.edu$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
8617363Sgblack@eecs.umich.edu{
8627363Sgblack@eecs.umich.edu  m_tbe_ptr = m_new_tbe;
8637363Sgblack@eecs.umich.edu}
8647363Sgblack@eecs.umich.edu
8657363Sgblack@eecs.umich.eduvoid
8667363Sgblack@eecs.umich.edu$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
867{
868  m_tbe_ptr = NULL;
869}
870''')
871
872        code('''
873
874void
875$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
876{
877''')
878        #
879        # Record cache contents for all associated caches.
880        #
881        code.indent()
882        for param in self.config_parameters:
883            if param.type_ast.type.ident == "CacheMemory":
884                assert(param.pointer)
885                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
886
887        code.dedent()
888        code('''
889}
890
891// Actions
892''')
893        if self.TBEType != None and self.EntryType != None:
894            for action in self.actions.itervalues():
895                if "c_code" not in action:
896                 continue
897
898                code('''
899/** \\brief ${{action.desc}} */
900void
901$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
902{
903    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
904    ${{action["c_code"]}}
905}
906
907''')
908        elif self.TBEType != None:
909            for action in self.actions.itervalues():
910                if "c_code" not in action:
911                 continue
912
913                code('''
914/** \\brief ${{action.desc}} */
915void
916$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
917{
918    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
919    ${{action["c_code"]}}
920}
921
922''')
923        elif self.EntryType != None:
924            for action in self.actions.itervalues():
925                if "c_code" not in action:
926                 continue
927
928                code('''
929/** \\brief ${{action.desc}} */
930void
931$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
932{
933    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
934    ${{action["c_code"]}}
935}
936
937''')
938        else:
939            for action in self.actions.itervalues():
940                if "c_code" not in action:
941                 continue
942
943                code('''
944/** \\brief ${{action.desc}} */
945void
946$c_ident::${{action.ident}}(const Address& addr)
947{
948    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
949    ${{action["c_code"]}}
950}
951
952''')
953        for func in self.functions:
954            code(func.generateCode())
955
956        # Function for functional reads from messages buffered in the controller
957        code('''
958bool
959$c_ident::functionalReadBuffers(PacketPtr& pkt)
960{
961''')
962        for var in self.objects:
963            vtype = var.type
964            if vtype.isBuffer:
965                vid = "m_%s_ptr" % var.c_ident
966                code('if ($vid->functionalRead(pkt)) { return true; }')
967        code('''
968                return false;
969}
970''')
971
972        # Function for functional writes to messages buffered in the controller
973        code('''
974uint32_t
975$c_ident::functionalWriteBuffers(PacketPtr& pkt)
976{
977    uint32_t num_functional_writes = 0;
978''')
979        for var in self.objects:
980            vtype = var.type
981            if vtype.isBuffer:
982                vid = "m_%s_ptr" % var.c_ident
983                code('num_functional_writes += $vid->functionalWrite(pkt);')
984        code('''
985    return num_functional_writes;
986}
987''')
988
989        # Check if this controller has a peer, if yes then write the
990        # function for connecting to the peer.
991        if has_peer:
992            code('''
993
994void
995$c_ident::getQueuesFromPeer(AbstractController *peer)
996{
997''')
998            for var in self.objects:
999                if "network" in var and "physical_network" in var and \
1000                   var["network"] == "From":
1001                    code('''
1002m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1003assert(m_${{var.c_ident}}_ptr != NULL);
1004m_${{var.c_ident}}_ptr->setReceiver(this);
1005
1006''')
1007            code('}')
1008
1009        code.write(path, "%s.cc" % c_ident)
1010
1011    def printCWakeup(self, path, includes):
1012        '''Output the wakeup loop for the events'''
1013
1014        code = self.symtab.codeFormatter()
1015        ident = self.ident
1016
1017        outputRequest_types = True
1018        if len(self.request_types) == 0:
1019            outputRequest_types = False
1020
1021        code('''
1022// Auto generated C++ code started by $__file__:$__line__
1023// ${ident}: ${{self.short}}
1024
1025#include <sys/types.h>
1026#include <unistd.h>
1027
1028#include <cassert>
1029
1030#include "base/misc.hh"
1031#include "debug/RubySlicc.hh"
1032#include "mem/protocol/${ident}_Controller.hh"
1033#include "mem/protocol/${ident}_Event.hh"
1034#include "mem/protocol/${ident}_State.hh"
1035''')
1036
1037        if outputRequest_types:
1038            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1039
1040        code('''
1041#include "mem/protocol/Types.hh"
1042#include "mem/ruby/common/Global.hh"
1043#include "mem/ruby/system/System.hh"
1044''')
1045
1046
1047        for include_path in includes:
1048            code('#include "${{include_path}}"')
1049
1050        code('''
1051
1052using namespace std;
1053
1054void
1055${ident}_Controller::wakeup()
1056{
1057    int counter = 0;
1058    while (true) {
1059        // Some cases will put us into an infinite loop without this limit
1060        assert(counter <= m_transitions_per_cycle);
1061        if (counter == m_transitions_per_cycle) {
1062            // Count how often we are fully utilized
1063            m_fully_busy_cycles++;
1064
1065            // Wakeup in another cycle and try again
1066            scheduleEvent(Cycles(1));
1067            break;
1068        }
1069''')
1070
1071        code.indent()
1072        code.indent()
1073
1074        # InPorts
1075        #
1076        for port in self.in_ports:
1077            code.indent()
1078            code('// ${ident}InPort $port')
1079            if port.pairs.has_key("rank"):
1080                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1081            else:
1082                code('m_cur_in_port = 0;')
1083            code('${{port["c_code_in_port"]}}')
1084            code.dedent()
1085
1086            code('')
1087
1088        code.dedent()
1089        code.dedent()
1090        code('''
1091        break;  // If we got this far, we have nothing left todo
1092    }
1093}
1094''')
1095
1096        code.write(path, "%s_Wakeup.cc" % self.ident)
1097
1098    def printCSwitch(self, path):
1099        '''Output switch statement for transition table'''
1100
1101        code = self.symtab.codeFormatter()
1102        ident = self.ident
1103
1104        code('''
1105// Auto generated C++ code started by $__file__:$__line__
1106// ${ident}: ${{self.short}}
1107
1108#include <cassert>
1109
1110#include "base/misc.hh"
1111#include "base/trace.hh"
1112#include "debug/ProtocolTrace.hh"
1113#include "debug/RubyGenerated.hh"
1114#include "mem/protocol/${ident}_Controller.hh"
1115#include "mem/protocol/${ident}_Event.hh"
1116#include "mem/protocol/${ident}_State.hh"
1117#include "mem/protocol/Types.hh"
1118#include "mem/ruby/common/Global.hh"
1119#include "mem/ruby/system/System.hh"
1120
1121#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1122
1123#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1124#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1125
1126TransitionResult
1127${ident}_Controller::doTransition(${ident}_Event event,
1128''')
1129        if self.EntryType != None:
1130            code('''
1131                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1132''')
1133        if self.TBEType != None:
1134            code('''
1135                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1136''')
1137        code('''
1138                                  const Address addr)
1139{
1140''')
1141        if self.TBEType != None and self.EntryType != None:
1142            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1143        elif self.TBEType != None:
1144            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1145        elif self.EntryType != None:
1146            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1147        else:
1148            code('${ident}_State state = getState(addr);')
1149
1150        code('''
1151    ${ident}_State next_state = state;
1152
1153    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1154            *this, curCycle(), ${ident}_State_to_string(state),
1155            ${ident}_Event_to_string(event), addr);
1156
1157    TransitionResult result =
1158''')
1159        if self.TBEType != None and self.EntryType != None:
1160            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1161        elif self.TBEType != None:
1162            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1163        elif self.EntryType != None:
1164            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1165        else:
1166            code('doTransitionWorker(event, state, next_state, addr);')
1167
1168        code('''
1169    if (result == TransitionResult_Valid) {
1170        DPRINTF(RubyGenerated, "next_state: %s\\n",
1171                ${ident}_State_to_string(next_state));
1172        countTransition(state, event);
1173        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1174                 curTick(), m_version, "${ident}",
1175                 ${ident}_Event_to_string(event),
1176                 ${ident}_State_to_string(state),
1177                 ${ident}_State_to_string(next_state),
1178                 addr, GET_TRANSITION_COMMENT());
1179
1180        CLEAR_TRANSITION_COMMENT();
1181''')
1182        if self.TBEType != None and self.EntryType != None:
1183            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1184            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1185        elif self.TBEType != None:
1186            code('setState(m_tbe_ptr, addr, next_state);')
1187            code('setAccessPermission(addr, next_state);')
1188        elif self.EntryType != None:
1189            code('setState(m_cache_entry_ptr, addr, next_state);')
1190            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1191        else:
1192            code('setState(addr, next_state);')
1193            code('setAccessPermission(addr, next_state);')
1194
1195        code('''
1196    } else if (result == TransitionResult_ResourceStall) {
1197        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1198                 curTick(), m_version, "${ident}",
1199                 ${ident}_Event_to_string(event),
1200                 ${ident}_State_to_string(state),
1201                 ${ident}_State_to_string(next_state),
1202                 addr, "Resource Stall");
1203    } else if (result == TransitionResult_ProtocolStall) {
1204        DPRINTF(RubyGenerated, "stalling\\n");
1205        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1206                 curTick(), m_version, "${ident}",
1207                 ${ident}_Event_to_string(event),
1208                 ${ident}_State_to_string(state),
1209                 ${ident}_State_to_string(next_state),
1210                 addr, "Protocol Stall");
1211    }
1212
1213    return result;
1214}
1215
1216TransitionResult
1217${ident}_Controller::doTransitionWorker(${ident}_Event event,
1218                                        ${ident}_State state,
1219                                        ${ident}_State& next_state,
1220''')
1221
1222        if self.TBEType != None:
1223            code('''
1224                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1225''')
1226        if self.EntryType != None:
1227                  code('''
1228                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1229''')
1230        code('''
1231                                        const Address& addr)
1232{
1233    switch(HASH_FUN(state, event)) {
1234''')
1235
1236        # This map will allow suppress generating duplicate code
1237        cases = orderdict()
1238
1239        for trans in self.transitions:
1240            case_string = "%s_State_%s, %s_Event_%s" % \
1241                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1242
1243            case = self.symtab.codeFormatter()
1244            # Only set next_state if it changes
1245            if trans.state != trans.nextState:
1246                ns_ident = trans.nextState.ident
1247                case('next_state = ${ident}_State_${ns_ident};')
1248
1249            actions = trans.actions
1250            request_types = trans.request_types
1251
1252            # Check for resources
1253            case_sorter = []
1254            res = trans.resources
1255            for key,val in res.iteritems():
1256                if key.type.ident != "DNUCAStopTable":
1257                    val = '''
1258if (!%s.areNSlotsAvailable(%s))
1259    return TransitionResult_ResourceStall;
1260''' % (key.code, val)
1261                case_sorter.append(val)
1262
1263            # Check all of the request_types for resource constraints
1264            for request_type in request_types:
1265                val = '''
1266if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1267    return TransitionResult_ResourceStall;
1268}
1269''' % (self.ident, request_type.ident)
1270                case_sorter.append(val)
1271
1272            # Emit the code sequences in a sorted order.  This makes the
1273            # output deterministic (without this the output order can vary
1274            # since Map's keys() on a vector of pointers is not deterministic
1275            for c in sorted(case_sorter):
1276                case("$c")
1277
1278            # Record access types for this transition
1279            for request_type in request_types:
1280                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1281
1282            # Figure out if we stall
1283            stall = False
1284            for action in actions:
1285                if action.ident == "z_stall":
1286                    stall = True
1287                    break
1288
1289            if stall:
1290                case('return TransitionResult_ProtocolStall;')
1291            else:
1292                if self.TBEType != None and self.EntryType != None:
1293                    for action in actions:
1294                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1295                elif self.TBEType != None:
1296                    for action in actions:
1297                        case('${{action.ident}}(m_tbe_ptr, addr);')
1298                elif self.EntryType != None:
1299                    for action in actions:
1300                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1301                else:
1302                    for action in actions:
1303                        case('${{action.ident}}(addr);')
1304                case('return TransitionResult_Valid;')
1305
1306            case = str(case)
1307
1308            # Look to see if this transition code is unique.
1309            if case not in cases:
1310                cases[case] = []
1311
1312            cases[case].append(case_string)
1313
1314        # Walk through all of the unique code blocks and spit out the
1315        # corresponding case statement elements
1316        for case,transitions in cases.iteritems():
1317            # Iterative over all the multiple transitions that share
1318            # the same code
1319            for trans in transitions:
1320                code('  case HASH_FUN($trans):')
1321            code('    $case')
1322
1323        code('''
1324      default:
1325        fatal("Invalid transition\\n"
1326              "%s time: %d addr: %s event: %s state: %s\\n",
1327              name(), curCycle(), addr, event, state);
1328    }
1329    return TransitionResult_Valid;
1330}
1331''')
1332        code.write(path, "%s_Transitions.cc" % self.ident)
1333
1334
1335    # **************************
1336    # ******* HTML Files *******
1337    # **************************
1338    def frameRef(self, click_href, click_target, over_href, over_num, text):
1339        code = self.symtab.codeFormatter(fix_newlines=False)
1340        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1341    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1342        parent.frames[$over_num].location='$over_href'
1343    }\">
1344    ${{html.formatShorthand(text)}}
1345    </A>""")
1346        return str(code)
1347
1348    def writeHTMLFiles(self, path):
1349        # Create table with no row hilighted
1350        self.printHTMLTransitions(path, None)
1351
1352        # Generate transition tables
1353        for state in self.states.itervalues():
1354            self.printHTMLTransitions(path, state)
1355
1356        # Generate action descriptions
1357        for action in self.actions.itervalues():
1358            name = "%s_action_%s.html" % (self.ident, action.ident)
1359            code = html.createSymbol(action, "Action")
1360            code.write(path, name)
1361
1362        # Generate state descriptions
1363        for state in self.states.itervalues():
1364            name = "%s_State_%s.html" % (self.ident, state.ident)
1365            code = html.createSymbol(state, "State")
1366            code.write(path, name)
1367
1368        # Generate event descriptions
1369        for event in self.events.itervalues():
1370            name = "%s_Event_%s.html" % (self.ident, event.ident)
1371            code = html.createSymbol(event, "Event")
1372            code.write(path, name)
1373
1374    def printHTMLTransitions(self, path, active_state):
1375        code = self.symtab.codeFormatter()
1376
1377        code('''
1378<HTML>
1379<BODY link="blue" vlink="blue">
1380
1381<H1 align="center">${{html.formatShorthand(self.short)}}:
1382''')
1383        code.indent()
1384        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1385            mid = machine.ident
1386            if i != 0:
1387                extra = " - "
1388            else:
1389                extra = ""
1390            if machine == self:
1391                code('$extra$mid')
1392            else:
1393                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1394        code.dedent()
1395
1396        code("""
1397</H1>
1398
1399<TABLE border=1>
1400<TR>
1401  <TH> </TH>
1402""")
1403
1404        for event in self.events.itervalues():
1405            href = "%s_Event_%s.html" % (self.ident, event.ident)
1406            ref = self.frameRef(href, "Status", href, "1", event.short)
1407            code('<TH bgcolor=white>$ref</TH>')
1408
1409        code('</TR>')
1410        # -- Body of table
1411        for state in self.states.itervalues():
1412            # -- Each row
1413            if state == active_state:
1414                color = "yellow"
1415            else:
1416                color = "white"
1417
1418            click = "%s_table_%s.html" % (self.ident, state.ident)
1419            over = "%s_State_%s.html" % (self.ident, state.ident)
1420            text = html.formatShorthand(state.short)
1421            ref = self.frameRef(click, "Table", over, "1", state.short)
1422            code('''
1423<TR>
1424  <TH bgcolor=$color>$ref</TH>
1425''')
1426
1427            # -- One column for each event
1428            for event in self.events.itervalues():
1429                trans = self.table.get((state,event), None)
1430                if trans is None:
1431                    # This is the no transition case
1432                    if state == active_state:
1433                        color = "#C0C000"
1434                    else:
1435                        color = "lightgrey"
1436
1437                    code('<TD bgcolor=$color>&nbsp;</TD>')
1438                    continue
1439
1440                next = trans.nextState
1441                stall_action = False
1442
1443                # -- Get the actions
1444                for action in trans.actions:
1445                    if action.ident == "z_stall" or \
1446                       action.ident == "zz_recycleMandatoryQueue":
1447                        stall_action = True
1448
1449                # -- Print out "actions/next-state"
1450                if stall_action:
1451                    if state == active_state:
1452                        color = "#C0C000"
1453                    else:
1454                        color = "lightgrey"
1455
1456                elif active_state and next.ident == active_state.ident:
1457                    color = "aqua"
1458                elif state == active_state:
1459                    color = "yellow"
1460                else:
1461                    color = "white"
1462
1463                code('<TD bgcolor=$color>')
1464                for action in trans.actions:
1465                    href = "%s_action_%s.html" % (self.ident, action.ident)
1466                    ref = self.frameRef(href, "Status", href, "1",
1467                                        action.short)
1468                    code('  $ref')
1469                if next != state:
1470                    if trans.actions:
1471                        code('/')
1472                    click = "%s_table_%s.html" % (self.ident, next.ident)
1473                    over = "%s_State_%s.html" % (self.ident, next.ident)
1474                    ref = self.frameRef(click, "Table", over, "1", next.short)
1475                    code("$ref")
1476                code("</TD>")
1477
1478            # -- Each row
1479            if state == active_state:
1480                color = "yellow"
1481            else:
1482                color = "white"
1483
1484            click = "%s_table_%s.html" % (self.ident, state.ident)
1485            over = "%s_State_%s.html" % (self.ident, state.ident)
1486            ref = self.frameRef(click, "Table", over, "1", state.short)
1487            code('''
1488  <TH bgcolor=$color>$ref</TH>
1489</TR>
1490''')
1491        code('''
1492<!- Column footer->
1493<TR>
1494  <TH> </TH>
1495''')
1496
1497        for event in self.events.itervalues():
1498            href = "%s_Event_%s.html" % (self.ident, event.ident)
1499            ref = self.frameRef(href, "Status", href, "1", event.short)
1500            code('<TH bgcolor=white>$ref</TH>')
1501        code('''
1502</TR>
1503</TABLE>
1504</BODY></HTML>
1505''')
1506
1507
1508        if active_state:
1509            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1510        else:
1511            name = "%s_table.html" % self.ident
1512        code.write(path, name)
1513
1514__all__ = [ "StateMachine" ]
1515