StateMachine.py revision 9595:470016acf37d
12391SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
22391SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company
32391SN/A# All rights reserved.
42391SN/A#
52391SN/A# Redistribution and use in source and binary forms, with or without
62391SN/A# modification, are permitted provided that the following conditions are
72391SN/A# met: redistributions of source code must retain the above copyright
82391SN/A# notice, this list of conditions and the following disclaimer;
92391SN/A# redistributions in binary form must reproduce the above copyright
102391SN/A# notice, this list of conditions and the following disclaimer in the
112391SN/A# documentation and/or other materials provided with the distribution;
122391SN/A# neither the name of the copyright holders nor the names of its
132391SN/A# contributors may be used to endorse or promote products derived from
142391SN/A# this software without specific prior written permission.
152391SN/A#
162391SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172391SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182391SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192391SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202391SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212391SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222391SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232391SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242391SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252391SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262391SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272391SN/A
282391SN/Afrom m5.util import orderdict
292391SN/A
302391SN/Afrom slicc.symbols.Symbol import Symbol
312391SN/Afrom slicc.symbols.Var import Var
322391SN/Aimport slicc.generate.html as html
332391SN/Aimport re
342391SN/A
352391SN/Apython_class_map = {
362391SN/A                    "int": "Int",
372391SN/A                    "uint32_t" : "UInt32",
382391SN/A                    "std::string": "String",
392391SN/A                    "bool": "Bool",
402391SN/A                    "CacheMemory": "RubyCache",
412391SN/A                    "WireBuffer": "RubyWireBuffer",
422592SN/A                    "Sequencer": "RubySequencer",
432394SN/A                    "DirectoryMemory": "RubyDirectoryMemory",
442391SN/A                    "MemoryControl": "MemoryControl",
452391SN/A                    "DMASequencer": "DMASequencer",
462415SN/A                    "Prefetcher":"Prefetcher",
472423SN/A                    "Cycles":"Cycles",
482391SN/A                   }
492394SN/A
502391SN/Aclass StateMachine(Symbol):
512423SN/A    def __init__(self, symtab, ident, location, pairs, config_parameters):
522391SN/A        super(StateMachine, self).__init__(symtab, ident, location, pairs)
532630SN/A        self.table = None
542415SN/A        self.config_parameters = config_parameters
552415SN/A        self.prefetchers = []
562415SN/A
572415SN/A        for param in config_parameters:
582415SN/A            if param.pointer:
592415SN/A                var = Var(symtab, param.name, location, param.type_ast.type,
602415SN/A                          "(*m_%s_ptr)" % param.name, {}, self)
612415SN/A            else:
622415SN/A                var = Var(symtab, param.name, location, param.type_ast.type,
632415SN/A                          "m_%s" % param.name, {}, self)
642415SN/A            self.symtab.registerSym(param.name, var)
652415SN/A            if str(param.type_ast.type) == "Prefetcher":
662415SN/A                self.prefetchers.append(var)
672415SN/A
682415SN/A        self.states = orderdict()
692415SN/A        self.events = orderdict()
702415SN/A        self.actions = orderdict()
712415SN/A        self.request_types = orderdict()
722565SN/A        self.transitions = []
732565SN/A        self.in_ports = []
742391SN/A        self.functions = []
752391SN/A        self.objects = []
762391SN/A        self.TBEType   = None
772391SN/A        self.EntryType = None
782391SN/A
792391SN/A    def __repr__(self):
802391SN/A        return "[StateMachine: %s]" % self.ident
812391SN/A
822391SN/A    def addState(self, state):
832391SN/A        assert self.table is None
842391SN/A        self.states[state.ident] = state
852391SN/A
862391SN/A    def addEvent(self, event):
872391SN/A        assert self.table is None
882391SN/A        self.events[event.ident] = event
892391SN/A
902391SN/A    def addAction(self, action):
912391SN/A        assert self.table is None
922391SN/A
932541SN/A        # Check for duplicate action
942541SN/A        for other in self.actions.itervalues():
952541SN/A            if action.ident == other.ident:
962541SN/A                action.warning("Duplicate action definition: %s" % action.ident)
972541SN/A                action.error("Duplicate action definition: %s" % action.ident)
982541SN/A            if action.short == other.short:
992541SN/A                other.warning("Duplicate action shorthand: %s" % other.ident)
1002541SN/A                other.warning("    shorthand = %s" % other.short)
1012391SN/A                action.warning("Duplicate action shorthand: %s" % action.ident)
1022391SN/A                action.error("    shorthand = %s" % action.short)
1032391SN/A
1042391SN/A        self.actions[action.ident] = action
1052416SN/A
1062391SN/A    def addRequestType(self, request_type):
1072391SN/A        assert self.table is None
1082391SN/A        self.request_types[request_type.ident] = request_type
1092391SN/A
1102391SN/A    def addTransition(self, trans):
1112391SN/A        assert self.table is None
1122391SN/A        self.transitions.append(trans)
1132391SN/A
1142391SN/A    def addInPort(self, var):
1152391SN/A        self.in_ports.append(var)
1162391SN/A
1172391SN/A    def addFunc(self, func):
1182408SN/A        # register func in the symbol table
1192408SN/A        self.symtab.registerSym(str(func), func)
1202408SN/A        self.functions.append(func)
1212409SN/A
1222409SN/A    def addObject(self, obj):
1232408SN/A        self.objects.append(obj)
1242408SN/A
1252413SN/A    def addType(self, type):
1262630SN/A        type_ident = '%s' % type.c_ident
1272413SN/A
1282413SN/A        if type_ident == "%s_TBE" %self.ident:
1292415SN/A            if self.TBEType != None:
1302639Sstever@eecs.umich.edu                self.error("Multiple Transaction Buffer types in a " \
1312630SN/A                           "single machine.");
1322416SN/A            self.TBEType = type
1332415SN/A
1342415SN/A        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1352413SN/A            if self.EntryType != None:
1362413SN/A                self.error("Multiple AbstractCacheEntry types in a " \
1372413SN/A                           "single machine.");
1382413SN/A            self.EntryType = type
1392630SN/A
1402413SN/A    # Needs to be called before accessing the table
1412413SN/A    def buildTable(self):
1422630SN/A        assert self.table is None
1432413SN/A
1442413SN/A        table = {}
1452413SN/A
1462413SN/A        for trans in self.transitions:
1472630SN/A            # Track which actions we touch so we know if we use them
1482413SN/A            # all -- really this should be done for all symbols as
1492630SN/A            # part of the symbol table, then only trigger it for
1502414SN/A            # Actions, States, Events, etc.
1512630SN/A
1522413SN/A            for action in trans.actions:
1532630SN/A                action.used = True
1542630SN/A
1552418SN/A            index = (trans.state, trans.event)
1562413SN/A            if index in table:
1572630SN/A                table[index].warning("Duplicate transition: %s" % table[index])
1582630SN/A                trans.error("Duplicate transition: %s" % trans)
1592631SN/A            table[index] = trans
1602631SN/A
1612631SN/A        # Look at all actions to make sure we used them all
1622631SN/A        for action in self.actions.itervalues():
1632631SN/A            if not action.used:
1642418SN/A                error_msg = "Unused action: %s" % action.ident
1652413SN/A                if "desc" in action:
1662413SN/A                    error_msg += ", "  + action.desc
1672413SN/A                action.warning(error_msg)
1682420SN/A        self.table = table
1692630SN/A
1702413SN/A    def writeCodeFiles(self, path, includes):
1712413SN/A        self.printControllerPython(path)
1722413SN/A        self.printControllerHH(path)
1732499SN/A        self.printControllerCC(path, includes)
1742413SN/A        self.printCSwitch(path)
1752499SN/A        self.printCWakeup(path, includes)
1762499SN/A        self.printProfilerCC(path)
1772499SN/A        self.printProfilerHH(path)
1782640Sstever@eecs.umich.edu        self.printProfileDumperCC(path)
1792499SN/A        self.printProfileDumperHH(path)
1802519SN/A
1812519SN/A    def printControllerPython(self, path):
1822640Sstever@eecs.umich.edu        code = self.symtab.codeFormatter()
1832462SN/A        ident = self.ident
1842462SN/A        py_ident = "%s_Controller" % ident
1852462SN/A        c_ident = "%s_Controller" % self.ident
1862413SN/A        code('''
1872413SN/Afrom m5.params import *
1882413SN/Afrom m5.SimObject import SimObject
1892413SN/Afrom Controller import RubyController
1902413SN/A
1912413SN/Aclass $py_ident(RubyController):
1922413SN/A    type = '$py_ident'
1932640Sstever@eecs.umich.edu    cxx_header = 'mem/protocol/${c_ident}.hh'
1942640Sstever@eecs.umich.edu''')
1952640Sstever@eecs.umich.edu        code.indent()
1962413SN/A        for param in self.config_parameters:
1972413SN/A            dflt_str = ''
1982413SN/A            if param.default is not None:
1992413SN/A                dflt_str = str(param.default) + ', '
2002413SN/A            if python_class_map.has_key(param.type_ast.type.c_ident):
2012413SN/A                python_type = python_class_map[param.type_ast.type.c_ident]
2022413SN/A                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
2032413SN/A            else:
2042413SN/A                self.error("Unknown c++ to python class conversion for c++ " \
2052522SN/A                           "type: '%s'. Please update the python_class_map " \
2062522SN/A                           "in StateMachine.py", param.type_ast.type.c_ident)
2072413SN/A        code.dedent()
2082522SN/A        code.write(path, '%s.py' % py_ident)
2092497SN/A
2102497SN/A
2112497SN/A    def printControllerHH(self, path):
2122522SN/A        '''Output the method declarations for the class declaration'''
2132497SN/A        code = self.symtab.codeFormatter()
2142522SN/A        ident = self.ident
2152522SN/A        c_ident = "%s_Controller" % self.ident
2162522SN/A
2172413SN/A        code('''
2182413SN/A/** \\file $c_ident.hh
2192415SN/A *
2202415SN/A * Auto generated C++ code started by $__file__:$__line__
2212415SN/A * Created by slicc definition of Module "${{self.short}}"
2222415SN/A */
2232415SN/A
2242413SN/A#ifndef __${ident}_CONTROLLER_HH__
2252413SN/A#define __${ident}_CONTROLLER_HH__
2262630SN/A
2272413SN/A#include <iostream>
2282416SN/A#include <sstream>
2292413SN/A#include <string>
2302413SN/A
2312413SN/A#include "mem/protocol/${ident}_ProfileDumper.hh"
2322630SN/A#include "mem/protocol/${ident}_Profiler.hh"
2332413SN/A#include "mem/protocol/TransitionResult.hh"
2342413SN/A#include "mem/protocol/Types.hh"
2352413SN/A#include "mem/ruby/common/Consumer.hh"
2362413SN/A#include "mem/ruby/common/Global.hh"
2372413SN/A#include "mem/ruby/slicc_interface/AbstractController.hh"
2382630SN/A#include "params/$c_ident.hh"
2392413SN/A''')
2402413SN/A
2412413SN/A        seen_types = set()
2422413SN/A        has_peer = False
2432413SN/A        for var in self.objects:
2442413SN/A            if var.type.ident not in seen_types and not var.type.isPrimitive:
2452391SN/A                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2462391SN/A            if "network" in var and "physical_network" in var:
2472391SN/A                has_peer = True
2482391SN/A            seen_types.add(var.type.ident)
2492391SN/A
2502391SN/A        # for adding information to the protocol debug trace
2512391SN/A        code('''
2522391SN/Aextern std::stringstream ${ident}_transitionComment;
2532391SN/A
2542391SN/Aclass $c_ident : public AbstractController
2552391SN/A{
2562391SN/A  public:
2572391SN/A    typedef ${c_ident}Params Params;
2582391SN/A    $c_ident(const Params *p);
2592391SN/A    static int getNumControllers();
2602391SN/A    void init();
2612391SN/A    MessageBuffer* getMandatoryQueue() const;
2622391SN/A    const int & getVersion() const;
2632391SN/A    const std::string toString() const;
2642391SN/A    const std::string getName() const;
2652391SN/A    void stallBuffer(MessageBuffer* buf, Address addr);
2662391SN/A    void wakeUpBuffers(Address addr);
2672391SN/A    void wakeUpAllBuffers();
2682391SN/A    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
2692391SN/A    void print(std::ostream& out) const;
2702391SN/A    void wakeup();
2712391SN/A    void printStats(std::ostream& out) const;
2722391SN/A    void clearStats();
2732391SN/A    void blockOnQueue(Address addr, MessageBuffer* port);
2742391SN/A    void unblock(Address addr);
2752391SN/A    void recordCacheTrace(int cntrl, CacheRecorder* tr);
2762391SN/A    Sequencer* getSequencer() const;
2772391SN/A
2782391SN/A    bool functionalReadBuffers(PacketPtr&);
2792391SN/A    uint32_t functionalWriteBuffers(PacketPtr&);
2802391SN/A
2812391SN/Aprivate:
2822391SN/A''')
2832391SN/A
2842391SN/A        code.indent()
2852391SN/A        # added by SS
2862391SN/A        for param in self.config_parameters:
2872391SN/A            if param.pointer:
2882391SN/A                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
2892391SN/A            else:
2902391SN/A                code('${{param.type_ast.type}} m_${{param.ident}};')
2912391SN/A
2922391SN/A        code('''
2932391SN/ATransitionResult doTransition(${ident}_Event event,
2942391SN/A''')
2952391SN/A
2962391SN/A        if self.EntryType != None:
2972391SN/A            code('''
2982391SN/A                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
2992391SN/A''')
3002391SN/A        if self.TBEType != None:
3012391SN/A            code('''
3022391SN/A                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
3032391SN/A''')
3042391SN/A
3052391SN/A        code('''
3062391SN/A                              const Address& addr);
3072391SN/A
3082391SN/ATransitionResult doTransitionWorker(${ident}_Event event,
3092391SN/A                                    ${ident}_State state,
3102391SN/A                                    ${ident}_State& next_state,
3112391SN/A''')
3122391SN/A
3132391SN/A        if self.TBEType != None:
3142391SN/A            code('''
3152391SN/A                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
3162391SN/A''')
3172391SN/A        if self.EntryType != None:
3182391SN/A            code('''
3192391SN/A                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
3202391SN/A''')
3212391SN/A
3222391SN/A        code('''
3232391SN/A                                    const Address& addr);
3242391SN/A
3252391SN/Astatic ${ident}_ProfileDumper s_profileDumper;
3262391SN/A${ident}_Profiler m_profiler;
3272391SN/Astatic int m_num_controllers;
3282391SN/A
3292391SN/A// Internal functions
3302391SN/A''')
3312391SN/A
3322391SN/A        for func in self.functions:
3332391SN/A            proto = func.prototype
3342391SN/A            if proto:
3352391SN/A                code('$proto')
3362391SN/A
3372391SN/A        if has_peer:
3382391SN/A            code('void getQueuesFromPeer(AbstractController *);')
3392391SN/A        if self.EntryType != None:
3402391SN/A            code('''
3412391SN/A
3422391SN/A// Set and Reset for cache_entry variable
3432391SN/Avoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
3442391SN/Avoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
3452391SN/A''')
3462391SN/A
3472391SN/A        if self.TBEType != None:
3482391SN/A            code('''
3492391SN/A
3502391SN/A// Set and Reset for tbe variable
3512391SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
3522413SN/Avoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
3532391SN/A''')
3542391SN/A
3552391SN/A        code('''
3562391SN/A
3572565SN/A// Actions
3582391SN/A''')
3592391SN/A        if self.TBEType != None and self.EntryType != None:
3602391SN/A            for action in self.actions.itervalues():
3612391SN/A                code('/** \\brief ${{action.desc}} */')
3622391SN/A                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
3632391SN/A        elif self.TBEType != None:
3642565SN/A            for action in self.actions.itervalues():
3652565SN/A                code('/** \\brief ${{action.desc}} */')
3662391SN/A                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
3672391SN/A        elif self.EntryType != None:
3682391SN/A            for action in self.actions.itervalues():
3692391SN/A                code('/** \\brief ${{action.desc}} */')
3702391SN/A                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
3712391SN/A        else:
3722565SN/A            for action in self.actions.itervalues():
3732391SN/A                code('/** \\brief ${{action.desc}} */')
3742391SN/A                code('void ${{action.ident}}(const Address& addr);')
3752391SN/A
376        # the controller internal variables
377        code('''
378
379// Objects
380''')
381        for var in self.objects:
382            th = var.get("template", "")
383            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
384
385        code.dedent()
386        code('};')
387        code('#endif // __${ident}_CONTROLLER_H__')
388        code.write(path, '%s.hh' % c_ident)
389
390    def printControllerCC(self, path, includes):
391        '''Output the actions for performing the actions'''
392
393        code = self.symtab.codeFormatter()
394        ident = self.ident
395        c_ident = "%s_Controller" % self.ident
396        has_peer = False
397
398        code('''
399/** \\file $c_ident.cc
400 *
401 * Auto generated C++ code started by $__file__:$__line__
402 * Created by slicc definition of Module "${{self.short}}"
403 */
404
405#include <sys/types.h>
406#include <unistd.h>
407
408#include <cassert>
409#include <sstream>
410#include <string>
411
412#include "base/compiler.hh"
413#include "base/cprintf.hh"
414#include "debug/RubyGenerated.hh"
415#include "debug/RubySlicc.hh"
416#include "mem/protocol/${ident}_Controller.hh"
417#include "mem/protocol/${ident}_Event.hh"
418#include "mem/protocol/${ident}_State.hh"
419#include "mem/protocol/Types.hh"
420#include "mem/ruby/common/Global.hh"
421#include "mem/ruby/system/System.hh"
422''')
423        for include_path in includes:
424            code('#include "${{include_path}}"')
425
426        code('''
427
428using namespace std;
429''')
430
431        # include object classes
432        seen_types = set()
433        for var in self.objects:
434            if var.type.ident not in seen_types and not var.type.isPrimitive:
435                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
436            seen_types.add(var.type.ident)
437
438        code('''
439$c_ident *
440${c_ident}Params::create()
441{
442    return new $c_ident(this);
443}
444
445int $c_ident::m_num_controllers = 0;
446${ident}_ProfileDumper $c_ident::s_profileDumper;
447
448// for adding information to the protocol debug trace
449stringstream ${ident}_transitionComment;
450#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
451
452/** \\brief constructor */
453$c_ident::$c_ident(const Params *p)
454    : AbstractController(p)
455{
456    m_name = "${ident}";
457''')
458        #
459        # max_port_rank is used to size vectors and thus should be one plus the
460        # largest port rank
461        #
462        max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
463        code('    m_max_in_port_rank = $max_port_rank;')
464        code.indent()
465
466        #
467        # After initializing the universal machine parameters, initialize the
468        # this machines config parameters.  Also detemine if these configuration
469        # params include a sequencer.  This information will be used later for
470        # contecting the sequencer back to the L1 cache controller.
471        #
472        contains_dma_sequencer = False
473        sequencers = []
474        for param in self.config_parameters:
475            if param.name == "dma_sequencer":
476                contains_dma_sequencer = True
477            elif re.compile("sequencer").search(param.name):
478                sequencers.append(param.name)
479            if param.pointer:
480                code('m_${{param.name}}_ptr = p->${{param.name}};')
481            else:
482                code('m_${{param.name}} = p->${{param.name}};')
483
484        #
485        # For the l1 cache controller, add the special atomic support which
486        # includes passing the sequencer a pointer to the controller.
487        #
488        if self.ident == "L1Cache":
489            if not sequencers:
490                self.error("The L1Cache controller must include the sequencer " \
491                           "configuration parameter")
492
493            for seq in sequencers:
494                code('''
495m_${{seq}}_ptr->setController(this);
496    ''')
497
498        else:
499            for seq in sequencers:
500                code('''
501m_${{seq}}_ptr->setController(this);
502    ''')
503
504        #
505        # For the DMA controller, pass the sequencer a pointer to the
506        # controller.
507        #
508        if self.ident == "DMA":
509            if not contains_dma_sequencer:
510                self.error("The DMA controller must include the sequencer " \
511                           "configuration parameter")
512
513            code('''
514m_dma_sequencer_ptr->setController(this);
515''')
516
517        code('m_num_controllers++;')
518        for var in self.objects:
519            if var.ident.find("mandatoryQueue") >= 0:
520                code('''
521m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
522m_${{var.c_ident}}_ptr->setReceiver(this);
523''')
524            else:
525                if "network" in var and "physical_network" in var and \
526                   var["network"] == "To":
527                    has_peer = True
528                    code('''
529m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
530peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
531m_${{var.c_ident}}_ptr->setSender(this);
532''')
533
534        code('''
535if (p->peer != NULL)
536    connectWithPeer(p->peer);
537''')
538        code.dedent()
539        code('''
540}
541
542void
543$c_ident::init()
544{
545    MachineType machine_type;
546    int base;
547    machine_type = string_to_MachineType("${{var.machine.ident}}");
548    base = MachineType_base_number(machine_type);
549
550    m_machineID.type = MachineType_${ident};
551    m_machineID.num = m_version;
552
553    // initialize objects
554    m_profiler.setVersion(m_version);
555    s_profileDumper.registerProfiler(&m_profiler);
556
557''')
558
559        code.indent()
560        for var in self.objects:
561            vtype = var.type
562            vid = "m_%s_ptr" % var.c_ident
563            if "network" not in var:
564                # Not a network port object
565                if "primitive" in vtype:
566                    code('$vid = new ${{vtype.c_ident}};')
567                    if "default" in var:
568                        code('(*$vid) = ${{var["default"]}};')
569                else:
570                    # Normal Object
571                    if var.ident.find("mandatoryQueue") < 0:
572                        th = var.get("template", "")
573                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
574                        args = ""
575                        if "non_obj" not in vtype and not vtype.isEnumeration:
576                            args = var.get("constructor", "")
577                        code('$expr($args);')
578
579                    code('assert($vid != NULL);')
580
581                    if "default" in var:
582                        code('*$vid = ${{var["default"]}}; // Object default')
583                    elif "default" in vtype:
584                        comment = "Type %s default" % vtype.ident
585                        code('*$vid = ${{vtype["default"]}}; // $comment')
586
587                    # Set ordering
588                    if "ordered" in var:
589                        # A buffer
590                        code('$vid->setOrdering(${{var["ordered"]}});')
591
592                    # Set randomization
593                    if "random" in var:
594                        # A buffer
595                        code('$vid->setRandomization(${{var["random"]}});')
596
597                    # Set Priority
598                    if vtype.isBuffer and "rank" in var:
599                        code('$vid->setPriority(${{var["rank"]}});')
600
601                    # Set sender and receiver for trigger queue
602                    if var.ident.find("triggerQueue") >= 0:
603                        code('$vid->setSender(this);')
604                        code('$vid->setReceiver(this);')
605                    elif vtype.c_ident == "TimerTable":
606                        code('$vid->setClockObj(this);')
607
608            else:
609                # Network port object
610                network = var["network"]
611                ordered =  var["ordered"]
612
613                if "virtual_network" in var:
614                    vnet = var["virtual_network"]
615                    vnet_type = var["vnet_type"]
616
617                    assert var.machine is not None
618                    code('''
619$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
620assert($vid != NULL);
621''')
622
623                    # Set the end
624                    if network == "To":
625                        code('$vid->setSender(this);')
626                    else:
627                        code('$vid->setReceiver(this);')
628
629                # Set ordering
630                if "ordered" in var:
631                    # A buffer
632                    code('$vid->setOrdering(${{var["ordered"]}});')
633
634                # Set randomization
635                if "random" in var:
636                    # A buffer
637                    code('$vid->setRandomization(${{var["random"]}});')
638
639                # Set Priority
640                if "rank" in var:
641                    code('$vid->setPriority(${{var["rank"]}})')
642
643                # Set buffer size
644                if vtype.isBuffer:
645                    code('''
646if (m_buffer_size > 0) {
647    $vid->resize(m_buffer_size);
648}
649''')
650
651                # set description (may be overriden later by port def)
652                code('''
653$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
654
655''')
656
657            if vtype.isBuffer:
658                if "recycle_latency" in var:
659                    code('$vid->setRecycleLatency( ' \
660                         'Cycles(${{var["recycle_latency"]}}));')
661                else:
662                    code('$vid->setRecycleLatency(m_recycle_latency);')
663
664        # Set the prefetchers
665        code()
666        for prefetcher in self.prefetchers:
667            code('${{prefetcher.code}}.setController(this);')
668
669        code()
670        for port in self.in_ports:
671            # Set the queue consumers
672            code('${{port.code}}.setConsumer(this);')
673            # Set the queue descriptions
674            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
675
676        # Initialize the transition profiling
677        code()
678        for trans in self.transitions:
679            # Figure out if we stall
680            stall = False
681            for action in trans.actions:
682                if action.ident == "z_stall":
683                    stall = True
684
685            # Only possible if it is not a 'z' case
686            if not stall:
687                state = "%s_State_%s" % (self.ident, trans.state.ident)
688                event = "%s_Event_%s" % (self.ident, trans.event.ident)
689                code('m_profiler.possibleTransition($state, $event);')
690
691        code.dedent()
692        code('''
693    AbstractController::init();
694    clearStats();
695}
696''')
697
698        has_mandatory_q = False
699        for port in self.in_ports:
700            if port.code.find("mandatoryQueue_ptr") >= 0:
701                has_mandatory_q = True
702
703        if has_mandatory_q:
704            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
705        else:
706            mq_ident = "NULL"
707
708        seq_ident = "NULL"
709        for param in self.config_parameters:
710            if param.name == "sequencer":
711                assert(param.pointer)
712                seq_ident = "m_%s_ptr" % param.name
713
714        code('''
715int
716$c_ident::getNumControllers()
717{
718    return m_num_controllers;
719}
720
721MessageBuffer*
722$c_ident::getMandatoryQueue() const
723{
724    return $mq_ident;
725}
726
727Sequencer*
728$c_ident::getSequencer() const
729{
730    return $seq_ident;
731}
732
733const int &
734$c_ident::getVersion() const
735{
736    return m_version;
737}
738
739const string
740$c_ident::toString() const
741{
742    return "$c_ident";
743}
744
745const string
746$c_ident::getName() const
747{
748    return m_name;
749}
750
751void
752$c_ident::stallBuffer(MessageBuffer* buf, Address addr)
753{
754    if (m_waiting_buffers.count(addr) == 0) {
755        MsgVecType* msgVec = new MsgVecType;
756        msgVec->resize(m_max_in_port_rank, NULL);
757        m_waiting_buffers[addr] = msgVec;
758    }
759    (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
760}
761
762void
763$c_ident::wakeUpBuffers(Address addr)
764{
765    if (m_waiting_buffers.count(addr) > 0) {
766        //
767        // Wake up all possible lower rank (i.e. lower priority) buffers that could
768        // be waiting on this message.
769        //
770        for (int in_port_rank = m_cur_in_port_rank - 1;
771             in_port_rank >= 0;
772             in_port_rank--) {
773            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
774                (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
775            }
776        }
777        delete m_waiting_buffers[addr];
778        m_waiting_buffers.erase(addr);
779    }
780}
781
782void
783$c_ident::wakeUpAllBuffers()
784{
785    //
786    // Wake up all possible buffers that could be waiting on any message.
787    //
788
789    std::vector<MsgVecType*> wokeUpMsgVecs;
790
791    if(m_waiting_buffers.size() > 0) {
792        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
793             buf_iter != m_waiting_buffers.end();
794             ++buf_iter) {
795             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
796                  vec_iter != buf_iter->second->end();
797                  ++vec_iter) {
798                  if (*vec_iter != NULL) {
799                      (*vec_iter)->reanalyzeAllMessages();
800                  }
801             }
802             wokeUpMsgVecs.push_back(buf_iter->second);
803        }
804
805        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
806             wb_iter != wokeUpMsgVecs.end();
807             ++wb_iter) {
808             delete (*wb_iter);
809        }
810
811        m_waiting_buffers.clear();
812    }
813}
814
815void
816$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
817{
818    m_is_blocking = true;
819    m_block_map[addr] = port;
820}
821
822void
823$c_ident::unblock(Address addr)
824{
825    m_block_map.erase(addr);
826    if (m_block_map.size() == 0) {
827       m_is_blocking = false;
828    }
829}
830
831void
832$c_ident::print(ostream& out) const
833{
834    out << "[$c_ident " << m_version << "]";
835}
836
837void
838$c_ident::printStats(ostream& out) const
839{
840''')
841        #
842        # Cache and Memory Controllers have specific profilers associated with
843        # them.  Print out these stats before dumping state transition stats.
844        #
845        for param in self.config_parameters:
846            if param.type_ast.type.ident == "CacheMemory" or \
847               param.type_ast.type.ident == "DirectoryMemory" or \
848                   param.type_ast.type.ident == "MemoryControl":
849                assert(param.pointer)
850                code('    m_${{param.ident}}_ptr->printStats(out);')
851
852        code('''
853    if (m_version == 0) {
854        s_profileDumper.dumpStats(out);
855    }
856}
857
858void $c_ident::clearStats() {
859''')
860        #
861        # Cache and Memory Controllers have specific profilers associated with
862        # them.  These stats must be cleared too.
863        #
864        for param in self.config_parameters:
865            if param.type_ast.type.ident == "CacheMemory" or \
866                   param.type_ast.type.ident == "MemoryControl":
867                assert(param.pointer)
868                code('    m_${{param.ident}}_ptr->clearStats();')
869
870        code('''
871    m_profiler.clearStats();
872    AbstractController::clearStats();
873}
874''')
875
876        if self.EntryType != None:
877            code('''
878
879// Set and Reset for cache_entry variable
880void
881$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
882{
883  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
884}
885
886void
887$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
888{
889  m_cache_entry_ptr = 0;
890}
891''')
892
893        if self.TBEType != None:
894            code('''
895
896// Set and Reset for tbe variable
897void
898$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
899{
900  m_tbe_ptr = m_new_tbe;
901}
902
903void
904$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
905{
906  m_tbe_ptr = NULL;
907}
908''')
909
910        code('''
911
912void
913$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
914{
915''')
916        #
917        # Record cache contents for all associated caches.
918        #
919        code.indent()
920        for param in self.config_parameters:
921            if param.type_ast.type.ident == "CacheMemory":
922                assert(param.pointer)
923                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
924
925        code.dedent()
926        code('''
927}
928
929// Actions
930''')
931        if self.TBEType != None and self.EntryType != None:
932            for action in self.actions.itervalues():
933                if "c_code" not in action:
934                 continue
935
936                code('''
937/** \\brief ${{action.desc}} */
938void
939$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
940{
941    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
942    ${{action["c_code"]}}
943}
944
945''')
946        elif self.TBEType != None:
947            for action in self.actions.itervalues():
948                if "c_code" not in action:
949                 continue
950
951                code('''
952/** \\brief ${{action.desc}} */
953void
954$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
955{
956    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
957    ${{action["c_code"]}}
958}
959
960''')
961        elif self.EntryType != None:
962            for action in self.actions.itervalues():
963                if "c_code" not in action:
964                 continue
965
966                code('''
967/** \\brief ${{action.desc}} */
968void
969$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
970{
971    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
972    ${{action["c_code"]}}
973}
974
975''')
976        else:
977            for action in self.actions.itervalues():
978                if "c_code" not in action:
979                 continue
980
981                code('''
982/** \\brief ${{action.desc}} */
983void
984$c_ident::${{action.ident}}(const Address& addr)
985{
986    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
987    ${{action["c_code"]}}
988}
989
990''')
991        for func in self.functions:
992            code(func.generateCode())
993
994        # Function for functional reads from messages buffered in the controller
995        code('''
996bool
997$c_ident::functionalReadBuffers(PacketPtr& pkt)
998{
999''')
1000        for var in self.objects:
1001            vtype = var.type
1002            if vtype.isBuffer:
1003                vid = "m_%s_ptr" % var.c_ident
1004                code('if ($vid->functionalRead(pkt)) { return true; }')
1005        code('''
1006                return false;
1007}
1008''')
1009
1010        # Function for functional writes to messages buffered in the controller
1011        code('''
1012uint32_t
1013$c_ident::functionalWriteBuffers(PacketPtr& pkt)
1014{
1015    uint32_t num_functional_writes = 0;
1016''')
1017        for var in self.objects:
1018            vtype = var.type
1019            if vtype.isBuffer:
1020                vid = "m_%s_ptr" % var.c_ident
1021                code('num_functional_writes += $vid->functionalWrite(pkt);')
1022        code('''
1023    return num_functional_writes;
1024}
1025''')
1026
1027        # Check if this controller has a peer, if yes then write the
1028        # function for connecting to the peer.
1029        if has_peer:
1030            code('''
1031
1032void
1033$c_ident::getQueuesFromPeer(AbstractController *peer)
1034{
1035''')
1036            for var in self.objects:
1037                if "network" in var and "physical_network" in var and \
1038                   var["network"] == "From":
1039                    code('''
1040m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1041assert(m_${{var.c_ident}}_ptr != NULL);
1042m_${{var.c_ident}}_ptr->setReceiver(this);
1043
1044''')
1045            code('}')
1046
1047        code.write(path, "%s.cc" % c_ident)
1048
1049    def printCWakeup(self, path, includes):
1050        '''Output the wakeup loop for the events'''
1051
1052        code = self.symtab.codeFormatter()
1053        ident = self.ident
1054
1055        outputRequest_types = True
1056        if len(self.request_types) == 0:
1057            outputRequest_types = False
1058
1059        code('''
1060// Auto generated C++ code started by $__file__:$__line__
1061// ${ident}: ${{self.short}}
1062
1063#include <sys/types.h>
1064#include <unistd.h>
1065
1066#include <cassert>
1067
1068#include "base/misc.hh"
1069#include "debug/RubySlicc.hh"
1070#include "mem/protocol/${ident}_Controller.hh"
1071#include "mem/protocol/${ident}_Event.hh"
1072#include "mem/protocol/${ident}_State.hh"
1073''')
1074
1075        if outputRequest_types:
1076            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1077
1078        code('''
1079#include "mem/protocol/Types.hh"
1080#include "mem/ruby/common/Global.hh"
1081#include "mem/ruby/system/System.hh"
1082''')
1083
1084
1085        for include_path in includes:
1086            code('#include "${{include_path}}"')
1087
1088        code('''
1089
1090using namespace std;
1091
1092void
1093${ident}_Controller::wakeup()
1094{
1095    int counter = 0;
1096    while (true) {
1097        // Some cases will put us into an infinite loop without this limit
1098        assert(counter <= m_transitions_per_cycle);
1099        if (counter == m_transitions_per_cycle) {
1100            // Count how often we are fully utilized
1101            m_fully_busy_cycles++;
1102
1103            // Wakeup in another cycle and try again
1104            scheduleEvent(Cycles(1));
1105            break;
1106        }
1107''')
1108
1109        code.indent()
1110        code.indent()
1111
1112        # InPorts
1113        #
1114        for port in self.in_ports:
1115            code.indent()
1116            code('// ${ident}InPort $port')
1117            if port.pairs.has_key("rank"):
1118                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1119            else:
1120                code('m_cur_in_port_rank = 0;')
1121            code('${{port["c_code_in_port"]}}')
1122            code.dedent()
1123
1124            code('')
1125
1126        code.dedent()
1127        code.dedent()
1128        code('''
1129        break;  // If we got this far, we have nothing left todo
1130    }
1131}
1132''')
1133
1134        code.write(path, "%s_Wakeup.cc" % self.ident)
1135
1136    def printCSwitch(self, path):
1137        '''Output switch statement for transition table'''
1138
1139        code = self.symtab.codeFormatter()
1140        ident = self.ident
1141
1142        code('''
1143// Auto generated C++ code started by $__file__:$__line__
1144// ${ident}: ${{self.short}}
1145
1146#include <cassert>
1147
1148#include "base/misc.hh"
1149#include "base/trace.hh"
1150#include "debug/ProtocolTrace.hh"
1151#include "debug/RubyGenerated.hh"
1152#include "mem/protocol/${ident}_Controller.hh"
1153#include "mem/protocol/${ident}_Event.hh"
1154#include "mem/protocol/${ident}_State.hh"
1155#include "mem/protocol/Types.hh"
1156#include "mem/ruby/common/Global.hh"
1157#include "mem/ruby/system/System.hh"
1158
1159#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1160
1161#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1162#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1163
1164TransitionResult
1165${ident}_Controller::doTransition(${ident}_Event event,
1166''')
1167        if self.EntryType != None:
1168            code('''
1169                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1170''')
1171        if self.TBEType != None:
1172            code('''
1173                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1174''')
1175        code('''
1176                                  const Address &addr)
1177{
1178''')
1179        if self.TBEType != None and self.EntryType != None:
1180            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1181        elif self.TBEType != None:
1182            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1183        elif self.EntryType != None:
1184            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1185        else:
1186            code('${ident}_State state = getState(addr);')
1187
1188        code('''
1189    ${ident}_State next_state = state;
1190
1191    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1192            *this, curCycle(), ${ident}_State_to_string(state),
1193            ${ident}_Event_to_string(event), addr);
1194
1195    TransitionResult result =
1196''')
1197        if self.TBEType != None and self.EntryType != None:
1198            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1199        elif self.TBEType != None:
1200            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1201        elif self.EntryType != None:
1202            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1203        else:
1204            code('doTransitionWorker(event, state, next_state, addr);')
1205
1206        code('''
1207    if (result == TransitionResult_Valid) {
1208        DPRINTF(RubyGenerated, "next_state: %s\\n",
1209                ${ident}_State_to_string(next_state));
1210        m_profiler.countTransition(state, event);
1211        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1212                 curTick(), m_version, "${ident}",
1213                 ${ident}_Event_to_string(event),
1214                 ${ident}_State_to_string(state),
1215                 ${ident}_State_to_string(next_state),
1216                 addr, GET_TRANSITION_COMMENT());
1217
1218        CLEAR_TRANSITION_COMMENT();
1219''')
1220        if self.TBEType != None and self.EntryType != None:
1221            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1222            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1223        elif self.TBEType != None:
1224            code('setState(m_tbe_ptr, addr, next_state);')
1225            code('setAccessPermission(addr, next_state);')
1226        elif self.EntryType != None:
1227            code('setState(m_cache_entry_ptr, addr, next_state);')
1228            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1229        else:
1230            code('setState(addr, next_state);')
1231            code('setAccessPermission(addr, next_state);')
1232
1233        code('''
1234    } else if (result == TransitionResult_ResourceStall) {
1235        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1236                 curTick(), m_version, "${ident}",
1237                 ${ident}_Event_to_string(event),
1238                 ${ident}_State_to_string(state),
1239                 ${ident}_State_to_string(next_state),
1240                 addr, "Resource Stall");
1241    } else if (result == TransitionResult_ProtocolStall) {
1242        DPRINTF(RubyGenerated, "stalling\\n");
1243        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1244                 curTick(), m_version, "${ident}",
1245                 ${ident}_Event_to_string(event),
1246                 ${ident}_State_to_string(state),
1247                 ${ident}_State_to_string(next_state),
1248                 addr, "Protocol Stall");
1249    }
1250
1251    return result;
1252}
1253
1254TransitionResult
1255${ident}_Controller::doTransitionWorker(${ident}_Event event,
1256                                        ${ident}_State state,
1257                                        ${ident}_State& next_state,
1258''')
1259
1260        if self.TBEType != None:
1261            code('''
1262                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1263''')
1264        if self.EntryType != None:
1265                  code('''
1266                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1267''')
1268        code('''
1269                                        const Address& addr)
1270{
1271    switch(HASH_FUN(state, event)) {
1272''')
1273
1274        # This map will allow suppress generating duplicate code
1275        cases = orderdict()
1276
1277        for trans in self.transitions:
1278            case_string = "%s_State_%s, %s_Event_%s" % \
1279                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1280
1281            case = self.symtab.codeFormatter()
1282            # Only set next_state if it changes
1283            if trans.state != trans.nextState:
1284                ns_ident = trans.nextState.ident
1285                case('next_state = ${ident}_State_${ns_ident};')
1286
1287            actions = trans.actions
1288            request_types = trans.request_types
1289
1290            # Check for resources
1291            case_sorter = []
1292            res = trans.resources
1293            for key,val in res.iteritems():
1294                if key.type.ident != "DNUCAStopTable":
1295                    val = '''
1296if (!%s.areNSlotsAvailable(%s))
1297    return TransitionResult_ResourceStall;
1298''' % (key.code, val)
1299                case_sorter.append(val)
1300
1301            # Check all of the request_types for resource constraints
1302            for request_type in request_types:
1303                val = '''
1304if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1305    return TransitionResult_ResourceStall;
1306}
1307''' % (self.ident, request_type.ident)
1308                case_sorter.append(val)
1309
1310            # Emit the code sequences in a sorted order.  This makes the
1311            # output deterministic (without this the output order can vary
1312            # since Map's keys() on a vector of pointers is not deterministic
1313            for c in sorted(case_sorter):
1314                case("$c")
1315
1316            # Record access types for this transition
1317            for request_type in request_types:
1318                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1319
1320            # Figure out if we stall
1321            stall = False
1322            for action in actions:
1323                if action.ident == "z_stall":
1324                    stall = True
1325                    break
1326
1327            if stall:
1328                case('return TransitionResult_ProtocolStall;')
1329            else:
1330                if self.TBEType != None and self.EntryType != None:
1331                    for action in actions:
1332                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1333                elif self.TBEType != None:
1334                    for action in actions:
1335                        case('${{action.ident}}(m_tbe_ptr, addr);')
1336                elif self.EntryType != None:
1337                    for action in actions:
1338                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1339                else:
1340                    for action in actions:
1341                        case('${{action.ident}}(addr);')
1342                case('return TransitionResult_Valid;')
1343
1344            case = str(case)
1345
1346            # Look to see if this transition code is unique.
1347            if case not in cases:
1348                cases[case] = []
1349
1350            cases[case].append(case_string)
1351
1352        # Walk through all of the unique code blocks and spit out the
1353        # corresponding case statement elements
1354        for case,transitions in cases.iteritems():
1355            # Iterative over all the multiple transitions that share
1356            # the same code
1357            for trans in transitions:
1358                code('  case HASH_FUN($trans):')
1359            code('    $case')
1360
1361        code('''
1362      default:
1363        fatal("Invalid transition\\n"
1364              "%s time: %d addr: %s event: %s state: %s\\n",
1365              name(), curCycle(), addr, event, state);
1366    }
1367    return TransitionResult_Valid;
1368}
1369''')
1370        code.write(path, "%s_Transitions.cc" % self.ident)
1371
1372    def printProfileDumperHH(self, path):
1373        code = self.symtab.codeFormatter()
1374        ident = self.ident
1375
1376        code('''
1377// Auto generated C++ code started by $__file__:$__line__
1378// ${ident}: ${{self.short}}
1379
1380#ifndef __${ident}_PROFILE_DUMPER_HH__
1381#define __${ident}_PROFILE_DUMPER_HH__
1382
1383#include <cassert>
1384#include <iostream>
1385#include <vector>
1386
1387#include "${ident}_Event.hh"
1388#include "${ident}_Profiler.hh"
1389
1390typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1391
1392class ${ident}_ProfileDumper
1393{
1394  public:
1395    ${ident}_ProfileDumper();
1396    void registerProfiler(${ident}_Profiler* profiler);
1397    void dumpStats(std::ostream& out) const;
1398
1399  private:
1400    ${ident}_profilers m_profilers;
1401};
1402
1403#endif // __${ident}_PROFILE_DUMPER_HH__
1404''')
1405        code.write(path, "%s_ProfileDumper.hh" % self.ident)
1406
1407    def printProfileDumperCC(self, path):
1408        code = self.symtab.codeFormatter()
1409        ident = self.ident
1410
1411        code('''
1412// Auto generated C++ code started by $__file__:$__line__
1413// ${ident}: ${{self.short}}
1414
1415#include "mem/protocol/${ident}_ProfileDumper.hh"
1416
1417${ident}_ProfileDumper::${ident}_ProfileDumper()
1418{
1419}
1420
1421void
1422${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1423{
1424    m_profilers.push_back(profiler);
1425}
1426
1427void
1428${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1429{
1430    out << " --- ${ident} ---\\n";
1431    out << " - Event Counts -\\n";
1432    for (${ident}_Event event = ${ident}_Event_FIRST;
1433         event < ${ident}_Event_NUM;
1434         ++event) {
1435        out << (${ident}_Event) event << " [";
1436        uint64 total = 0;
1437        for (int i = 0; i < m_profilers.size(); i++) {
1438             out << m_profilers[i]->getEventCount(event) << " ";
1439             total += m_profilers[i]->getEventCount(event);
1440        }
1441        out << "] " << total << "\\n";
1442    }
1443    out << "\\n";
1444    out << " - Transitions -\\n";
1445    for (${ident}_State state = ${ident}_State_FIRST;
1446         state < ${ident}_State_NUM;
1447         ++state) {
1448        for (${ident}_Event event = ${ident}_Event_FIRST;
1449             event < ${ident}_Event_NUM;
1450             ++event) {
1451            if (m_profilers[0]->isPossible(state, event)) {
1452                out << (${ident}_State) state << "  "
1453                    << (${ident}_Event) event << " [";
1454                uint64 total = 0;
1455                for (int i = 0; i < m_profilers.size(); i++) {
1456                     out << m_profilers[i]->getTransitionCount(state, event) << " ";
1457                     total += m_profilers[i]->getTransitionCount(state, event);
1458                }
1459                out << "] " << total << "\\n";
1460            }
1461        }
1462        out << "\\n";
1463    }
1464}
1465''')
1466        code.write(path, "%s_ProfileDumper.cc" % self.ident)
1467
1468    def printProfilerHH(self, path):
1469        code = self.symtab.codeFormatter()
1470        ident = self.ident
1471
1472        code('''
1473// Auto generated C++ code started by $__file__:$__line__
1474// ${ident}: ${{self.short}}
1475
1476#ifndef __${ident}_PROFILER_HH__
1477#define __${ident}_PROFILER_HH__
1478
1479#include <cassert>
1480#include <iostream>
1481
1482#include "mem/protocol/${ident}_Event.hh"
1483#include "mem/protocol/${ident}_State.hh"
1484#include "mem/ruby/common/TypeDefines.hh"
1485
1486class ${ident}_Profiler
1487{
1488  public:
1489    ${ident}_Profiler();
1490    void setVersion(int version);
1491    void countTransition(${ident}_State state, ${ident}_Event event);
1492    void possibleTransition(${ident}_State state, ${ident}_Event event);
1493    uint64 getEventCount(${ident}_Event event);
1494    bool isPossible(${ident}_State state, ${ident}_Event event);
1495    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1496    void clearStats();
1497
1498  private:
1499    int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1500    int m_event_counters[${ident}_Event_NUM];
1501    bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1502    int m_version;
1503};
1504
1505#endif // __${ident}_PROFILER_HH__
1506''')
1507        code.write(path, "%s_Profiler.hh" % self.ident)
1508
1509    def printProfilerCC(self, path):
1510        code = self.symtab.codeFormatter()
1511        ident = self.ident
1512
1513        code('''
1514// Auto generated C++ code started by $__file__:$__line__
1515// ${ident}: ${{self.short}}
1516
1517#include <cassert>
1518
1519#include "mem/protocol/${ident}_Profiler.hh"
1520
1521${ident}_Profiler::${ident}_Profiler()
1522{
1523    for (int state = 0; state < ${ident}_State_NUM; state++) {
1524        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1525            m_possible[state][event] = false;
1526            m_counters[state][event] = 0;
1527        }
1528    }
1529    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1530        m_event_counters[event] = 0;
1531    }
1532}
1533
1534void
1535${ident}_Profiler::setVersion(int version)
1536{
1537    m_version = version;
1538}
1539
1540void
1541${ident}_Profiler::clearStats()
1542{
1543    for (int state = 0; state < ${ident}_State_NUM; state++) {
1544        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1545            m_counters[state][event] = 0;
1546        }
1547    }
1548
1549    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1550        m_event_counters[event] = 0;
1551    }
1552}
1553void
1554${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1555{
1556    assert(m_possible[state][event]);
1557    m_counters[state][event]++;
1558    m_event_counters[event]++;
1559}
1560void
1561${ident}_Profiler::possibleTransition(${ident}_State state,
1562                                      ${ident}_Event event)
1563{
1564    m_possible[state][event] = true;
1565}
1566
1567uint64
1568${ident}_Profiler::getEventCount(${ident}_Event event)
1569{
1570    return m_event_counters[event];
1571}
1572
1573bool
1574${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1575{
1576    return m_possible[state][event];
1577}
1578
1579uint64
1580${ident}_Profiler::getTransitionCount(${ident}_State state,
1581                                      ${ident}_Event event)
1582{
1583    return m_counters[state][event];
1584}
1585
1586''')
1587        code.write(path, "%s_Profiler.cc" % self.ident)
1588
1589    # **************************
1590    # ******* HTML Files *******
1591    # **************************
1592    def frameRef(self, click_href, click_target, over_href, over_num, text):
1593        code = self.symtab.codeFormatter(fix_newlines=False)
1594        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1595    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1596        parent.frames[$over_num].location='$over_href'
1597    }\">
1598    ${{html.formatShorthand(text)}}
1599    </A>""")
1600        return str(code)
1601
1602    def writeHTMLFiles(self, path):
1603        # Create table with no row hilighted
1604        self.printHTMLTransitions(path, None)
1605
1606        # Generate transition tables
1607        for state in self.states.itervalues():
1608            self.printHTMLTransitions(path, state)
1609
1610        # Generate action descriptions
1611        for action in self.actions.itervalues():
1612            name = "%s_action_%s.html" % (self.ident, action.ident)
1613            code = html.createSymbol(action, "Action")
1614            code.write(path, name)
1615
1616        # Generate state descriptions
1617        for state in self.states.itervalues():
1618            name = "%s_State_%s.html" % (self.ident, state.ident)
1619            code = html.createSymbol(state, "State")
1620            code.write(path, name)
1621
1622        # Generate event descriptions
1623        for event in self.events.itervalues():
1624            name = "%s_Event_%s.html" % (self.ident, event.ident)
1625            code = html.createSymbol(event, "Event")
1626            code.write(path, name)
1627
1628    def printHTMLTransitions(self, path, active_state):
1629        code = self.symtab.codeFormatter()
1630
1631        code('''
1632<HTML>
1633<BODY link="blue" vlink="blue">
1634
1635<H1 align="center">${{html.formatShorthand(self.short)}}:
1636''')
1637        code.indent()
1638        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1639            mid = machine.ident
1640            if i != 0:
1641                extra = " - "
1642            else:
1643                extra = ""
1644            if machine == self:
1645                code('$extra$mid')
1646            else:
1647                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1648        code.dedent()
1649
1650        code("""
1651</H1>
1652
1653<TABLE border=1>
1654<TR>
1655  <TH> </TH>
1656""")
1657
1658        for event in self.events.itervalues():
1659            href = "%s_Event_%s.html" % (self.ident, event.ident)
1660            ref = self.frameRef(href, "Status", href, "1", event.short)
1661            code('<TH bgcolor=white>$ref</TH>')
1662
1663        code('</TR>')
1664        # -- Body of table
1665        for state in self.states.itervalues():
1666            # -- Each row
1667            if state == active_state:
1668                color = "yellow"
1669            else:
1670                color = "white"
1671
1672            click = "%s_table_%s.html" % (self.ident, state.ident)
1673            over = "%s_State_%s.html" % (self.ident, state.ident)
1674            text = html.formatShorthand(state.short)
1675            ref = self.frameRef(click, "Table", over, "1", state.short)
1676            code('''
1677<TR>
1678  <TH bgcolor=$color>$ref</TH>
1679''')
1680
1681            # -- One column for each event
1682            for event in self.events.itervalues():
1683                trans = self.table.get((state,event), None)
1684                if trans is None:
1685                    # This is the no transition case
1686                    if state == active_state:
1687                        color = "#C0C000"
1688                    else:
1689                        color = "lightgrey"
1690
1691                    code('<TD bgcolor=$color>&nbsp;</TD>')
1692                    continue
1693
1694                next = trans.nextState
1695                stall_action = False
1696
1697                # -- Get the actions
1698                for action in trans.actions:
1699                    if action.ident == "z_stall" or \
1700                       action.ident == "zz_recycleMandatoryQueue":
1701                        stall_action = True
1702
1703                # -- Print out "actions/next-state"
1704                if stall_action:
1705                    if state == active_state:
1706                        color = "#C0C000"
1707                    else:
1708                        color = "lightgrey"
1709
1710                elif active_state and next.ident == active_state.ident:
1711                    color = "aqua"
1712                elif state == active_state:
1713                    color = "yellow"
1714                else:
1715                    color = "white"
1716
1717                code('<TD bgcolor=$color>')
1718                for action in trans.actions:
1719                    href = "%s_action_%s.html" % (self.ident, action.ident)
1720                    ref = self.frameRef(href, "Status", href, "1",
1721                                        action.short)
1722                    code('  $ref')
1723                if next != state:
1724                    if trans.actions:
1725                        code('/')
1726                    click = "%s_table_%s.html" % (self.ident, next.ident)
1727                    over = "%s_State_%s.html" % (self.ident, next.ident)
1728                    ref = self.frameRef(click, "Table", over, "1", next.short)
1729                    code("$ref")
1730                code("</TD>")
1731
1732            # -- Each row
1733            if state == active_state:
1734                color = "yellow"
1735            else:
1736                color = "white"
1737
1738            click = "%s_table_%s.html" % (self.ident, state.ident)
1739            over = "%s_State_%s.html" % (self.ident, state.ident)
1740            ref = self.frameRef(click, "Table", over, "1", state.short)
1741            code('''
1742  <TH bgcolor=$color>$ref</TH>
1743</TR>
1744''')
1745        code('''
1746<!- Column footer->
1747<TR>
1748  <TH> </TH>
1749''')
1750
1751        for event in self.events.itervalues():
1752            href = "%s_Event_%s.html" % (self.ident, event.ident)
1753            ref = self.frameRef(href, "Status", href, "1", event.short)
1754            code('<TH bgcolor=white>$ref</TH>')
1755        code('''
1756</TR>
1757</TABLE>
1758</BODY></HTML>
1759''')
1760
1761
1762        if active_state:
1763            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1764        else:
1765            name = "%s_table.html" % self.ident
1766        code.write(path, name)
1767
1768__all__ = [ "StateMachine" ]
1769