StateMachine.py revision 11308
111923Sandreas.sandberg@arm.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
211923Sandreas.sandberg@arm.com# Copyright (c) 2009 The Hewlett-Packard Development Company
311923Sandreas.sandberg@arm.com# Copyright (c) 2013 Advanced Micro Devices, Inc.
411923Sandreas.sandberg@arm.com# All rights reserved.
511923Sandreas.sandberg@arm.com#
611923Sandreas.sandberg@arm.com# Redistribution and use in source and binary forms, with or without
711923Sandreas.sandberg@arm.com# modification, are permitted provided that the following conditions are
811923Sandreas.sandberg@arm.com# met: redistributions of source code must retain the above copyright
911923Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer;
1011923Sandreas.sandberg@arm.com# redistributions in binary form must reproduce the above copyright
1111923Sandreas.sandberg@arm.com# notice, this list of conditions and the following disclaimer in the
1211923Sandreas.sandberg@arm.com# documentation and/or other materials provided with the distribution;
136654Snate@binkert.org# neither the name of the copyright holders nor the names of its
146654Snate@binkert.org# contributors may be used to endorse or promote products derived from
155467Snate@binkert.org# this software without specific prior written permission.
165467Snate@binkert.org#
175467Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
185467Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
195467Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
205467Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
215467Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
225467Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
235467Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245467Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255467Snate@binkert.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265467Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
275467Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285467Snate@binkert.org
295467Snate@binkert.orgfrom m5.util import orderdict
305467Snate@binkert.org
315467Snate@binkert.orgfrom slicc.symbols.Symbol import Symbol
325467Snate@binkert.orgfrom slicc.symbols.Var import Var
335467Snate@binkert.orgimport slicc.generate.html as html
345467Snate@binkert.orgimport re
355467Snate@binkert.org
365467Snate@binkert.orgpython_class_map = {
375467Snate@binkert.org                    "int": "Int",
385467Snate@binkert.org                    "NodeID": "Int",
395467Snate@binkert.org                    "uint32_t" : "UInt32",
405467Snate@binkert.org                    "std::string": "String",
415467Snate@binkert.org                    "bool": "Bool",
426654Snate@binkert.org                    "CacheMemory": "RubyCache",
436654Snate@binkert.org                    "WireBuffer": "RubyWireBuffer",
446654Snate@binkert.org                    "Sequencer": "RubySequencer",
456654Snate@binkert.org                    "GPUCoalescer" : "RubyGPUCoalescer",
466654Snate@binkert.org                    "VIPERCoalescer" : "VIPERCoalescer",
476654Snate@binkert.org                    "DirectoryMemory": "RubyDirectoryMemory",
486654Snate@binkert.org                    "PerfectCacheMemory": "RubyPerfectCacheMemory",
497459Snate@binkert.org                    "MemoryControl": "MemoryControl",
506502Snate@binkert.org                    "MessageBuffer": "MessageBuffer",
515467Snate@binkert.org                    "DMASequencer": "DMASequencer",
526500Snate@binkert.org                    "Prefetcher":"Prefetcher",
536654Snate@binkert.org                    "Cycles":"Cycles",
547503Snate@binkert.org                   }
555873Snate@binkert.org
566654Snate@binkert.orgclass StateMachine(Symbol):
576654Snate@binkert.org    def __init__(self, symtab, ident, location, pairs, config_parameters):
586654Snate@binkert.org        super(StateMachine, self).__init__(symtab, ident, location, pairs)
596654Snate@binkert.org        self.table = None
606654Snate@binkert.org
616654Snate@binkert.org        # Data members in the State Machine that have been declared before
626654Snate@binkert.org        # the opening brace '{'  of the machine.  Note that these along with
636654Snate@binkert.org        # the members in self.objects form the entire set of data members.
646654Snate@binkert.org        self.config_parameters = config_parameters
656654Snate@binkert.org
666654Snate@binkert.org        self.prefetchers = []
676654Snate@binkert.org
686654Snate@binkert.org        for param in config_parameters:
696654Snate@binkert.org            if param.pointer:
709528Ssascha.bischoff@arm.com                var = Var(symtab, param.ident, location, param.type_ast.type,
719528Ssascha.bischoff@arm.com                          "(*m_%s_ptr)" % param.ident, {}, self)
729528Ssascha.bischoff@arm.com            else:
739528Ssascha.bischoff@arm.com                var = Var(symtab, param.ident, location, param.type_ast.type,
749528Ssascha.bischoff@arm.com                          "m_%s" % param.ident, {}, self)
759528Ssascha.bischoff@arm.com
769528Ssascha.bischoff@arm.com            self.symtab.registerSym(param.ident, var)
779528Ssascha.bischoff@arm.com
789528Ssascha.bischoff@arm.com            if str(param.type_ast.type) == "Prefetcher":
799528Ssascha.bischoff@arm.com                self.prefetchers.append(var)
809528Ssascha.bischoff@arm.com
816654Snate@binkert.org        self.states = orderdict()
826654Snate@binkert.org        self.events = orderdict()
836654Snate@binkert.org        self.actions = orderdict()
846654Snate@binkert.org        self.request_types = orderdict()
856654Snate@binkert.org        self.transitions = []
866654Snate@binkert.org        self.in_ports = []
876654Snate@binkert.org        self.functions = []
886654Snate@binkert.org
896654Snate@binkert.org        # Data members in the State Machine that have been declared inside
906654Snate@binkert.org        # the {} machine.  Note that these along with the config params
916654Snate@binkert.org        # form the entire set of data members of the machine.
926654Snate@binkert.org        self.objects = []
936654Snate@binkert.org        self.TBEType   = None
946654Snate@binkert.org        self.EntryType = None
956654Snate@binkert.org        self.debug_flags = set()
966654Snate@binkert.org        self.debug_flags.add('RubyGenerated')
976654Snate@binkert.org        self.debug_flags.add('RubySlicc')
986654Snate@binkert.org
996654Snate@binkert.org    def __repr__(self):
1006654Snate@binkert.org        return "[StateMachine: %s]" % self.ident
1016654Snate@binkert.org
1026654Snate@binkert.org    def addState(self, state):
1036654Snate@binkert.org        assert self.table is None
1046654Snate@binkert.org        self.states[state.ident] = state
1056654Snate@binkert.org
1066654Snate@binkert.org    def addEvent(self, event):
1076654Snate@binkert.org        assert self.table is None
1086654Snate@binkert.org        self.events[event.ident] = event
1096654Snate@binkert.org
1106654Snate@binkert.org    def addAction(self, action):
1116654Snate@binkert.org        assert self.table is None
1126654Snate@binkert.org
1136654Snate@binkert.org        # Check for duplicate action
1146654Snate@binkert.org        for other in self.actions.itervalues():
1156654Snate@binkert.org            if action.ident == other.ident:
1166654Snate@binkert.org                action.warning("Duplicate action definition: %s" % action.ident)
1176654Snate@binkert.org                action.error("Duplicate action definition: %s" % action.ident)
1186654Snate@binkert.org            if action.short == other.short:
1196654Snate@binkert.org                other.warning("Duplicate action shorthand: %s" % other.ident)
1206654Snate@binkert.org                other.warning("    shorthand = %s" % other.short)
1216654Snate@binkert.org                action.warning("Duplicate action shorthand: %s" % action.ident)
1226654Snate@binkert.org                action.error("    shorthand = %s" % action.short)
1236654Snate@binkert.org
1246654Snate@binkert.org        self.actions[action.ident] = action
1256654Snate@binkert.org
1266654Snate@binkert.org    def addDebugFlag(self, flag):
1276654Snate@binkert.org        self.debug_flags.add(flag)
1286654Snate@binkert.org
1296654Snate@binkert.org    def addRequestType(self, request_type):
1306654Snate@binkert.org        assert self.table is None
1316654Snate@binkert.org        self.request_types[request_type.ident] = request_type
1326654Snate@binkert.org
1336654Snate@binkert.org    def addTransition(self, trans):
1346654Snate@binkert.org        assert self.table is None
1356654Snate@binkert.org        self.transitions.append(trans)
1366654Snate@binkert.org
1376654Snate@binkert.org    def addInPort(self, var):
1386654Snate@binkert.org        self.in_ports.append(var)
1396654Snate@binkert.org
1406654Snate@binkert.org    def addFunc(self, func):
1416654Snate@binkert.org        # register func in the symbol table
1426654Snate@binkert.org        self.symtab.registerSym(str(func), func)
1436654Snate@binkert.org        self.functions.append(func)
1446654Snate@binkert.org
1456654Snate@binkert.org    def addObject(self, obj):
1466654Snate@binkert.org        self.symtab.registerSym(str(obj), obj)
1476654Snate@binkert.org        self.objects.append(obj)
1486654Snate@binkert.org
1496654Snate@binkert.org    def addType(self, type):
1506654Snate@binkert.org        type_ident = '%s' % type.c_ident
1516654Snate@binkert.org
1526654Snate@binkert.org        if type_ident == "%s_TBE" %self.ident:
1536654Snate@binkert.org            if self.TBEType != None:
1546654Snate@binkert.org                self.error("Multiple Transaction Buffer types in a " \
1556654Snate@binkert.org                           "single machine.");
1566654Snate@binkert.org            self.TBEType = type
1576654Snate@binkert.org
1586654Snate@binkert.org        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
1596654Snate@binkert.org            if "main" in type and "false" == type["main"].lower():
1606654Snate@binkert.org                pass # this isn't the EntryType
1616654Snate@binkert.org            else:
1626654Snate@binkert.org                if self.EntryType != None:
1636654Snate@binkert.org                    self.error("Multiple AbstractCacheEntry types in a " \
1646654Snate@binkert.org                               "single machine.");
1656654Snate@binkert.org                self.EntryType = type
1665873Snate@binkert.org
1675873Snate@binkert.org    # Needs to be called before accessing the table
1685873Snate@binkert.org    def buildTable(self):
1695873Snate@binkert.org        assert self.table is None
1705873Snate@binkert.org
1715873Snate@binkert.org        table = {}
1725873Snate@binkert.org
1735873Snate@binkert.org        for trans in self.transitions:
1745873Snate@binkert.org            # Track which actions we touch so we know if we use them
1755873Snate@binkert.org            # all -- really this should be done for all symbols as
1765873Snate@binkert.org            # part of the symbol table, then only trigger it for
1776654Snate@binkert.org            # Actions, States, Events, etc.
1786654Snate@binkert.org
1796654Snate@binkert.org            for action in trans.actions:
1806654Snate@binkert.org                action.used = True
1816654Snate@binkert.org
1826654Snate@binkert.org            index = (trans.state, trans.event)
1836654Snate@binkert.org            if index in table:
1846654Snate@binkert.org                table[index].warning("Duplicate transition: %s" % table[index])
1856654Snate@binkert.org                trans.error("Duplicate transition: %s" % trans)
1866654Snate@binkert.org            table[index] = trans
1876654Snate@binkert.org
18811320Ssteve.reinhardt@amd.com        # Look at all actions to make sure we used them all
1896654Snate@binkert.org        for action in self.actions.itervalues():
1906654Snate@binkert.org            if not action.used:
1916654Snate@binkert.org                error_msg = "Unused action: %s" % action.ident
1926654Snate@binkert.org                if "desc" in action:
1936654Snate@binkert.org                    error_msg += ", "  + action.desc
1946654Snate@binkert.org                action.warning(error_msg)
1956654Snate@binkert.org        self.table = table
1966654Snate@binkert.org
1976654Snate@binkert.org    # determine the port->msg buffer mappings
1986654Snate@binkert.org    def getBufferMaps(self, ident):
1996654Snate@binkert.org        msg_bufs = []
2006654Snate@binkert.org        port_to_buf_map = {}
2018453Snate@binkert.org        in_msg_bufs = {}
2028453Snate@binkert.org        for port in self.in_ports:
2038453Snate@binkert.org            buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name
2048453Snate@binkert.org            msg_bufs.append(buf_name)
2058453Snate@binkert.org            port_to_buf_map[port] = msg_bufs.index(buf_name)
2068453Snate@binkert.org            if buf_name not in in_msg_bufs:
2078453Snate@binkert.org                in_msg_bufs[buf_name] = [port]
2088453Snate@binkert.org            else:
2098453Snate@binkert.org                in_msg_bufs[buf_name].append(port)
21011923Sandreas.sandberg@arm.com        return port_to_buf_map, in_msg_bufs, msg_bufs
21111923Sandreas.sandberg@arm.com
21211923Sandreas.sandberg@arm.com    def writeCodeFiles(self, path, includes):
21311923Sandreas.sandberg@arm.com        self.printControllerPython(path)
21411923Sandreas.sandberg@arm.com        self.printControllerHH(path)
215        self.printControllerCC(path, includes)
216        self.printCSwitch(path)
217        self.printCWakeup(path, includes)
218
219    def printControllerPython(self, path):
220        code = self.symtab.codeFormatter()
221        ident = self.ident
222
223        py_ident = "%s_Controller" % ident
224        c_ident = "%s_Controller" % self.ident
225
226        code('''
227from m5.params import *
228from m5.SimObject import SimObject
229from Controller import RubyController
230
231class $py_ident(RubyController):
232    type = '$py_ident'
233    cxx_header = 'mem/protocol/${c_ident}.hh'
234''')
235        code.indent()
236        for param in self.config_parameters:
237            dflt_str = ''
238
239            if param.rvalue is not None:
240                dflt_str = str(param.rvalue.inline()) + ', '
241
242            if python_class_map.has_key(param.type_ast.type.c_ident):
243                python_type = python_class_map[param.type_ast.type.c_ident]
244                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
245
246            else:
247                self.error("Unknown c++ to python class conversion for c++ " \
248                           "type: '%s'. Please update the python_class_map " \
249                           "in StateMachine.py", param.type_ast.type.c_ident)
250
251        code.dedent()
252        code.write(path, '%s.py' % py_ident)
253
254
255    def printControllerHH(self, path):
256        '''Output the method declarations for the class declaration'''
257        code = self.symtab.codeFormatter()
258        ident = self.ident
259        c_ident = "%s_Controller" % self.ident
260
261        code('''
262/** \\file $c_ident.hh
263 *
264 * Auto generated C++ code started by $__file__:$__line__
265 * Created by slicc definition of Module "${{self.short}}"
266 */
267
268#ifndef __${ident}_CONTROLLER_HH__
269#define __${ident}_CONTROLLER_HH__
270
271#include <iostream>
272#include <sstream>
273#include <string>
274
275#include "mem/protocol/TransitionResult.hh"
276#include "mem/protocol/Types.hh"
277#include "mem/ruby/common/Consumer.hh"
278#include "mem/ruby/slicc_interface/AbstractController.hh"
279#include "params/$c_ident.hh"
280
281''')
282
283        seen_types = set()
284        for var in self.objects:
285            if var.type.ident not in seen_types and not var.type.isPrimitive:
286                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
287                seen_types.add(var.type.ident)
288
289        # for adding information to the protocol debug trace
290        code('''
291extern std::stringstream ${ident}_transitionComment;
292
293class $c_ident : public AbstractController
294{
295  public:
296    typedef ${c_ident}Params Params;
297    $c_ident(const Params *p);
298    static int getNumControllers();
299    void init();
300
301    MessageBuffer *getMandatoryQueue() const;
302    MessageBuffer *getMemoryQueue() const;
303    void initNetQueues();
304
305    void print(std::ostream& out) const;
306    void wakeup();
307    void resetStats();
308    void regStats();
309    void collateStats();
310
311    void recordCacheTrace(int cntrl, CacheRecorder* tr);
312    Sequencer* getCPUSequencer() const;
313
314    int functionalWriteBuffers(PacketPtr&);
315
316    void countTransition(${ident}_State state, ${ident}_Event event);
317    void possibleTransition(${ident}_State state, ${ident}_Event event);
318    uint64_t getEventCount(${ident}_Event event);
319    bool isPossible(${ident}_State state, ${ident}_Event event);
320    uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event);
321
322private:
323''')
324
325        code.indent()
326        # added by SS
327        for param in self.config_parameters:
328            if param.pointer:
329                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
330            else:
331                code('${{param.type_ast.type}} m_${{param.ident}};')
332
333        code('''
334TransitionResult doTransition(${ident}_Event event,
335''')
336
337        if self.EntryType != None:
338            code('''
339                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
340''')
341        if self.TBEType != None:
342            code('''
343                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
344''')
345
346        code('''
347                              Addr addr);
348
349TransitionResult doTransitionWorker(${ident}_Event event,
350                                    ${ident}_State state,
351                                    ${ident}_State& next_state,
352''')
353
354        if self.TBEType != None:
355            code('''
356                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
357''')
358        if self.EntryType != None:
359            code('''
360                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
361''')
362
363        code('''
364                                    Addr addr);
365
366int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
367int m_event_counters[${ident}_Event_NUM];
368bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
369
370static std::vector<Stats::Vector *> eventVec;
371static std::vector<std::vector<Stats::Vector *> > transVec;
372static int m_num_controllers;
373
374// Internal functions
375''')
376
377        for func in self.functions:
378            proto = func.prototype
379            if proto:
380                code('$proto')
381
382        if self.EntryType != None:
383            code('''
384
385// Set and Reset for cache_entry variable
386void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
387void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
388''')
389
390        if self.TBEType != None:
391            code('''
392
393// Set and Reset for tbe variable
394void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
395void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
396''')
397
398        # Prototype the actions that the controller can take
399        code('''
400
401// Actions
402''')
403        if self.TBEType != None and self.EntryType != None:
404            for action in self.actions.itervalues():
405                code('/** \\brief ${{action.desc}} */')
406                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
407                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
408                     'm_cache_entry_ptr, Addr addr);')
409        elif self.TBEType != None:
410            for action in self.actions.itervalues():
411                code('/** \\brief ${{action.desc}} */')
412                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
413                     'm_tbe_ptr, Addr addr);')
414        elif self.EntryType != None:
415            for action in self.actions.itervalues():
416                code('/** \\brief ${{action.desc}} */')
417                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
418                     'm_cache_entry_ptr, Addr addr);')
419        else:
420            for action in self.actions.itervalues():
421                code('/** \\brief ${{action.desc}} */')
422                code('void ${{action.ident}}(Addr addr);')
423
424        # the controller internal variables
425        code('''
426
427// Objects
428''')
429        for var in self.objects:
430            th = var.get("template", "")
431            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
432
433        code.dedent()
434        code('};')
435        code('#endif // __${ident}_CONTROLLER_H__')
436        code.write(path, '%s.hh' % c_ident)
437
438    def printControllerCC(self, path, includes):
439        '''Output the actions for performing the actions'''
440
441        code = self.symtab.codeFormatter()
442        ident = self.ident
443        c_ident = "%s_Controller" % self.ident
444
445        code('''
446/** \\file $c_ident.cc
447 *
448 * Auto generated C++ code started by $__file__:$__line__
449 * Created by slicc definition of Module "${{self.short}}"
450 */
451
452#include <sys/types.h>
453#include <unistd.h>
454
455#include <cassert>
456#include <sstream>
457#include <string>
458#include <typeinfo>
459
460#include "base/compiler.hh"
461#include "base/cprintf.hh"
462
463''')
464        for f in self.debug_flags:
465            code('#include "debug/${{f}}.hh"')
466        code('''
467#include "mem/protocol/${ident}_Controller.hh"
468#include "mem/protocol/${ident}_Event.hh"
469#include "mem/protocol/${ident}_State.hh"
470#include "mem/protocol/Types.hh"
471#include "mem/ruby/system/RubySystem.hh"
472
473''')
474        for include_path in includes:
475            code('#include "${{include_path}}"')
476
477        code('''
478
479using namespace std;
480''')
481
482        # include object classes
483        seen_types = set()
484        for var in self.objects:
485            if var.type.ident not in seen_types and not var.type.isPrimitive:
486                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
487            seen_types.add(var.type.ident)
488
489        num_in_ports = len(self.in_ports)
490
491        code('''
492$c_ident *
493${c_ident}Params::create()
494{
495    return new $c_ident(this);
496}
497
498int $c_ident::m_num_controllers = 0;
499std::vector<Stats::Vector *>  $c_ident::eventVec;
500std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
501
502// for adding information to the protocol debug trace
503stringstream ${ident}_transitionComment;
504
505#ifndef NDEBUG
506#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
507#else
508#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
509#endif
510
511/** \\brief constructor */
512$c_ident::$c_ident(const Params *p)
513    : AbstractController(p)
514{
515    m_machineID.type = MachineType_${ident};
516    m_machineID.num = m_version;
517    m_num_controllers++;
518
519    m_in_ports = $num_in_ports;
520''')
521        code.indent()
522
523        #
524        # After initializing the universal machine parameters, initialize the
525        # this machines config parameters.  Also if these configuration params
526        # include a sequencer, connect the it to the controller.
527        #
528        for param in self.config_parameters:
529            if param.pointer:
530                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
531            else:
532                code('m_${{param.ident}} = p->${{param.ident}};')
533
534            if re.compile("sequencer").search(param.ident) or \
535                   param.type_ast.type.c_ident == "GPUCoalescer" or \
536                   param.type_ast.type.c_ident == "VIPERCoalescer":
537                code('''
538if (m_${{param.ident}}_ptr != NULL) {
539    m_${{param.ident}}_ptr->setController(this);
540}
541''')
542
543        code('''
544
545for (int state = 0; state < ${ident}_State_NUM; state++) {
546    for (int event = 0; event < ${ident}_Event_NUM; event++) {
547        m_possible[state][event] = false;
548        m_counters[state][event] = 0;
549    }
550}
551for (int event = 0; event < ${ident}_Event_NUM; event++) {
552    m_event_counters[event] = 0;
553}
554''')
555        code.dedent()
556        code('''
557}
558
559void
560$c_ident::initNetQueues()
561{
562    MachineType machine_type = string_to_MachineType("${{self.ident}}");
563    int base M5_VAR_USED = MachineType_base_number(machine_type);
564
565''')
566        code.indent()
567
568        # set for maintaining the vnet, direction pairs already seen for this
569        # machine.  This map helps in implementing the check for avoiding
570        # multiple message buffers being mapped to the same vnet.
571        vnet_dir_set = set()
572
573        for var in self.config_parameters:
574            vid = "m_%s_ptr" % var.ident
575            if "network" in var:
576                vtype = var.type_ast.type
577                code('assert($vid != NULL);')
578
579                # Network port object
580                network = var["network"]
581
582                if "virtual_network" in var:
583                    vnet = var["virtual_network"]
584                    vnet_type = var["vnet_type"]
585
586                    assert (vnet, network) not in vnet_dir_set
587                    vnet_dir_set.add((vnet,network))
588
589                    code('''
590m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet,
591                                 "$vnet_type", $vid);
592''')
593                # Set Priority
594                if "rank" in var:
595                    code('$vid->setPriority(${{var["rank"]}})')
596
597        code.dedent()
598        code('''
599}
600
601void
602$c_ident::init()
603{
604    // initialize objects
605''')
606
607        code.indent()
608
609        for var in self.objects:
610            vtype = var.type
611            vid = "m_%s_ptr" % var.ident
612            if "network" not in var:
613                # Not a network port object
614                if "primitive" in vtype:
615                    code('$vid = new ${{vtype.c_ident}};')
616                    if "default" in var:
617                        code('(*$vid) = ${{var["default"]}};')
618                else:
619                    # Normal Object
620                    th = var.get("template", "")
621                    expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
622                    args = ""
623                    if "non_obj" not in vtype and not vtype.isEnumeration:
624                        args = var.get("constructor", "")
625
626                    code('$expr($args);')
627                    code('assert($vid != NULL);')
628
629                    if "default" in var:
630                        code('*$vid = ${{var["default"]}}; // Object default')
631                    elif "default" in vtype:
632                        comment = "Type %s default" % vtype.ident
633                        code('*$vid = ${{vtype["default"]}}; // $comment')
634
635        # Set the prefetchers
636        code()
637        for prefetcher in self.prefetchers:
638            code('${{prefetcher.code}}.setController(this);')
639
640        code()
641        for port in self.in_ports:
642            # Set the queue consumers
643            code('${{port.code}}.setConsumer(this);')
644
645        # Initialize the transition profiling
646        code()
647        for trans in self.transitions:
648            # Figure out if we stall
649            stall = False
650            for action in trans.actions:
651                if action.ident == "z_stall":
652                    stall = True
653
654            # Only possible if it is not a 'z' case
655            if not stall:
656                state = "%s_State_%s" % (self.ident, trans.state.ident)
657                event = "%s_Event_%s" % (self.ident, trans.event.ident)
658                code('possibleTransition($state, $event);')
659
660        code.dedent()
661        code('''
662    AbstractController::init();
663    resetStats();
664}
665''')
666
667        mq_ident = "NULL"
668        for port in self.in_ports:
669            if port.code.find("mandatoryQueue_ptr") >= 0:
670                mq_ident = "m_mandatoryQueue_ptr"
671
672        memq_ident = "NULL"
673        for port in self.in_ports:
674            if port.code.find("responseFromMemory_ptr") >= 0:
675                memq_ident = "m_responseFromMemory_ptr"
676
677        seq_ident = "NULL"
678        for param in self.config_parameters:
679            if param.ident == "sequencer":
680                assert(param.pointer)
681                seq_ident = "m_%s_ptr" % param.ident
682
683        if seq_ident != "NULL":
684            code('''
685Sequencer*
686$c_ident::getCPUSequencer() const
687{
688    if (NULL != $seq_ident && $seq_ident->isCPUSequencer()) {
689        return $seq_ident;
690    } else {
691        return NULL;
692    }
693}
694''')
695        else:
696            code('''
697
698Sequencer*
699$c_ident::getCPUSequencer() const
700{
701    return NULL;
702}
703''')
704
705        code('''
706
707void
708$c_ident::regStats()
709{
710    AbstractController::regStats();
711
712    if (m_version == 0) {
713        for (${ident}_Event event = ${ident}_Event_FIRST;
714             event < ${ident}_Event_NUM; ++event) {
715            Stats::Vector *t = new Stats::Vector();
716            t->init(m_num_controllers);
717            t->name(params()->ruby_system->name() + ".${c_ident}." +
718                ${ident}_Event_to_string(event));
719            t->flags(Stats::pdf | Stats::total | Stats::oneline |
720                     Stats::nozero);
721
722            eventVec.push_back(t);
723        }
724
725        for (${ident}_State state = ${ident}_State_FIRST;
726             state < ${ident}_State_NUM; ++state) {
727
728            transVec.push_back(std::vector<Stats::Vector *>());
729
730            for (${ident}_Event event = ${ident}_Event_FIRST;
731                 event < ${ident}_Event_NUM; ++event) {
732
733                Stats::Vector *t = new Stats::Vector();
734                t->init(m_num_controllers);
735                t->name(params()->ruby_system->name() + ".${c_ident}." +
736                        ${ident}_State_to_string(state) +
737                        "." + ${ident}_Event_to_string(event));
738
739                t->flags(Stats::pdf | Stats::total | Stats::oneline |
740                         Stats::nozero);
741                transVec[state].push_back(t);
742            }
743        }
744    }
745}
746
747void
748$c_ident::collateStats()
749{
750    for (${ident}_Event event = ${ident}_Event_FIRST;
751         event < ${ident}_Event_NUM; ++event) {
752        for (unsigned int i = 0; i < m_num_controllers; ++i) {
753            RubySystem *rs = params()->ruby_system;
754            std::map<uint32_t, AbstractController *>::iterator it =
755                     rs->m_abstract_controls[MachineType_${ident}].find(i);
756            assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
757            (*eventVec[event])[i] =
758                (($c_ident *)(*it).second)->getEventCount(event);
759        }
760    }
761
762    for (${ident}_State state = ${ident}_State_FIRST;
763         state < ${ident}_State_NUM; ++state) {
764
765        for (${ident}_Event event = ${ident}_Event_FIRST;
766             event < ${ident}_Event_NUM; ++event) {
767
768            for (unsigned int i = 0; i < m_num_controllers; ++i) {
769                RubySystem *rs = params()->ruby_system;
770                std::map<uint32_t, AbstractController *>::iterator it =
771                         rs->m_abstract_controls[MachineType_${ident}].find(i);
772                assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
773                (*transVec[state][event])[i] =
774                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
775            }
776        }
777    }
778}
779
780void
781$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
782{
783    assert(m_possible[state][event]);
784    m_counters[state][event]++;
785    m_event_counters[event]++;
786}
787void
788$c_ident::possibleTransition(${ident}_State state,
789                             ${ident}_Event event)
790{
791    m_possible[state][event] = true;
792}
793
794uint64_t
795$c_ident::getEventCount(${ident}_Event event)
796{
797    return m_event_counters[event];
798}
799
800bool
801$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
802{
803    return m_possible[state][event];
804}
805
806uint64_t
807$c_ident::getTransitionCount(${ident}_State state,
808                             ${ident}_Event event)
809{
810    return m_counters[state][event];
811}
812
813int
814$c_ident::getNumControllers()
815{
816    return m_num_controllers;
817}
818
819MessageBuffer*
820$c_ident::getMandatoryQueue() const
821{
822    return $mq_ident;
823}
824
825MessageBuffer*
826$c_ident::getMemoryQueue() const
827{
828    return $memq_ident;
829}
830
831void
832$c_ident::print(ostream& out) const
833{
834    out << "[$c_ident " << m_version << "]";
835}
836
837void $c_ident::resetStats()
838{
839    for (int state = 0; state < ${ident}_State_NUM; state++) {
840        for (int event = 0; event < ${ident}_Event_NUM; event++) {
841            m_counters[state][event] = 0;
842        }
843    }
844
845    for (int event = 0; event < ${ident}_Event_NUM; event++) {
846        m_event_counters[event] = 0;
847    }
848
849    AbstractController::resetStats();
850}
851''')
852
853        if self.EntryType != None:
854            code('''
855
856// Set and Reset for cache_entry variable
857void
858$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
859{
860  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
861}
862
863void
864$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
865{
866  m_cache_entry_ptr = 0;
867}
868''')
869
870        if self.TBEType != None:
871            code('''
872
873// Set and Reset for tbe variable
874void
875$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
876{
877  m_tbe_ptr = m_new_tbe;
878}
879
880void
881$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
882{
883  m_tbe_ptr = NULL;
884}
885''')
886
887        code('''
888
889void
890$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
891{
892''')
893        #
894        # Record cache contents for all associated caches.
895        #
896        code.indent()
897        for param in self.config_parameters:
898            if param.type_ast.type.ident == "CacheMemory":
899                assert(param.pointer)
900                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
901
902        code.dedent()
903        code('''
904}
905
906// Actions
907''')
908        if self.TBEType != None and self.EntryType != None:
909            for action in self.actions.itervalues():
910                if "c_code" not in action:
911                 continue
912
913                code('''
914/** \\brief ${{action.desc}} */
915void
916$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
917{
918    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
919    try {
920       ${{action["c_code"]}}
921    } catch (const RejectException & e) {
922       fatal("Error in action ${{ident}}:${{action.ident}}: "
923             "executed a peek statement with the wrong message "
924             "type specified. ");
925    }
926}
927
928''')
929        elif self.TBEType != None:
930            for action in self.actions.itervalues():
931                if "c_code" not in action:
932                 continue
933
934                code('''
935/** \\brief ${{action.desc}} */
936void
937$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr)
938{
939    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
940    ${{action["c_code"]}}
941}
942
943''')
944        elif self.EntryType != None:
945            for action in self.actions.itervalues():
946                if "c_code" not in action:
947                 continue
948
949                code('''
950/** \\brief ${{action.desc}} */
951void
952$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
953{
954    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
955    ${{action["c_code"]}}
956}
957
958''')
959        else:
960            for action in self.actions.itervalues():
961                if "c_code" not in action:
962                 continue
963
964                code('''
965/** \\brief ${{action.desc}} */
966void
967$c_ident::${{action.ident}}(Addr addr)
968{
969    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
970    ${{action["c_code"]}}
971}
972
973''')
974        for func in self.functions:
975            code(func.generateCode())
976
977        # Function for functional writes to messages buffered in the controller
978        code('''
979int
980$c_ident::functionalWriteBuffers(PacketPtr& pkt)
981{
982    int num_functional_writes = 0;
983''')
984        for var in self.objects:
985            vtype = var.type
986            if vtype.isBuffer:
987                vid = "m_%s_ptr" % var.ident
988                code('num_functional_writes += $vid->functionalWrite(pkt);')
989
990        for var in self.config_parameters:
991            vtype = var.type_ast.type
992            if vtype.isBuffer:
993                vid = "m_%s_ptr" % var.ident
994                code('num_functional_writes += $vid->functionalWrite(pkt);')
995
996        code('''
997    return num_functional_writes;
998}
999''')
1000
1001        code.write(path, "%s.cc" % c_ident)
1002
1003    def printCWakeup(self, path, includes):
1004        '''Output the wakeup loop for the events'''
1005
1006        code = self.symtab.codeFormatter()
1007        ident = self.ident
1008
1009        outputRequest_types = True
1010        if len(self.request_types) == 0:
1011            outputRequest_types = False
1012
1013        code('''
1014// Auto generated C++ code started by $__file__:$__line__
1015// ${ident}: ${{self.short}}
1016
1017#include <sys/types.h>
1018#include <unistd.h>
1019
1020#include <cassert>
1021#include <typeinfo>
1022
1023#include "base/misc.hh"
1024
1025''')
1026        for f in self.debug_flags:
1027            code('#include "debug/${{f}}.hh"')
1028        code('''
1029#include "mem/protocol/${ident}_Controller.hh"
1030#include "mem/protocol/${ident}_Event.hh"
1031#include "mem/protocol/${ident}_State.hh"
1032
1033''')
1034
1035        if outputRequest_types:
1036            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1037
1038        code('''
1039#include "mem/protocol/Types.hh"
1040#include "mem/ruby/system/RubySystem.hh"
1041
1042''')
1043
1044
1045        for include_path in includes:
1046            code('#include "${{include_path}}"')
1047
1048        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1049
1050        code('''
1051
1052using namespace std;
1053
1054void
1055${ident}_Controller::wakeup()
1056{
1057    int counter = 0;
1058    while (true) {
1059        unsigned char rejected[${{len(msg_bufs)}}];
1060        memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
1061        // Some cases will put us into an infinite loop without this limit
1062        assert(counter <= m_transitions_per_cycle);
1063        if (counter == m_transitions_per_cycle) {
1064            // Count how often we are fully utilized
1065            m_fully_busy_cycles++;
1066
1067            // Wakeup in another cycle and try again
1068            scheduleEvent(Cycles(1));
1069            break;
1070        }
1071''')
1072
1073        code.indent()
1074        code.indent()
1075
1076        # InPorts
1077        #
1078        for port in self.in_ports:
1079            code.indent()
1080            code('// ${ident}InPort $port')
1081            if port.pairs.has_key("rank"):
1082                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1083            else:
1084                code('m_cur_in_port = 0;')
1085            if port in port_to_buf_map:
1086                code('try {')
1087                code.indent()
1088            code('${{port["c_code_in_port"]}}')
1089
1090            if port in port_to_buf_map:
1091                code.dedent()
1092                code('''
1093            } catch (const RejectException & e) {
1094                rejected[${{port_to_buf_map[port]}}]++;
1095            }
1096''')
1097            code.dedent()
1098            code('')
1099
1100        code.dedent()
1101        code.dedent()
1102        code('''
1103        // If we got this far, we have nothing left todo or something went
1104        // wrong''')
1105        for buf_name, ports in in_msg_bufs.items():
1106            if len(ports) > 1:
1107                # only produce checks when a buffer is shared by multiple ports
1108                code('''
1109        if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
1110        {
1111            // no port claimed the message on the top of this buffer
1112            panic("Runtime Error at Ruby Time: %d. "
1113                  "All ports rejected a message. "
1114                  "You are probably sending a message type to this controller "
1115                  "over a virtual network that do not define an in_port for "
1116                  "the incoming message type.\\n",
1117                  Cycles(1));
1118        }
1119''')
1120        code('''
1121        break;
1122    }
1123}
1124''')
1125
1126        code.write(path, "%s_Wakeup.cc" % self.ident)
1127
1128    def printCSwitch(self, path):
1129        '''Output switch statement for transition table'''
1130
1131        code = self.symtab.codeFormatter()
1132        ident = self.ident
1133
1134        code('''
1135// Auto generated C++ code started by $__file__:$__line__
1136// ${ident}: ${{self.short}}
1137
1138#include <cassert>
1139
1140#include "base/misc.hh"
1141#include "base/trace.hh"
1142#include "debug/ProtocolTrace.hh"
1143#include "debug/RubyGenerated.hh"
1144#include "mem/protocol/${ident}_Controller.hh"
1145#include "mem/protocol/${ident}_Event.hh"
1146#include "mem/protocol/${ident}_State.hh"
1147#include "mem/protocol/Types.hh"
1148#include "mem/ruby/system/RubySystem.hh"
1149
1150#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1151
1152#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1153#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1154
1155TransitionResult
1156${ident}_Controller::doTransition(${ident}_Event event,
1157''')
1158        if self.EntryType != None:
1159            code('''
1160                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1161''')
1162        if self.TBEType != None:
1163            code('''
1164                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1165''')
1166        code('''
1167                                  Addr addr)
1168{
1169''')
1170        code.indent()
1171
1172        if self.TBEType != None and self.EntryType != None:
1173            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1174        elif self.TBEType != None:
1175            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1176        elif self.EntryType != None:
1177            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1178        else:
1179            code('${ident}_State state = getState(addr);')
1180
1181        code('''
1182${ident}_State next_state = state;
1183
1184DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n",
1185        *this, curCycle(), ${ident}_State_to_string(state),
1186        ${ident}_Event_to_string(event), addr);
1187
1188TransitionResult result =
1189''')
1190        if self.TBEType != None and self.EntryType != None:
1191            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1192        elif self.TBEType != None:
1193            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1194        elif self.EntryType != None:
1195            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1196        else:
1197            code('doTransitionWorker(event, state, next_state, addr);')
1198
1199        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1200
1201        code('''
1202
1203if (result == TransitionResult_Valid) {
1204    DPRINTF(RubyGenerated, "next_state: %s\\n",
1205            ${ident}_State_to_string(next_state));
1206    countTransition(state, event);
1207
1208    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n",
1209             curTick(), m_version, "${ident}",
1210             ${ident}_Event_to_string(event),
1211             ${ident}_State_to_string(state),
1212             ${ident}_State_to_string(next_state),
1213             printAddress(addr), GET_TRANSITION_COMMENT());
1214
1215    CLEAR_TRANSITION_COMMENT();
1216''')
1217        if self.TBEType != None and self.EntryType != None:
1218            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1219            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1220        elif self.TBEType != None:
1221            code('setState(m_tbe_ptr, addr, next_state);')
1222            code('setAccessPermission(addr, next_state);')
1223        elif self.EntryType != None:
1224            code('setState(m_cache_entry_ptr, addr, next_state);')
1225            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1226        else:
1227            code('setState(addr, next_state);')
1228            code('setAccessPermission(addr, next_state);')
1229
1230        code('''
1231} else if (result == TransitionResult_ResourceStall) {
1232    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1233             curTick(), m_version, "${ident}",
1234             ${ident}_Event_to_string(event),
1235             ${ident}_State_to_string(state),
1236             ${ident}_State_to_string(next_state),
1237             printAddress(addr), "Resource Stall");
1238} else if (result == TransitionResult_ProtocolStall) {
1239    DPRINTF(RubyGenerated, "stalling\\n");
1240    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1241             curTick(), m_version, "${ident}",
1242             ${ident}_Event_to_string(event),
1243             ${ident}_State_to_string(state),
1244             ${ident}_State_to_string(next_state),
1245             printAddress(addr), "Protocol Stall");
1246}
1247
1248return result;
1249''')
1250        code.dedent()
1251        code('''
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                                        Addr 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                if trans.nextState.isWildcard():
1285                    # When * is encountered as an end state of a transition,
1286                    # the next state is determined by calling the
1287                    # machine-specific getNextState function. The next state
1288                    # is determined before any actions of the transition
1289                    # execute, and therefore the next state calculation cannot
1290                    # depend on any of the transitionactions.
1291                    case('next_state = getNextState(addr);')
1292                else:
1293                    ns_ident = trans.nextState.ident
1294                    case('next_state = ${ident}_State_${ns_ident};')
1295
1296            actions = trans.actions
1297            request_types = trans.request_types
1298
1299            # Check for resources
1300            case_sorter = []
1301            res = trans.resources
1302            for key,val in res.iteritems():
1303                val = '''
1304if (!%s.areNSlotsAvailable(%s, clockEdge()))
1305    return TransitionResult_ResourceStall;
1306''' % (key.code, val)
1307                case_sorter.append(val)
1308
1309            # Check all of the request_types for resource constraints
1310            for request_type in request_types:
1311                val = '''
1312if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1313    return TransitionResult_ResourceStall;
1314}
1315''' % (self.ident, request_type.ident)
1316                case_sorter.append(val)
1317
1318            # Emit the code sequences in a sorted order.  This makes the
1319            # output deterministic (without this the output order can vary
1320            # since Map's keys() on a vector of pointers is not deterministic
1321            for c in sorted(case_sorter):
1322                case("$c")
1323
1324            # Record access types for this transition
1325            for request_type in request_types:
1326                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1327
1328            # Figure out if we stall
1329            stall = False
1330            for action in actions:
1331                if action.ident == "z_stall":
1332                    stall = True
1333                    break
1334
1335            if stall:
1336                case('return TransitionResult_ProtocolStall;')
1337            else:
1338                if self.TBEType != None and self.EntryType != None:
1339                    for action in actions:
1340                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1341                elif self.TBEType != None:
1342                    for action in actions:
1343                        case('${{action.ident}}(m_tbe_ptr, addr);')
1344                elif self.EntryType != None:
1345                    for action in actions:
1346                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1347                else:
1348                    for action in actions:
1349                        case('${{action.ident}}(addr);')
1350                case('return TransitionResult_Valid;')
1351
1352            case = str(case)
1353
1354            # Look to see if this transition code is unique.
1355            if case not in cases:
1356                cases[case] = []
1357
1358            cases[case].append(case_string)
1359
1360        # Walk through all of the unique code blocks and spit out the
1361        # corresponding case statement elements
1362        for case,transitions in cases.iteritems():
1363            # Iterative over all the multiple transitions that share
1364            # the same code
1365            for trans in transitions:
1366                code('  case HASH_FUN($trans):')
1367            code('    $case\n')
1368
1369        code('''
1370      default:
1371        panic("Invalid transition\\n"
1372              "%s time: %d addr: %s event: %s state: %s\\n",
1373              name(), curCycle(), addr, event, state);
1374    }
1375
1376    return TransitionResult_Valid;
1377}
1378''')
1379        code.write(path, "%s_Transitions.cc" % self.ident)
1380
1381
1382    # **************************
1383    # ******* HTML Files *******
1384    # **************************
1385    def frameRef(self, click_href, click_target, over_href, over_num, text):
1386        code = self.symtab.codeFormatter(fix_newlines=False)
1387        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1388    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1389        parent.frames[$over_num].location='$over_href'
1390    }\">
1391    ${{html.formatShorthand(text)}}
1392    </A>""")
1393        return str(code)
1394
1395    def writeHTMLFiles(self, path):
1396        # Create table with no row hilighted
1397        self.printHTMLTransitions(path, None)
1398
1399        # Generate transition tables
1400        for state in self.states.itervalues():
1401            self.printHTMLTransitions(path, state)
1402
1403        # Generate action descriptions
1404        for action in self.actions.itervalues():
1405            name = "%s_action_%s.html" % (self.ident, action.ident)
1406            code = html.createSymbol(action, "Action")
1407            code.write(path, name)
1408
1409        # Generate state descriptions
1410        for state in self.states.itervalues():
1411            name = "%s_State_%s.html" % (self.ident, state.ident)
1412            code = html.createSymbol(state, "State")
1413            code.write(path, name)
1414
1415        # Generate event descriptions
1416        for event in self.events.itervalues():
1417            name = "%s_Event_%s.html" % (self.ident, event.ident)
1418            code = html.createSymbol(event, "Event")
1419            code.write(path, name)
1420
1421    def printHTMLTransitions(self, path, active_state):
1422        code = self.symtab.codeFormatter()
1423
1424        code('''
1425<HTML>
1426<BODY link="blue" vlink="blue">
1427
1428<H1 align="center">${{html.formatShorthand(self.short)}}:
1429''')
1430        code.indent()
1431        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1432            mid = machine.ident
1433            if i != 0:
1434                extra = " - "
1435            else:
1436                extra = ""
1437            if machine == self:
1438                code('$extra$mid')
1439            else:
1440                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1441        code.dedent()
1442
1443        code("""
1444</H1>
1445
1446<TABLE border=1>
1447<TR>
1448  <TH> </TH>
1449""")
1450
1451        for event in self.events.itervalues():
1452            href = "%s_Event_%s.html" % (self.ident, event.ident)
1453            ref = self.frameRef(href, "Status", href, "1", event.short)
1454            code('<TH bgcolor=white>$ref</TH>')
1455
1456        code('</TR>')
1457        # -- Body of table
1458        for state in self.states.itervalues():
1459            # -- Each row
1460            if state == active_state:
1461                color = "yellow"
1462            else:
1463                color = "white"
1464
1465            click = "%s_table_%s.html" % (self.ident, state.ident)
1466            over = "%s_State_%s.html" % (self.ident, state.ident)
1467            text = html.formatShorthand(state.short)
1468            ref = self.frameRef(click, "Table", over, "1", state.short)
1469            code('''
1470<TR>
1471  <TH bgcolor=$color>$ref</TH>
1472''')
1473
1474            # -- One column for each event
1475            for event in self.events.itervalues():
1476                trans = self.table.get((state,event), None)
1477                if trans is None:
1478                    # This is the no transition case
1479                    if state == active_state:
1480                        color = "#C0C000"
1481                    else:
1482                        color = "lightgrey"
1483
1484                    code('<TD bgcolor=$color>&nbsp;</TD>')
1485                    continue
1486
1487                next = trans.nextState
1488                stall_action = False
1489
1490                # -- Get the actions
1491                for action in trans.actions:
1492                    if action.ident == "z_stall" or \
1493                       action.ident == "zz_recycleMandatoryQueue":
1494                        stall_action = True
1495
1496                # -- Print out "actions/next-state"
1497                if stall_action:
1498                    if state == active_state:
1499                        color = "#C0C000"
1500                    else:
1501                        color = "lightgrey"
1502
1503                elif active_state and next.ident == active_state.ident:
1504                    color = "aqua"
1505                elif state == active_state:
1506                    color = "yellow"
1507                else:
1508                    color = "white"
1509
1510                code('<TD bgcolor=$color>')
1511                for action in trans.actions:
1512                    href = "%s_action_%s.html" % (self.ident, action.ident)
1513                    ref = self.frameRef(href, "Status", href, "1",
1514                                        action.short)
1515                    code('  $ref')
1516                if next != state:
1517                    if trans.actions:
1518                        code('/')
1519                    click = "%s_table_%s.html" % (self.ident, next.ident)
1520                    over = "%s_State_%s.html" % (self.ident, next.ident)
1521                    ref = self.frameRef(click, "Table", over, "1", next.short)
1522                    code("$ref")
1523                code("</TD>")
1524
1525            # -- Each row
1526            if state == active_state:
1527                color = "yellow"
1528            else:
1529                color = "white"
1530
1531            click = "%s_table_%s.html" % (self.ident, state.ident)
1532            over = "%s_State_%s.html" % (self.ident, state.ident)
1533            ref = self.frameRef(click, "Table", over, "1", state.short)
1534            code('''
1535  <TH bgcolor=$color>$ref</TH>
1536</TR>
1537''')
1538        code('''
1539<!- Column footer->
1540<TR>
1541  <TH> </TH>
1542''')
1543
1544        for event in self.events.itervalues():
1545            href = "%s_Event_%s.html" % (self.ident, event.ident)
1546            ref = self.frameRef(href, "Status", href, "1", event.short)
1547            code('<TH bgcolor=white>$ref</TH>')
1548        code('''
1549</TR>
1550</TABLE>
1551</BODY></HTML>
1552''')
1553
1554
1555        if active_state:
1556            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1557        else:
1558            name = "%s_table.html" % self.ident
1559        code.write(path, name)
1560
1561__all__ = [ "StateMachine" ]
1562