StateMachine.py revision 11111:6da33e720481
1545SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
21762SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company
3545SN/A# Copyright (c) 2013 Advanced Micro Devices, Inc.
4545SN/A# All rights reserved.
5545SN/A#
6545SN/A# Redistribution and use in source and binary forms, with or without
7545SN/A# modification, are permitted provided that the following conditions are
8545SN/A# met: redistributions of source code must retain the above copyright
9545SN/A# notice, this list of conditions and the following disclaimer;
10545SN/A# redistributions in binary form must reproduce the above copyright
11545SN/A# notice, this list of conditions and the following disclaimer in the
12545SN/A# documentation and/or other materials provided with the distribution;
13545SN/A# neither the name of the copyright holders nor the names of its
14545SN/A# contributors may be used to endorse or promote products derived from
15545SN/A# this software without specific prior written permission.
16545SN/A#
17545SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18545SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19545SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20545SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21545SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22545SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23545SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24545SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25545SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26545SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272665Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edufrom m5.util import orderdict
30545SN/A
31545SN/Afrom slicc.symbols.Symbol import Symbol
321310SN/Afrom slicc.symbols.Var import Var
331310SN/Aimport slicc.generate.html as html
34545SN/Aimport re
352542SN/A
363348Sbinkertn@umich.edupython_class_map = {
373348Sbinkertn@umich.edu                    "int": "Int",
382489SN/A                    "uint32_t" : "UInt32",
39545SN/A                    "std::string": "String",
403090Sstever@eecs.umich.edu                    "bool": "Bool",
411310SN/A                    "CacheMemory": "RubyCache",
422384SN/A                    "WireBuffer": "RubyWireBuffer",
432489SN/A                    "Sequencer": "RubySequencer",
442522SN/A                    "DirectoryMemory": "RubyDirectoryMemory",
45545SN/A                    "MemoryControl": "MemoryControl",
462489SN/A                    "MessageBuffer": "MessageBuffer",
472489SN/A                    "DMASequencer": "DMASequencer",
482489SN/A                    "Prefetcher":"Prefetcher",
492489SN/A                    "Cycles":"Cycles",
502489SN/A                   }
513090Sstever@eecs.umich.edu
523090Sstever@eecs.umich.educlass StateMachine(Symbol):
532914Ssaidi@eecs.umich.edu    def __init__(self, symtab, ident, location, pairs, config_parameters):
54545SN/A        super(StateMachine, self).__init__(symtab, ident, location, pairs)
55545SN/A        self.table = None
562489SN/A
572384SN/A        # Data members in the State Machine that have been declared before
582384SN/A        # the opening brace '{'  of the machine.  Note that these along with
593349Sbinkertn@umich.edu        # the members in self.objects form the entire set of data members.
602384SN/A        self.config_parameters = config_parameters
613090Sstever@eecs.umich.edu
623090Sstever@eecs.umich.edu        self.prefetchers = []
632384SN/A
642384SN/A        for param in config_parameters:
653091Sstever@eecs.umich.edu            if param.pointer:
662901Ssaidi@eecs.umich.edu                var = Var(symtab, param.ident, location, param.type_ast.type,
672384SN/A                          "(*m_%s_ptr)" % param.ident, {}, self)
682384SN/A            else:
692565SN/A                var = Var(symtab, param.ident, location, param.type_ast.type,
702384SN/A                          "m_%s" % param.ident, {}, self)
712384SN/A
722384SN/A            self.symtab.registerSym(param.ident, var)
732784Ssaidi@eecs.umich.edu
742784Ssaidi@eecs.umich.edu            if str(param.type_ast.type) == "Prefetcher":
752784Ssaidi@eecs.umich.edu                self.prefetchers.append(var)
762784Ssaidi@eecs.umich.edu
772784Ssaidi@eecs.umich.edu        self.states = orderdict()
782784Ssaidi@eecs.umich.edu        self.events = orderdict()
792784Ssaidi@eecs.umich.edu        self.actions = orderdict()
802784Ssaidi@eecs.umich.edu        self.request_types = orderdict()
812784Ssaidi@eecs.umich.edu        self.transitions = []
822784Ssaidi@eecs.umich.edu        self.in_ports = []
832784Ssaidi@eecs.umich.edu        self.functions = []
842784Ssaidi@eecs.umich.edu
852784Ssaidi@eecs.umich.edu        # Data members in the State Machine that have been declared inside
862784Ssaidi@eecs.umich.edu        # the {} machine.  Note that these along with the config params
872784Ssaidi@eecs.umich.edu        # form the entire set of data members of the machine.
882784Ssaidi@eecs.umich.edu        self.objects = []
892784Ssaidi@eecs.umich.edu        self.TBEType   = None
902784Ssaidi@eecs.umich.edu        self.EntryType = None
912784Ssaidi@eecs.umich.edu        self.debug_flags = set()
922784Ssaidi@eecs.umich.edu        self.debug_flags.add('RubyGenerated')
932565SN/A        self.debug_flags.add('RubySlicc')
943349Sbinkertn@umich.edu
952384SN/A    def __repr__(self):
962901Ssaidi@eecs.umich.edu        return "[StateMachine: %s]" % self.ident
972565SN/A
982901Ssaidi@eecs.umich.edu    def addState(self, state):
992565SN/A        assert self.table is None
1002565SN/A        self.states[state.ident] = state
1012565SN/A
1022384SN/A    def addEvent(self, event):
1032901Ssaidi@eecs.umich.edu        assert self.table is None
1042901Ssaidi@eecs.umich.edu        self.events[event.ident] = event
1052901Ssaidi@eecs.umich.edu
1062901Ssaidi@eecs.umich.edu    def addAction(self, action):
1072901Ssaidi@eecs.umich.edu        assert self.table is None
1082901Ssaidi@eecs.umich.edu
1092901Ssaidi@eecs.umich.edu        # Check for duplicate action
1104435Ssaidi@eecs.umich.edu        for other in self.actions.itervalues():
1114435Ssaidi@eecs.umich.edu            if action.ident == other.ident:
1124435Ssaidi@eecs.umich.edu                action.warning("Duplicate action definition: %s" % action.ident)
1134435Ssaidi@eecs.umich.edu                action.error("Duplicate action definition: %s" % action.ident)
1144435Ssaidi@eecs.umich.edu            if action.short == other.short:
1154435Ssaidi@eecs.umich.edu                other.warning("Duplicate action shorthand: %s" % other.ident)
1164435Ssaidi@eecs.umich.edu                other.warning("    shorthand = %s" % other.short)
1174435Ssaidi@eecs.umich.edu                action.warning("Duplicate action shorthand: %s" % action.ident)
1183349Sbinkertn@umich.edu                action.error("    shorthand = %s" % action.short)
1193349Sbinkertn@umich.edu
1203918Ssaidi@eecs.umich.edu        self.actions[action.ident] = action
1213349Sbinkertn@umich.edu
1222384SN/A    def addDebugFlag(self, flag):
1232384SN/A        self.debug_flags.add(flag)
1242384SN/A
1252384SN/A    def addRequestType(self, request_type):
1262384SN/A        assert self.table is None
1272657Ssaidi@eecs.umich.edu        self.request_types[request_type.ident] = request_type
1282384SN/A
1293090Sstever@eecs.umich.edu    def addTransition(self, trans):
1303090Sstever@eecs.umich.edu        assert self.table is None
1312521SN/A        self.transitions.append(trans)
1322384SN/A
1334435Ssaidi@eecs.umich.edu    def addInPort(self, var):
1344435Ssaidi@eecs.umich.edu        self.in_ports.append(var)
1354435Ssaidi@eecs.umich.edu
1364435Ssaidi@eecs.umich.edu    def addFunc(self, func):
1374435Ssaidi@eecs.umich.edu        # register func in the symbol table
1382489SN/A        self.symtab.registerSym(str(func), func)
1392384SN/A        self.functions.append(func)
1402901Ssaidi@eecs.umich.edu
1412565SN/A    def addObject(self, obj):
1422641Sstever@eecs.umich.edu        self.symtab.registerSym(str(obj), obj)
1432641Sstever@eecs.umich.edu        self.objects.append(obj)
1442565SN/A
1452565SN/A    def addType(self, type):
1462384SN/A        type_ident = '%s' % type.c_ident
1474263Ssaidi@eecs.umich.edu
1482901Ssaidi@eecs.umich.edu        if type_ident == "%s_TBE" %self.ident:
1492384SN/A            if self.TBEType != None:
1502384SN/A                self.error("Multiple Transaction Buffer types in a " \
1512489SN/A                           "single machine.");
1522489SN/A            self.TBEType = type
1532489SN/A
1542489SN/A        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1552489SN/A            if "main" in type and "false" == type["main"].lower():
1562489SN/A                pass # this isn't the EntryType
1572489SN/A            else:
1582542SN/A                if self.EntryType != None:
1592384SN/A                    self.error("Multiple AbstractCacheEntry types in a " \
1602384SN/A                               "single machine.");
1612384SN/A                self.EntryType = type
1622489SN/A
1632489SN/A    # Needs to be called before accessing the table
1641310SN/A    def buildTable(self):
1652384SN/A        assert self.table is None
1662901Ssaidi@eecs.umich.edu
1672901Ssaidi@eecs.umich.edu        table = {}
1682489SN/A
1692489SN/A        for trans in self.transitions:
1702384SN/A            # Track which actions we touch so we know if we use them
1712384SN/A            # all -- really this should be done for all symbols as
1722521SN/A            # part of the symbol table, then only trigger it for
1732384SN/A            # Actions, States, Events, etc.
1743090Sstever@eecs.umich.edu
1753090Sstever@eecs.umich.edu            for action in trans.actions:
1762523SN/A                action.used = True
1772523SN/A
1782523SN/A            index = (trans.state, trans.event)
1793349Sbinkertn@umich.edu            if index in table:
1802384SN/A                table[index].warning("Duplicate transition: %s" % table[index])
1812489SN/A                trans.error("Duplicate transition: %s" % trans)
1822523SN/A            table[index] = trans
1832523SN/A
1842523SN/A        # Look at all actions to make sure we used them all
1852523SN/A        for action in self.actions.itervalues():
1863349Sbinkertn@umich.edu            if not action.used:
187545SN/A                error_msg = "Unused action: %s" % action.ident
188545SN/A                if "desc" in action:
1893090Sstever@eecs.umich.edu                    error_msg += ", "  + action.desc
1903090Sstever@eecs.umich.edu                action.warning(error_msg)
1913090Sstever@eecs.umich.edu        self.table = table
1922512SN/A
1932512SN/A    # determine the port->msg buffer mappings
1942512SN/A    def getBufferMaps(self, ident):
1952512SN/A        msg_bufs = []
1962522SN/A        port_to_buf_map = {}
1972512SN/A        in_msg_bufs = {}
1982521SN/A        for port in self.in_ports:
1992512SN/A            buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name
2002512SN/A            msg_bufs.append(buf_name)
2012512SN/A            port_to_buf_map[port] = msg_bufs.index(buf_name)
2022512SN/A            if buf_name not in in_msg_bufs:
2032512SN/A                in_msg_bufs[buf_name] = [port]
2042512SN/A            else:
2052521SN/A                in_msg_bufs[buf_name].append(port)
2062901Ssaidi@eecs.umich.edu        return port_to_buf_map, in_msg_bufs, msg_bufs
2072901Ssaidi@eecs.umich.edu
2082512SN/A    def writeCodeFiles(self, path, includes):
2092384SN/A        self.printControllerPython(path)
210545SN/A        self.printControllerHH(path)
2112384SN/A        self.printControllerCC(path, includes)
2122541SN/A        self.printCSwitch(path)
2132541SN/A        self.printCWakeup(path, includes)
2142901Ssaidi@eecs.umich.edu
2152901Ssaidi@eecs.umich.edu    def printControllerPython(self, path):
2162738Sstever@eecs.umich.edu        code = self.symtab.codeFormatter()
2172384SN/A        ident = self.ident
2182521SN/A
2192512SN/A        py_ident = "%s_Controller" % ident
2202512SN/A        c_ident = "%s_Controller" % self.ident
2212901Ssaidi@eecs.umich.edu
2222384SN/A        code('''
2232521SN/Afrom m5.params import *
2242384SN/Afrom m5.SimObject import SimObject
2252384SN/Afrom Controller import RubyController
2262489SN/A
2272489SN/Aclass $py_ident(RubyController):
228545SN/A    type = '$py_ident'
229545SN/A    cxx_header = 'mem/protocol/${c_ident}.hh'
2302512SN/A''')
2312512SN/A        code.indent()
2322512SN/A        for param in self.config_parameters:
2332521SN/A            dflt_str = ''
2342512SN/A
2352512SN/A            if param.rvalue is not None:
2362512SN/A                dflt_str = str(param.rvalue.inline()) + ', '
2372512SN/A
2382512SN/A            if python_class_map.has_key(param.type_ast.type.c_ident):
2392512SN/A                python_type = python_class_map[param.type_ast.type.c_ident]
2402512SN/A                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
2412512SN/A
2422512SN/A            else:
2432512SN/A                self.error("Unknown c++ to python class conversion for c++ " \
2442521SN/A                           "type: '%s'. Please update the python_class_map " \
2452512SN/A                           "in StateMachine.py", param.type_ast.type.c_ident)
2462512SN/A
2472512SN/A        code.dedent()
2482512SN/A        code.write(path, '%s.py' % py_ident)
2492512SN/A
2502521SN/A
2513090Sstever@eecs.umich.edu    def printControllerHH(self, path):
2523090Sstever@eecs.umich.edu        '''Output the method declarations for the class declaration'''
2532512SN/A        code = self.symtab.codeFormatter()
2542512SN/A        ident = self.ident
2552539SN/A        c_ident = "%s_Controller" % self.ident
2562982Sstever@eecs.umich.edu
2572539SN/A        code('''
2582542SN/A/** \\file $c_ident.hh
2592539SN/A *
2602512SN/A * Auto generated C++ code started by $__file__:$__line__
2612512SN/A * Created by slicc definition of Module "${{self.short}}"
262545SN/A */
263545SN/A
2644435Ssaidi@eecs.umich.edu#ifndef __${ident}_CONTROLLER_HH__
2654435Ssaidi@eecs.umich.edu#define __${ident}_CONTROLLER_HH__
2664435Ssaidi@eecs.umich.edu
2674435Ssaidi@eecs.umich.edu#include <iostream>
2684435Ssaidi@eecs.umich.edu#include <sstream>
2694435Ssaidi@eecs.umich.edu#include <string>
2704435Ssaidi@eecs.umich.edu
2714435Ssaidi@eecs.umich.edu#include "mem/protocol/TransitionResult.hh"
2722384SN/A#include "mem/protocol/Types.hh"
2734435Ssaidi@eecs.umich.edu#include "mem/ruby/common/Consumer.hh"
2744435Ssaidi@eecs.umich.edu#include "mem/ruby/slicc_interface/AbstractController.hh"
275545SN/A#include "params/$c_ident.hh"
276545SN/A
2772521SN/A''')
278545SN/A
2792384SN/A        seen_types = set()
2802565SN/A        for var in self.objects:
2814022Sstever@eecs.umich.edu            if var.type.ident not in seen_types and not var.type.isPrimitive:
2824022Sstever@eecs.umich.edu                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
2834022Sstever@eecs.umich.edu                seen_types.add(var.type.ident)
2844022Sstever@eecs.umich.edu
2852565SN/A        # for adding information to the protocol debug trace
2864263Ssaidi@eecs.umich.edu        code('''
2874263Ssaidi@eecs.umich.eduextern std::stringstream ${ident}_transitionComment;
2884263Ssaidi@eecs.umich.edu
2894263Ssaidi@eecs.umich.educlass $c_ident : public AbstractController
2902565SN/A{
2912565SN/A  public:
2922565SN/A    typedef ${c_ident}Params Params;
2932901Ssaidi@eecs.umich.edu    $c_ident(const Params *p);
2942901Ssaidi@eecs.umich.edu    static int getNumControllers();
2954263Ssaidi@eecs.umich.edu    void init();
2964263Ssaidi@eecs.umich.edu
2972738Sstever@eecs.umich.edu    MessageBuffer *getMandatoryQueue() const;
2982384SN/A    MessageBuffer *getMemoryQueue() const;
2992565SN/A    void initNetQueues();
3002565SN/A
3012565SN/A    void print(std::ostream& out) const;
3022901Ssaidi@eecs.umich.edu    void wakeup();
3032384SN/A    void resetStats();
3042565SN/A    void regStats();
3052565SN/A    void collateStats();
3062565SN/A
3072901Ssaidi@eecs.umich.edu    void recordCacheTrace(int cntrl, CacheRecorder* tr);
3082384SN/A    Sequencer* getSequencer() const;
3092565SN/A
3102384SN/A    int functionalWriteBuffers(PacketPtr&);
3112384SN/A
3122489SN/A    void countTransition(${ident}_State state, ${ident}_Event event);
3132489SN/A    void possibleTransition(${ident}_State state, ${ident}_Event event);
314545SN/A    uint64_t getEventCount(${ident}_Event event);
315545SN/A    bool isPossible(${ident}_State state, ${ident}_Event event);
3162384SN/A    uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event);
3171310SN/A
318private:
319''')
320
321        code.indent()
322        # added by SS
323        for param in self.config_parameters:
324            if param.pointer:
325                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
326            else:
327                code('${{param.type_ast.type}} m_${{param.ident}};')
328
329        code('''
330TransitionResult doTransition(${ident}_Event event,
331''')
332
333        if self.EntryType != None:
334            code('''
335                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
336''')
337        if self.TBEType != None:
338            code('''
339                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
340''')
341
342        code('''
343                              Addr addr);
344
345TransitionResult doTransitionWorker(${ident}_Event event,
346                                    ${ident}_State state,
347                                    ${ident}_State& next_state,
348''')
349
350        if self.TBEType != None:
351            code('''
352                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
353''')
354        if self.EntryType != None:
355            code('''
356                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
357''')
358
359        code('''
360                                    Addr addr);
361
362int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
363int m_event_counters[${ident}_Event_NUM];
364bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
365
366static std::vector<Stats::Vector *> eventVec;
367static std::vector<std::vector<Stats::Vector *> > transVec;
368static int m_num_controllers;
369
370// Internal functions
371''')
372
373        for func in self.functions:
374            proto = func.prototype
375            if proto:
376                code('$proto')
377
378        if self.EntryType != None:
379            code('''
380
381// Set and Reset for cache_entry variable
382void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
383void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
384''')
385
386        if self.TBEType != None:
387            code('''
388
389// Set and Reset for tbe variable
390void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
391void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
392''')
393
394        # Prototype the actions that the controller can take
395        code('''
396
397// Actions
398''')
399        if self.TBEType != None and self.EntryType != None:
400            for action in self.actions.itervalues():
401                code('/** \\brief ${{action.desc}} */')
402                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
403                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
404                     'm_cache_entry_ptr, Addr addr);')
405        elif self.TBEType != None:
406            for action in self.actions.itervalues():
407                code('/** \\brief ${{action.desc}} */')
408                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
409                     'm_tbe_ptr, Addr addr);')
410        elif self.EntryType != None:
411            for action in self.actions.itervalues():
412                code('/** \\brief ${{action.desc}} */')
413                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
414                     'm_cache_entry_ptr, Addr addr);')
415        else:
416            for action in self.actions.itervalues():
417                code('/** \\brief ${{action.desc}} */')
418                code('void ${{action.ident}}(Addr addr);')
419
420        # the controller internal variables
421        code('''
422
423// Objects
424''')
425        for var in self.objects:
426            th = var.get("template", "")
427            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
428
429        code.dedent()
430        code('};')
431        code('#endif // __${ident}_CONTROLLER_H__')
432        code.write(path, '%s.hh' % c_ident)
433
434    def printControllerCC(self, path, includes):
435        '''Output the actions for performing the actions'''
436
437        code = self.symtab.codeFormatter()
438        ident = self.ident
439        c_ident = "%s_Controller" % self.ident
440
441        code('''
442/** \\file $c_ident.cc
443 *
444 * Auto generated C++ code started by $__file__:$__line__
445 * Created by slicc definition of Module "${{self.short}}"
446 */
447
448#include <sys/types.h>
449#include <unistd.h>
450
451#include <cassert>
452#include <sstream>
453#include <string>
454#include <typeinfo>
455
456#include "base/compiler.hh"
457#include "base/cprintf.hh"
458
459''')
460        for f in self.debug_flags:
461            code('#include "debug/${{f}}.hh"')
462        code('''
463#include "mem/protocol/${ident}_Controller.hh"
464#include "mem/protocol/${ident}_Event.hh"
465#include "mem/protocol/${ident}_State.hh"
466#include "mem/protocol/Types.hh"
467#include "mem/ruby/system/RubySystem.hh"
468
469''')
470        for include_path in includes:
471            code('#include "${{include_path}}"')
472
473        code('''
474
475using namespace std;
476''')
477
478        # include object classes
479        seen_types = set()
480        for var in self.objects:
481            if var.type.ident not in seen_types and not var.type.isPrimitive:
482                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
483            seen_types.add(var.type.ident)
484
485        num_in_ports = len(self.in_ports)
486
487        code('''
488$c_ident *
489${c_ident}Params::create()
490{
491    return new $c_ident(this);
492}
493
494int $c_ident::m_num_controllers = 0;
495std::vector<Stats::Vector *>  $c_ident::eventVec;
496std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
497
498// for adding information to the protocol debug trace
499stringstream ${ident}_transitionComment;
500
501#ifndef NDEBUG
502#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
503#else
504#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
505#endif
506
507/** \\brief constructor */
508$c_ident::$c_ident(const Params *p)
509    : AbstractController(p)
510{
511    m_machineID.type = MachineType_${ident};
512    m_machineID.num = m_version;
513    m_num_controllers++;
514
515    m_in_ports = $num_in_ports;
516''')
517        code.indent()
518
519        #
520        # After initializing the universal machine parameters, initialize the
521        # this machines config parameters.  Also if these configuration params
522        # include a sequencer, connect the it to the controller.
523        #
524        for param in self.config_parameters:
525            if param.pointer:
526                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
527            else:
528                code('m_${{param.ident}} = p->${{param.ident}};')
529
530            if re.compile("sequencer").search(param.ident):
531                code('m_${{param.ident}}_ptr->setController(this);')
532
533        code('''
534
535for (int state = 0; state < ${ident}_State_NUM; state++) {
536    for (int event = 0; event < ${ident}_Event_NUM; event++) {
537        m_possible[state][event] = false;
538        m_counters[state][event] = 0;
539    }
540}
541for (int event = 0; event < ${ident}_Event_NUM; event++) {
542    m_event_counters[event] = 0;
543}
544''')
545        code.dedent()
546        code('''
547}
548
549void
550$c_ident::initNetQueues()
551{
552    MachineType machine_type = string_to_MachineType("${{self.ident}}");
553    int base M5_VAR_USED = MachineType_base_number(machine_type);
554
555''')
556        code.indent()
557
558        # set for maintaining the vnet, direction pairs already seen for this
559        # machine.  This map helps in implementing the check for avoiding
560        # multiple message buffers being mapped to the same vnet.
561        vnet_dir_set = set()
562
563        for var in self.config_parameters:
564            vid = "m_%s_ptr" % var.ident
565            if "network" in var:
566                vtype = var.type_ast.type
567                code('assert($vid != NULL);')
568
569                # Network port object
570                network = var["network"]
571
572                if "virtual_network" in var:
573                    vnet = var["virtual_network"]
574                    vnet_type = var["vnet_type"]
575
576                    assert (vnet, network) not in vnet_dir_set
577                    vnet_dir_set.add((vnet,network))
578
579                    code('''
580m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet,
581                                 "$vnet_type", $vid);
582''')
583                # Set Priority
584                if "rank" in var:
585                    code('$vid->setPriority(${{var["rank"]}})')
586
587        code.dedent()
588        code('''
589}
590
591void
592$c_ident::init()
593{
594    // initialize objects
595    initNetQueues();
596''')
597
598        code.indent()
599
600        for var in self.objects:
601            vtype = var.type
602            vid = "m_%s_ptr" % var.ident
603            if "network" not in var:
604                # Not a network port object
605                if "primitive" in vtype:
606                    code('$vid = new ${{vtype.c_ident}};')
607                    if "default" in var:
608                        code('(*$vid) = ${{var["default"]}};')
609                else:
610                    # Normal Object
611                    th = var.get("template", "")
612                    expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
613                    args = ""
614                    if "non_obj" not in vtype and not vtype.isEnumeration:
615                        args = var.get("constructor", "")
616
617                    code('$expr($args);')
618                    code('assert($vid != NULL);')
619
620                    if "default" in var:
621                        code('*$vid = ${{var["default"]}}; // Object default')
622                    elif "default" in vtype:
623                        comment = "Type %s default" % vtype.ident
624                        code('*$vid = ${{vtype["default"]}}; // $comment')
625
626        # Set the prefetchers
627        code()
628        for prefetcher in self.prefetchers:
629            code('${{prefetcher.code}}.setController(this);')
630
631        code()
632        for port in self.in_ports:
633            # Set the queue consumers
634            code('${{port.code}}.setConsumer(this);')
635
636        # Initialize the transition profiling
637        code()
638        for trans in self.transitions:
639            # Figure out if we stall
640            stall = False
641            for action in trans.actions:
642                if action.ident == "z_stall":
643                    stall = True
644
645            # Only possible if it is not a 'z' case
646            if not stall:
647                state = "%s_State_%s" % (self.ident, trans.state.ident)
648                event = "%s_Event_%s" % (self.ident, trans.event.ident)
649                code('possibleTransition($state, $event);')
650
651        code.dedent()
652        code('''
653    AbstractController::init();
654    resetStats();
655}
656''')
657
658        mq_ident = "NULL"
659        for port in self.in_ports:
660            if port.code.find("mandatoryQueue_ptr") >= 0:
661                mq_ident = "m_mandatoryQueue_ptr"
662
663        memq_ident = "NULL"
664        for port in self.in_ports:
665            if port.code.find("responseFromMemory_ptr") >= 0:
666                memq_ident = "m_responseFromMemory_ptr"
667
668        seq_ident = "NULL"
669        for param in self.config_parameters:
670            if param.ident == "sequencer":
671                assert(param.pointer)
672                seq_ident = "m_%s_ptr" % param.ident
673
674        code('''
675
676void
677$c_ident::regStats()
678{
679    AbstractController::regStats();
680
681    if (m_version == 0) {
682        for (${ident}_Event event = ${ident}_Event_FIRST;
683             event < ${ident}_Event_NUM; ++event) {
684            Stats::Vector *t = new Stats::Vector();
685            t->init(m_num_controllers);
686            t->name(params()->ruby_system->name() + ".${c_ident}." +
687                ${ident}_Event_to_string(event));
688            t->flags(Stats::pdf | Stats::total | Stats::oneline |
689                     Stats::nozero);
690
691            eventVec.push_back(t);
692        }
693
694        for (${ident}_State state = ${ident}_State_FIRST;
695             state < ${ident}_State_NUM; ++state) {
696
697            transVec.push_back(std::vector<Stats::Vector *>());
698
699            for (${ident}_Event event = ${ident}_Event_FIRST;
700                 event < ${ident}_Event_NUM; ++event) {
701
702                Stats::Vector *t = new Stats::Vector();
703                t->init(m_num_controllers);
704                t->name(params()->ruby_system->name() + ".${c_ident}." +
705                        ${ident}_State_to_string(state) +
706                        "." + ${ident}_Event_to_string(event));
707
708                t->flags(Stats::pdf | Stats::total | Stats::oneline |
709                         Stats::nozero);
710                transVec[state].push_back(t);
711            }
712        }
713    }
714}
715
716void
717$c_ident::collateStats()
718{
719    for (${ident}_Event event = ${ident}_Event_FIRST;
720         event < ${ident}_Event_NUM; ++event) {
721        for (unsigned int i = 0; i < m_num_controllers; ++i) {
722            RubySystem *rs = params()->ruby_system;
723            std::map<uint32_t, AbstractController *>::iterator it =
724                     rs->m_abstract_controls[MachineType_${ident}].find(i);
725            assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
726            (*eventVec[event])[i] =
727                (($c_ident *)(*it).second)->getEventCount(event);
728        }
729    }
730
731    for (${ident}_State state = ${ident}_State_FIRST;
732         state < ${ident}_State_NUM; ++state) {
733
734        for (${ident}_Event event = ${ident}_Event_FIRST;
735             event < ${ident}_Event_NUM; ++event) {
736
737            for (unsigned int i = 0; i < m_num_controllers; ++i) {
738                RubySystem *rs = params()->ruby_system;
739                std::map<uint32_t, AbstractController *>::iterator it =
740                         rs->m_abstract_controls[MachineType_${ident}].find(i);
741                assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
742                (*transVec[state][event])[i] =
743                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
744            }
745        }
746    }
747}
748
749void
750$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
751{
752    assert(m_possible[state][event]);
753    m_counters[state][event]++;
754    m_event_counters[event]++;
755}
756void
757$c_ident::possibleTransition(${ident}_State state,
758                             ${ident}_Event event)
759{
760    m_possible[state][event] = true;
761}
762
763uint64_t
764$c_ident::getEventCount(${ident}_Event event)
765{
766    return m_event_counters[event];
767}
768
769bool
770$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
771{
772    return m_possible[state][event];
773}
774
775uint64_t
776$c_ident::getTransitionCount(${ident}_State state,
777                             ${ident}_Event event)
778{
779    return m_counters[state][event];
780}
781
782int
783$c_ident::getNumControllers()
784{
785    return m_num_controllers;
786}
787
788MessageBuffer*
789$c_ident::getMandatoryQueue() const
790{
791    return $mq_ident;
792}
793
794MessageBuffer*
795$c_ident::getMemoryQueue() const
796{
797    return $memq_ident;
798}
799
800Sequencer*
801$c_ident::getSequencer() const
802{
803    return $seq_ident;
804}
805
806void
807$c_ident::print(ostream& out) const
808{
809    out << "[$c_ident " << m_version << "]";
810}
811
812void $c_ident::resetStats()
813{
814    for (int state = 0; state < ${ident}_State_NUM; state++) {
815        for (int event = 0; event < ${ident}_Event_NUM; event++) {
816            m_counters[state][event] = 0;
817        }
818    }
819
820    for (int event = 0; event < ${ident}_Event_NUM; event++) {
821        m_event_counters[event] = 0;
822    }
823
824    AbstractController::resetStats();
825}
826''')
827
828        if self.EntryType != None:
829            code('''
830
831// Set and Reset for cache_entry variable
832void
833$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
834{
835  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
836}
837
838void
839$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
840{
841  m_cache_entry_ptr = 0;
842}
843''')
844
845        if self.TBEType != None:
846            code('''
847
848// Set and Reset for tbe variable
849void
850$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
851{
852  m_tbe_ptr = m_new_tbe;
853}
854
855void
856$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
857{
858  m_tbe_ptr = NULL;
859}
860''')
861
862        code('''
863
864void
865$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
866{
867''')
868        #
869        # Record cache contents for all associated caches.
870        #
871        code.indent()
872        for param in self.config_parameters:
873            if param.type_ast.type.ident == "CacheMemory":
874                assert(param.pointer)
875                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
876
877        code.dedent()
878        code('''
879}
880
881// Actions
882''')
883        if self.TBEType != None and self.EntryType != None:
884            for action in self.actions.itervalues():
885                if "c_code" not in action:
886                 continue
887
888                code('''
889/** \\brief ${{action.desc}} */
890void
891$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
892{
893    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
894    try {
895       ${{action["c_code"]}}
896    } catch (const RejectException & e) {
897       fatal("Error in action ${{ident}}:${{action.ident}}: "
898             "executed a peek statement with the wrong message "
899             "type specified. ");
900    }
901}
902
903''')
904        elif self.TBEType != None:
905            for action in self.actions.itervalues():
906                if "c_code" not in action:
907                 continue
908
909                code('''
910/** \\brief ${{action.desc}} */
911void
912$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr)
913{
914    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
915    ${{action["c_code"]}}
916}
917
918''')
919        elif self.EntryType != None:
920            for action in self.actions.itervalues():
921                if "c_code" not in action:
922                 continue
923
924                code('''
925/** \\brief ${{action.desc}} */
926void
927$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
928{
929    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
930    ${{action["c_code"]}}
931}
932
933''')
934        else:
935            for action in self.actions.itervalues():
936                if "c_code" not in action:
937                 continue
938
939                code('''
940/** \\brief ${{action.desc}} */
941void
942$c_ident::${{action.ident}}(Addr addr)
943{
944    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
945    ${{action["c_code"]}}
946}
947
948''')
949        for func in self.functions:
950            code(func.generateCode())
951
952        # Function for functional writes to messages buffered in the controller
953        code('''
954int
955$c_ident::functionalWriteBuffers(PacketPtr& pkt)
956{
957    int num_functional_writes = 0;
958''')
959        for var in self.objects:
960            vtype = var.type
961            if vtype.isBuffer:
962                vid = "m_%s_ptr" % var.ident
963                code('num_functional_writes += $vid->functionalWrite(pkt);')
964
965        for var in self.config_parameters:
966            vtype = var.type_ast.type
967            if vtype.isBuffer:
968                vid = "m_%s_ptr" % var.ident
969                code('num_functional_writes += $vid->functionalWrite(pkt);')
970
971        code('''
972    return num_functional_writes;
973}
974''')
975
976        code.write(path, "%s.cc" % c_ident)
977
978    def printCWakeup(self, path, includes):
979        '''Output the wakeup loop for the events'''
980
981        code = self.symtab.codeFormatter()
982        ident = self.ident
983
984        outputRequest_types = True
985        if len(self.request_types) == 0:
986            outputRequest_types = False
987
988        code('''
989// Auto generated C++ code started by $__file__:$__line__
990// ${ident}: ${{self.short}}
991
992#include <sys/types.h>
993#include <unistd.h>
994
995#include <cassert>
996#include <typeinfo>
997
998#include "base/misc.hh"
999
1000''')
1001        for f in self.debug_flags:
1002            code('#include "debug/${{f}}.hh"')
1003        code('''
1004#include "mem/protocol/${ident}_Controller.hh"
1005#include "mem/protocol/${ident}_Event.hh"
1006#include "mem/protocol/${ident}_State.hh"
1007
1008''')
1009
1010        if outputRequest_types:
1011            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1012
1013        code('''
1014#include "mem/protocol/Types.hh"
1015#include "mem/ruby/system/RubySystem.hh"
1016
1017''')
1018
1019
1020        for include_path in includes:
1021            code('#include "${{include_path}}"')
1022
1023        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1024
1025        code('''
1026
1027using namespace std;
1028
1029void
1030${ident}_Controller::wakeup()
1031{
1032    int counter = 0;
1033    while (true) {
1034        unsigned char rejected[${{len(msg_bufs)}}];
1035        memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
1036        // Some cases will put us into an infinite loop without this limit
1037        assert(counter <= m_transitions_per_cycle);
1038        if (counter == m_transitions_per_cycle) {
1039            // Count how often we are fully utilized
1040            m_fully_busy_cycles++;
1041
1042            // Wakeup in another cycle and try again
1043            scheduleEvent(Cycles(1));
1044            break;
1045        }
1046''')
1047
1048        code.indent()
1049        code.indent()
1050
1051        # InPorts
1052        #
1053        for port in self.in_ports:
1054            code.indent()
1055            code('// ${ident}InPort $port')
1056            if port.pairs.has_key("rank"):
1057                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1058            else:
1059                code('m_cur_in_port = 0;')
1060            if port in port_to_buf_map:
1061                code('try {')
1062                code.indent()
1063            code('${{port["c_code_in_port"]}}')
1064
1065            if port in port_to_buf_map:
1066                code.dedent()
1067                code('''
1068            } catch (const RejectException & e) {
1069                rejected[${{port_to_buf_map[port]}}]++;
1070            }
1071''')
1072            code.dedent()
1073            code('')
1074
1075        code.dedent()
1076        code.dedent()
1077        code('''
1078        // If we got this far, we have nothing left todo or something went
1079        // wrong''')
1080        for buf_name, ports in in_msg_bufs.items():
1081            if len(ports) > 1:
1082                # only produce checks when a buffer is shared by multiple ports
1083                code('''
1084        if (${{buf_name}}->isReady() && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
1085        {
1086            // no port claimed the message on the top of this buffer
1087            panic("Runtime Error at Ruby Time: %d. "
1088                  "All ports rejected a message. "
1089                  "You are probably sending a message type to this controller "
1090                  "over a virtual network that do not define an in_port for "
1091                  "the incoming message type.\\n",
1092                  Cycles(1));
1093        }
1094''')
1095        code('''
1096        break;
1097    }
1098}
1099''')
1100
1101        code.write(path, "%s_Wakeup.cc" % self.ident)
1102
1103    def printCSwitch(self, path):
1104        '''Output switch statement for transition table'''
1105
1106        code = self.symtab.codeFormatter()
1107        ident = self.ident
1108
1109        code('''
1110// Auto generated C++ code started by $__file__:$__line__
1111// ${ident}: ${{self.short}}
1112
1113#include <cassert>
1114
1115#include "base/misc.hh"
1116#include "base/trace.hh"
1117#include "debug/ProtocolTrace.hh"
1118#include "debug/RubyGenerated.hh"
1119#include "mem/protocol/${ident}_Controller.hh"
1120#include "mem/protocol/${ident}_Event.hh"
1121#include "mem/protocol/${ident}_State.hh"
1122#include "mem/protocol/Types.hh"
1123#include "mem/ruby/system/RubySystem.hh"
1124
1125#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1126
1127#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1128#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1129
1130TransitionResult
1131${ident}_Controller::doTransition(${ident}_Event event,
1132''')
1133        if self.EntryType != None:
1134            code('''
1135                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1136''')
1137        if self.TBEType != None:
1138            code('''
1139                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1140''')
1141        code('''
1142                                  Addr addr)
1143{
1144''')
1145        code.indent()
1146
1147        if self.TBEType != None and self.EntryType != None:
1148            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1149        elif self.TBEType != None:
1150            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1151        elif self.EntryType != None:
1152            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1153        else:
1154            code('${ident}_State state = getState(addr);')
1155
1156        code('''
1157${ident}_State next_state = state;
1158
1159DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1160        *this, curCycle(), ${ident}_State_to_string(state),
1161        ${ident}_Event_to_string(event), addr);
1162
1163TransitionResult result =
1164''')
1165        if self.TBEType != None and self.EntryType != None:
1166            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1167        elif self.TBEType != None:
1168            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1169        elif self.EntryType != None:
1170            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1171        else:
1172            code('doTransitionWorker(event, state, next_state, addr);')
1173
1174        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1175
1176        code('''
1177
1178if (result == TransitionResult_Valid) {
1179    DPRINTF(RubyGenerated, "next_state: %s\\n",
1180            ${ident}_State_to_string(next_state));
1181    countTransition(state, event);
1182
1183    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n",
1184             curTick(), m_version, "${ident}",
1185             ${ident}_Event_to_string(event),
1186             ${ident}_State_to_string(state),
1187             ${ident}_State_to_string(next_state),
1188             addr, GET_TRANSITION_COMMENT());
1189
1190    CLEAR_TRANSITION_COMMENT();
1191''')
1192        if self.TBEType != None and self.EntryType != None:
1193            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1194            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1195        elif self.TBEType != None:
1196            code('setState(m_tbe_ptr, addr, next_state);')
1197            code('setAccessPermission(addr, next_state);')
1198        elif self.EntryType != None:
1199            code('setState(m_cache_entry_ptr, addr, next_state);')
1200            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1201        else:
1202            code('setState(addr, next_state);')
1203            code('setAccessPermission(addr, next_state);')
1204
1205        code('''
1206} else if (result == TransitionResult_ResourceStall) {
1207    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1208             curTick(), m_version, "${ident}",
1209             ${ident}_Event_to_string(event),
1210             ${ident}_State_to_string(state),
1211             ${ident}_State_to_string(next_state),
1212             addr, "Resource Stall");
1213} else if (result == TransitionResult_ProtocolStall) {
1214    DPRINTF(RubyGenerated, "stalling\\n");
1215    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1216             curTick(), m_version, "${ident}",
1217             ${ident}_Event_to_string(event),
1218             ${ident}_State_to_string(state),
1219             ${ident}_State_to_string(next_state),
1220             addr, "Protocol Stall");
1221}
1222
1223return result;
1224''')
1225        code.dedent()
1226        code('''
1227}
1228
1229TransitionResult
1230${ident}_Controller::doTransitionWorker(${ident}_Event event,
1231                                        ${ident}_State state,
1232                                        ${ident}_State& next_state,
1233''')
1234
1235        if self.TBEType != None:
1236            code('''
1237                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1238''')
1239        if self.EntryType != None:
1240                  code('''
1241                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1242''')
1243        code('''
1244                                        Addr addr)
1245{
1246    switch(HASH_FUN(state, event)) {
1247''')
1248
1249        # This map will allow suppress generating duplicate code
1250        cases = orderdict()
1251
1252        for trans in self.transitions:
1253            case_string = "%s_State_%s, %s_Event_%s" % \
1254                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1255
1256            case = self.symtab.codeFormatter()
1257            # Only set next_state if it changes
1258            if trans.state != trans.nextState:
1259                if trans.nextState.isWildcard():
1260                    # When * is encountered as an end state of a transition,
1261                    # the next state is determined by calling the
1262                    # machine-specific getNextState function. The next state
1263                    # is determined before any actions of the transition
1264                    # execute, and therefore the next state calculation cannot
1265                    # depend on any of the transitionactions.
1266                    case('next_state = getNextState(addr);')
1267                else:
1268                    ns_ident = trans.nextState.ident
1269                    case('next_state = ${ident}_State_${ns_ident};')
1270
1271            actions = trans.actions
1272            request_types = trans.request_types
1273
1274            # Check for resources
1275            case_sorter = []
1276            res = trans.resources
1277            for key,val in res.iteritems():
1278                val = '''
1279if (!%s.areNSlotsAvailable(%s, clockEdge()))
1280    return TransitionResult_ResourceStall;
1281''' % (key.code, val)
1282                case_sorter.append(val)
1283
1284            # Check all of the request_types for resource constraints
1285            for request_type in request_types:
1286                val = '''
1287if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1288    return TransitionResult_ResourceStall;
1289}
1290''' % (self.ident, request_type.ident)
1291                case_sorter.append(val)
1292
1293            # Emit the code sequences in a sorted order.  This makes the
1294            # output deterministic (without this the output order can vary
1295            # since Map's keys() on a vector of pointers is not deterministic
1296            for c in sorted(case_sorter):
1297                case("$c")
1298
1299            # Record access types for this transition
1300            for request_type in request_types:
1301                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1302
1303            # Figure out if we stall
1304            stall = False
1305            for action in actions:
1306                if action.ident == "z_stall":
1307                    stall = True
1308                    break
1309
1310            if stall:
1311                case('return TransitionResult_ProtocolStall;')
1312            else:
1313                if self.TBEType != None and self.EntryType != None:
1314                    for action in actions:
1315                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1316                elif self.TBEType != None:
1317                    for action in actions:
1318                        case('${{action.ident}}(m_tbe_ptr, addr);')
1319                elif self.EntryType != None:
1320                    for action in actions:
1321                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1322                else:
1323                    for action in actions:
1324                        case('${{action.ident}}(addr);')
1325                case('return TransitionResult_Valid;')
1326
1327            case = str(case)
1328
1329            # Look to see if this transition code is unique.
1330            if case not in cases:
1331                cases[case] = []
1332
1333            cases[case].append(case_string)
1334
1335        # Walk through all of the unique code blocks and spit out the
1336        # corresponding case statement elements
1337        for case,transitions in cases.iteritems():
1338            # Iterative over all the multiple transitions that share
1339            # the same code
1340            for trans in transitions:
1341                code('  case HASH_FUN($trans):')
1342            code('    $case\n')
1343
1344        code('''
1345      default:
1346        panic("Invalid transition\\n"
1347              "%s time: %d addr: %s event: %s state: %s\\n",
1348              name(), curCycle(), addr, event, state);
1349    }
1350
1351    return TransitionResult_Valid;
1352}
1353''')
1354        code.write(path, "%s_Transitions.cc" % self.ident)
1355
1356
1357    # **************************
1358    # ******* HTML Files *******
1359    # **************************
1360    def frameRef(self, click_href, click_target, over_href, over_num, text):
1361        code = self.symtab.codeFormatter(fix_newlines=False)
1362        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1363    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1364        parent.frames[$over_num].location='$over_href'
1365    }\">
1366    ${{html.formatShorthand(text)}}
1367    </A>""")
1368        return str(code)
1369
1370    def writeHTMLFiles(self, path):
1371        # Create table with no row hilighted
1372        self.printHTMLTransitions(path, None)
1373
1374        # Generate transition tables
1375        for state in self.states.itervalues():
1376            self.printHTMLTransitions(path, state)
1377
1378        # Generate action descriptions
1379        for action in self.actions.itervalues():
1380            name = "%s_action_%s.html" % (self.ident, action.ident)
1381            code = html.createSymbol(action, "Action")
1382            code.write(path, name)
1383
1384        # Generate state descriptions
1385        for state in self.states.itervalues():
1386            name = "%s_State_%s.html" % (self.ident, state.ident)
1387            code = html.createSymbol(state, "State")
1388            code.write(path, name)
1389
1390        # Generate event descriptions
1391        for event in self.events.itervalues():
1392            name = "%s_Event_%s.html" % (self.ident, event.ident)
1393            code = html.createSymbol(event, "Event")
1394            code.write(path, name)
1395
1396    def printHTMLTransitions(self, path, active_state):
1397        code = self.symtab.codeFormatter()
1398
1399        code('''
1400<HTML>
1401<BODY link="blue" vlink="blue">
1402
1403<H1 align="center">${{html.formatShorthand(self.short)}}:
1404''')
1405        code.indent()
1406        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1407            mid = machine.ident
1408            if i != 0:
1409                extra = " - "
1410            else:
1411                extra = ""
1412            if machine == self:
1413                code('$extra$mid')
1414            else:
1415                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1416        code.dedent()
1417
1418        code("""
1419</H1>
1420
1421<TABLE border=1>
1422<TR>
1423  <TH> </TH>
1424""")
1425
1426        for event in self.events.itervalues():
1427            href = "%s_Event_%s.html" % (self.ident, event.ident)
1428            ref = self.frameRef(href, "Status", href, "1", event.short)
1429            code('<TH bgcolor=white>$ref</TH>')
1430
1431        code('</TR>')
1432        # -- Body of table
1433        for state in self.states.itervalues():
1434            # -- Each row
1435            if state == active_state:
1436                color = "yellow"
1437            else:
1438                color = "white"
1439
1440            click = "%s_table_%s.html" % (self.ident, state.ident)
1441            over = "%s_State_%s.html" % (self.ident, state.ident)
1442            text = html.formatShorthand(state.short)
1443            ref = self.frameRef(click, "Table", over, "1", state.short)
1444            code('''
1445<TR>
1446  <TH bgcolor=$color>$ref</TH>
1447''')
1448
1449            # -- One column for each event
1450            for event in self.events.itervalues():
1451                trans = self.table.get((state,event), None)
1452                if trans is None:
1453                    # This is the no transition case
1454                    if state == active_state:
1455                        color = "#C0C000"
1456                    else:
1457                        color = "lightgrey"
1458
1459                    code('<TD bgcolor=$color>&nbsp;</TD>')
1460                    continue
1461
1462                next = trans.nextState
1463                stall_action = False
1464
1465                # -- Get the actions
1466                for action in trans.actions:
1467                    if action.ident == "z_stall" or \
1468                       action.ident == "zz_recycleMandatoryQueue":
1469                        stall_action = True
1470
1471                # -- Print out "actions/next-state"
1472                if stall_action:
1473                    if state == active_state:
1474                        color = "#C0C000"
1475                    else:
1476                        color = "lightgrey"
1477
1478                elif active_state and next.ident == active_state.ident:
1479                    color = "aqua"
1480                elif state == active_state:
1481                    color = "yellow"
1482                else:
1483                    color = "white"
1484
1485                code('<TD bgcolor=$color>')
1486                for action in trans.actions:
1487                    href = "%s_action_%s.html" % (self.ident, action.ident)
1488                    ref = self.frameRef(href, "Status", href, "1",
1489                                        action.short)
1490                    code('  $ref')
1491                if next != state:
1492                    if trans.actions:
1493                        code('/')
1494                    click = "%s_table_%s.html" % (self.ident, next.ident)
1495                    over = "%s_State_%s.html" % (self.ident, next.ident)
1496                    ref = self.frameRef(click, "Table", over, "1", next.short)
1497                    code("$ref")
1498                code("</TD>")
1499
1500            # -- Each row
1501            if state == active_state:
1502                color = "yellow"
1503            else:
1504                color = "white"
1505
1506            click = "%s_table_%s.html" % (self.ident, state.ident)
1507            over = "%s_State_%s.html" % (self.ident, state.ident)
1508            ref = self.frameRef(click, "Table", over, "1", state.short)
1509            code('''
1510  <TH bgcolor=$color>$ref</TH>
1511</TR>
1512''')
1513        code('''
1514<!- Column footer->
1515<TR>
1516  <TH> </TH>
1517''')
1518
1519        for event in self.events.itervalues():
1520            href = "%s_Event_%s.html" % (self.ident, event.ident)
1521            ref = self.frameRef(href, "Status", href, "1", event.short)
1522            code('<TH bgcolor=white>$ref</TH>')
1523        code('''
1524</TR>
1525</TABLE>
1526</BODY></HTML>
1527''')
1528
1529
1530        if active_state:
1531            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1532        else:
1533            name = "%s_table.html" % self.ident
1534        code.write(path, name)
1535
1536__all__ = [ "StateMachine" ]
1537