StateMachine.py revision 9561:bc043a0455e3
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2# Copyright (c) 2009 The Hewlett-Packard Development Company
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28from m5.util import orderdict
29
30from slicc.symbols.Symbol import Symbol
31from slicc.symbols.Var import Var
32import slicc.generate.html as html
33import re
34
35python_class_map = {
36                    "int": "Int",
37                    "uint32_t" : "UInt32",
38                    "std::string": "String",
39                    "bool": "Bool",
40                    "CacheMemory": "RubyCache",
41                    "WireBuffer": "RubyWireBuffer",
42                    "Sequencer": "RubySequencer",
43                    "DirectoryMemory": "RubyDirectoryMemory",
44                    "MemoryControl": "MemoryControl",
45                    "DMASequencer": "DMASequencer",
46                    "Prefetcher":"Prefetcher",
47                    "Cycles":"Cycles",
48                   }
49
50class StateMachine(Symbol):
51    def __init__(self, symtab, ident, location, pairs, config_parameters):
52        super(StateMachine, self).__init__(symtab, ident, location, pairs)
53        self.table = None
54        self.config_parameters = config_parameters
55        self.prefetchers = []
56
57        for param in config_parameters:
58            if param.pointer:
59                var = Var(symtab, param.name, location, param.type_ast.type,
60                          "(*m_%s_ptr)" % param.name, {}, self)
61            else:
62                var = Var(symtab, param.name, location, param.type_ast.type,
63                          "m_%s" % param.name, {}, self)
64            self.symtab.registerSym(param.name, var)
65            if str(param.type_ast.type) == "Prefetcher":
66                self.prefetchers.append(var)
67
68        self.states = orderdict()
69        self.events = orderdict()
70        self.actions = orderdict()
71        self.request_types = orderdict()
72        self.transitions = []
73        self.in_ports = []
74        self.functions = []
75        self.objects = []
76        self.TBEType   = None
77        self.EntryType = None
78
79    def __repr__(self):
80        return "[StateMachine: %s]" % self.ident
81
82    def addState(self, state):
83        assert self.table is None
84        self.states[state.ident] = state
85
86    def addEvent(self, event):
87        assert self.table is None
88        self.events[event.ident] = event
89
90    def addAction(self, action):
91        assert self.table is None
92
93        # Check for duplicate action
94        for other in self.actions.itervalues():
95            if action.ident == other.ident:
96                action.warning("Duplicate action definition: %s" % action.ident)
97                action.error("Duplicate action definition: %s" % action.ident)
98            if action.short == other.short:
99                other.warning("Duplicate action shorthand: %s" % other.ident)
100                other.warning("    shorthand = %s" % other.short)
101                action.warning("Duplicate action shorthand: %s" % action.ident)
102                action.error("    shorthand = %s" % action.short)
103
104        self.actions[action.ident] = action
105
106    def addRequestType(self, request_type):
107        assert self.table is None
108        self.request_types[request_type.ident] = request_type
109
110    def addTransition(self, trans):
111        assert self.table is None
112        self.transitions.append(trans)
113
114    def addInPort(self, var):
115        self.in_ports.append(var)
116
117    def addFunc(self, func):
118        # register func in the symbol table
119        self.symtab.registerSym(str(func), func)
120        self.functions.append(func)
121
122    def addObject(self, obj):
123        self.objects.append(obj)
124
125    def addType(self, type):
126        type_ident = '%s' % type.c_ident
127
128        if type_ident == "%s_TBE" %self.ident:
129            if self.TBEType != None:
130                self.error("Multiple Transaction Buffer types in a " \
131                           "single machine.");
132            self.TBEType = type
133
134        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
135            if self.EntryType != None:
136                self.error("Multiple AbstractCacheEntry types in a " \
137                           "single machine.");
138            self.EntryType = type
139
140    # Needs to be called before accessing the table
141    def buildTable(self):
142        assert self.table is None
143
144        table = {}
145
146        for trans in self.transitions:
147            # Track which actions we touch so we know if we use them
148            # all -- really this should be done for all symbols as
149            # part of the symbol table, then only trigger it for
150            # Actions, States, Events, etc.
151
152            for action in trans.actions:
153                action.used = True
154
155            index = (trans.state, trans.event)
156            if index in table:
157                table[index].warning("Duplicate transition: %s" % table[index])
158                trans.error("Duplicate transition: %s" % trans)
159            table[index] = trans
160
161        # Look at all actions to make sure we used them all
162        for action in self.actions.itervalues():
163            if not action.used:
164                error_msg = "Unused action: %s" % action.ident
165                if "desc" in action:
166                    error_msg += ", "  + action.desc
167                action.warning(error_msg)
168        self.table = table
169
170    def writeCodeFiles(self, path, includes):
171        self.printControllerPython(path)
172        self.printControllerHH(path)
173        self.printControllerCC(path, includes)
174        self.printCSwitch(path)
175        self.printCWakeup(path, includes)
176        self.printProfilerCC(path)
177        self.printProfilerHH(path)
178        self.printProfileDumperCC(path)
179        self.printProfileDumperHH(path)
180
181    def printControllerPython(self, path):
182        code = self.symtab.codeFormatter()
183        ident = self.ident
184        py_ident = "%s_Controller" % ident
185        c_ident = "%s_Controller" % self.ident
186        code('''
187from m5.params import *
188from m5.SimObject import SimObject
189from Controller import RubyController
190
191class $py_ident(RubyController):
192    type = '$py_ident'
193    cxx_header = 'mem/protocol/${c_ident}.hh'
194''')
195        code.indent()
196        for param in self.config_parameters:
197            dflt_str = ''
198            if param.default is not None:
199                dflt_str = str(param.default) + ', '
200            if python_class_map.has_key(param.type_ast.type.c_ident):
201                python_type = python_class_map[param.type_ast.type.c_ident]
202                code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
203            else:
204                self.error("Unknown c++ to python class conversion for c++ " \
205                           "type: '%s'. Please update the python_class_map " \
206                           "in StateMachine.py", param.type_ast.type.c_ident)
207        code.dedent()
208        code.write(path, '%s.py' % py_ident)
209
210
211    def printControllerHH(self, path):
212        '''Output the method declarations for the class declaration'''
213        code = self.symtab.codeFormatter()
214        ident = self.ident
215        c_ident = "%s_Controller" % self.ident
216
217        code('''
218/** \\file $c_ident.hh
219 *
220 * Auto generated C++ code started by $__file__:$__line__
221 * Created by slicc definition of Module "${{self.short}}"
222 */
223
224#ifndef __${ident}_CONTROLLER_HH__
225#define __${ident}_CONTROLLER_HH__
226
227#include <iostream>
228#include <sstream>
229#include <string>
230
231#include "mem/protocol/${ident}_ProfileDumper.hh"
232#include "mem/protocol/${ident}_Profiler.hh"
233#include "mem/protocol/TransitionResult.hh"
234#include "mem/protocol/Types.hh"
235#include "mem/ruby/common/Consumer.hh"
236#include "mem/ruby/common/Global.hh"
237#include "mem/ruby/slicc_interface/AbstractController.hh"
238#include "params/$c_ident.hh"
239''')
240
241        seen_types = set()
242        for var in self.objects:
243            if var.type.ident not in seen_types and not var.type.isPrimitive:
244                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
245            seen_types.add(var.type.ident)
246
247        # for adding information to the protocol debug trace
248        code('''
249extern std::stringstream ${ident}_transitionComment;
250
251class $c_ident : public AbstractController
252{
253  public:
254    typedef ${c_ident}Params Params;
255    $c_ident(const Params *p);
256    static int getNumControllers();
257    void init();
258    MessageBuffer* getMandatoryQueue() const;
259    const int & getVersion() const;
260    const std::string toString() const;
261    const std::string getName() const;
262    void stallBuffer(MessageBuffer* buf, Address addr);
263    void wakeUpBuffers(Address addr);
264    void wakeUpAllBuffers();
265    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
266    void print(std::ostream& out) const;
267    void wakeup();
268    void printStats(std::ostream& out) const;
269    void clearStats();
270    void blockOnQueue(Address addr, MessageBuffer* port);
271    void unblock(Address addr);
272    void recordCacheTrace(int cntrl, CacheRecorder* tr);
273    Sequencer* getSequencer() const;
274
275    bool functionalReadBuffers(PacketPtr&);
276    uint32_t functionalWriteBuffers(PacketPtr&);
277
278private:
279''')
280
281        code.indent()
282        # added by SS
283        for param in self.config_parameters:
284            if param.pointer:
285                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
286            else:
287                code('${{param.type_ast.type}} m_${{param.ident}};')
288
289        code('''
290TransitionResult doTransition(${ident}_Event event,
291''')
292
293        if self.EntryType != None:
294            code('''
295                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
296''')
297        if self.TBEType != None:
298            code('''
299                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
300''')
301
302        code('''
303                              const Address& addr);
304
305TransitionResult doTransitionWorker(${ident}_Event event,
306                                    ${ident}_State state,
307                                    ${ident}_State& next_state,
308''')
309
310        if self.TBEType != None:
311            code('''
312                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
313''')
314        if self.EntryType != None:
315            code('''
316                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
317''')
318
319        code('''
320                                    const Address& addr);
321
322static ${ident}_ProfileDumper s_profileDumper;
323${ident}_Profiler m_profiler;
324static int m_num_controllers;
325
326// Internal functions
327''')
328
329        for func in self.functions:
330            proto = func.prototype
331            if proto:
332                code('$proto')
333
334        if self.EntryType != None:
335            code('''
336
337// Set and Reset for cache_entry variable
338void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
339void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
340''')
341
342        if self.TBEType != None:
343            code('''
344
345// Set and Reset for tbe variable
346void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
347void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
348''')
349
350        code('''
351
352// Actions
353''')
354        if self.TBEType != None and self.EntryType != None:
355            for action in self.actions.itervalues():
356                code('/** \\brief ${{action.desc}} */')
357                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
358        elif self.TBEType != None:
359            for action in self.actions.itervalues():
360                code('/** \\brief ${{action.desc}} */')
361                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
362        elif self.EntryType != None:
363            for action in self.actions.itervalues():
364                code('/** \\brief ${{action.desc}} */')
365                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
366        else:
367            for action in self.actions.itervalues():
368                code('/** \\brief ${{action.desc}} */')
369                code('void ${{action.ident}}(const Address& addr);')
370
371        # the controller internal variables
372        code('''
373
374// Objects
375''')
376        for var in self.objects:
377            th = var.get("template", "")
378            code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
379
380        code.dedent()
381        code('};')
382        code('#endif // __${ident}_CONTROLLER_H__')
383        code.write(path, '%s.hh' % c_ident)
384
385    def printControllerCC(self, path, includes):
386        '''Output the actions for performing the actions'''
387
388        code = self.symtab.codeFormatter()
389        ident = self.ident
390        c_ident = "%s_Controller" % self.ident
391
392        code('''
393/** \\file $c_ident.cc
394 *
395 * Auto generated C++ code started by $__file__:$__line__
396 * Created by slicc definition of Module "${{self.short}}"
397 */
398
399#include <sys/types.h>
400#include <unistd.h>
401
402#include <cassert>
403#include <sstream>
404#include <string>
405
406#include "base/compiler.hh"
407#include "base/cprintf.hh"
408#include "debug/RubyGenerated.hh"
409#include "debug/RubySlicc.hh"
410#include "mem/protocol/${ident}_Controller.hh"
411#include "mem/protocol/${ident}_Event.hh"
412#include "mem/protocol/${ident}_State.hh"
413#include "mem/protocol/Types.hh"
414#include "mem/ruby/common/Global.hh"
415#include "mem/ruby/system/System.hh"
416''')
417        for include_path in includes:
418            code('#include "${{include_path}}"')
419
420        code('''
421
422using namespace std;
423''')
424
425        # include object classes
426        seen_types = set()
427        for var in self.objects:
428            if var.type.ident not in seen_types and not var.type.isPrimitive:
429                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
430            seen_types.add(var.type.ident)
431
432        code('''
433$c_ident *
434${c_ident}Params::create()
435{
436    return new $c_ident(this);
437}
438
439int $c_ident::m_num_controllers = 0;
440${ident}_ProfileDumper $c_ident::s_profileDumper;
441
442// for adding information to the protocol debug trace
443stringstream ${ident}_transitionComment;
444#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
445
446/** \\brief constructor */
447$c_ident::$c_ident(const Params *p)
448    : AbstractController(p)
449{
450    m_name = "${ident}";
451''')
452        #
453        # max_port_rank is used to size vectors and thus should be one plus the
454        # largest port rank
455        #
456        max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1
457        code('    m_max_in_port_rank = $max_port_rank;')
458        code.indent()
459
460        #
461        # After initializing the universal machine parameters, initialize the
462        # this machines config parameters.  Also detemine if these configuration
463        # params include a sequencer.  This information will be used later for
464        # contecting the sequencer back to the L1 cache controller.
465        #
466        contains_dma_sequencer = False
467        sequencers = []
468        for param in self.config_parameters:
469            if param.name == "dma_sequencer":
470                contains_dma_sequencer = True
471            elif re.compile("sequencer").search(param.name):
472                sequencers.append(param.name)
473            if param.pointer:
474                code('m_${{param.name}}_ptr = p->${{param.name}};')
475            else:
476                code('m_${{param.name}} = p->${{param.name}};')
477
478        #
479        # For the l1 cache controller, add the special atomic support which
480        # includes passing the sequencer a pointer to the controller.
481        #
482        if self.ident == "L1Cache":
483            if not sequencers:
484                self.error("The L1Cache controller must include the sequencer " \
485                           "configuration parameter")
486
487            for seq in sequencers:
488                code('''
489m_${{seq}}_ptr->setController(this);
490    ''')
491
492        else:
493            for seq in sequencers:
494                code('''
495m_${{seq}}_ptr->setController(this);
496    ''')
497
498        #
499        # For the DMA controller, pass the sequencer a pointer to the
500        # controller.
501        #
502        if self.ident == "DMA":
503            if not contains_dma_sequencer:
504                self.error("The DMA controller must include the sequencer " \
505                           "configuration parameter")
506
507            code('''
508m_dma_sequencer_ptr->setController(this);
509''')
510
511        code('m_num_controllers++;')
512        for var in self.objects:
513            if var.ident.find("mandatoryQueue") >= 0:
514                code('''
515m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
516m_${{var.c_ident}}_ptr->setReceiver(this);
517''')
518
519        code.dedent()
520        code('''
521}
522
523void
524$c_ident::init()
525{
526    MachineType machine_type;
527    int base;
528    machine_type = string_to_MachineType("${{var.machine.ident}}");
529    base = MachineType_base_number(machine_type);
530
531    m_machineID.type = MachineType_${ident};
532    m_machineID.num = m_version;
533
534    // initialize objects
535    m_profiler.setVersion(m_version);
536    s_profileDumper.registerProfiler(&m_profiler);
537
538''')
539
540        code.indent()
541        for var in self.objects:
542            vtype = var.type
543            vid = "m_%s_ptr" % var.c_ident
544            if "network" not in var:
545                # Not a network port object
546                if "primitive" in vtype:
547                    code('$vid = new ${{vtype.c_ident}};')
548                    if "default" in var:
549                        code('(*$vid) = ${{var["default"]}};')
550                else:
551                    # Normal Object
552                    # added by SS
553                    if "factory" in var:
554                        code('$vid = ${{var["factory"]}};')
555                    elif var.ident.find("mandatoryQueue") < 0:
556                        th = var.get("template", "")
557                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
558                        args = ""
559                        if "non_obj" not in vtype and not vtype.isEnumeration:
560                            args = var.get("constructor", "")
561                        code('$expr($args);')
562
563                    code('assert($vid != NULL);')
564
565                    if "default" in var:
566                        code('*$vid = ${{var["default"]}}; // Object default')
567                    elif "default" in vtype:
568                        comment = "Type %s default" % vtype.ident
569                        code('*$vid = ${{vtype["default"]}}; // $comment')
570
571                    # Set ordering
572                    if "ordered" in var:
573                        # A buffer
574                        code('$vid->setOrdering(${{var["ordered"]}});')
575
576                    # Set randomization
577                    if "random" in var:
578                        # A buffer
579                        code('$vid->setRandomization(${{var["random"]}});')
580
581                    # Set Priority
582                    if vtype.isBuffer and "rank" in var:
583                        code('$vid->setPriority(${{var["rank"]}});')
584
585                    # Set sender and receiver for trigger queue
586                    if var.ident.find("triggerQueue") >= 0:
587                        code('$vid->setSender(this);')
588                        code('$vid->setReceiver(this);')
589                    elif vtype.c_ident == "TimerTable":
590                        code('$vid->setClockObj(this);')
591
592            else:
593                # Network port object
594                network = var["network"]
595                ordered =  var["ordered"]
596                vnet = var["virtual_network"]
597                vnet_type = var["vnet_type"]
598
599                assert var.machine is not None
600                code('''
601$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
602''')
603
604                code('assert($vid != NULL);')
605
606                # Set the end
607                if network == "To":
608                    code('$vid->setSender(this);')
609                else:
610                    code('$vid->setReceiver(this);')
611
612                # Set ordering
613                if "ordered" in var:
614                    # A buffer
615                    code('$vid->setOrdering(${{var["ordered"]}});')
616
617                # Set randomization
618                if "random" in var:
619                    # A buffer
620                    code('$vid->setRandomization(${{var["random"]}});')
621
622                # Set Priority
623                if "rank" in var:
624                    code('$vid->setPriority(${{var["rank"]}})')
625
626                # Set buffer size
627                if vtype.isBuffer:
628                    code('''
629if (m_buffer_size > 0) {
630    $vid->resize(m_buffer_size);
631}
632''')
633
634                # set description (may be overriden later by port def)
635                code('''
636$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
637
638''')
639
640            if vtype.isBuffer:
641                if "recycle_latency" in var:
642                    code('$vid->setRecycleLatency( ' \
643                         'Cycles(${{var["recycle_latency"]}}));')
644                else:
645                    code('$vid->setRecycleLatency(m_recycle_latency);')
646
647        # Set the prefetchers
648        code()
649        for prefetcher in self.prefetchers:
650            code('${{prefetcher.code}}.setController(this);')
651
652        code()
653        for port in self.in_ports:
654            # Set the queue consumers
655            code('${{port.code}}.setConsumer(this);')
656            # Set the queue descriptions
657            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
658
659        # Initialize the transition profiling
660        code()
661        for trans in self.transitions:
662            # Figure out if we stall
663            stall = False
664            for action in trans.actions:
665                if action.ident == "z_stall":
666                    stall = True
667
668            # Only possible if it is not a 'z' case
669            if not stall:
670                state = "%s_State_%s" % (self.ident, trans.state.ident)
671                event = "%s_Event_%s" % (self.ident, trans.event.ident)
672                code('m_profiler.possibleTransition($state, $event);')
673
674        code.dedent()
675        code('''
676    AbstractController::init();
677    clearStats();
678}
679''')
680
681        has_mandatory_q = False
682        for port in self.in_ports:
683            if port.code.find("mandatoryQueue_ptr") >= 0:
684                has_mandatory_q = True
685
686        if has_mandatory_q:
687            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
688        else:
689            mq_ident = "NULL"
690
691        seq_ident = "NULL"
692        for param in self.config_parameters:
693            if param.name == "sequencer":
694                assert(param.pointer)
695                seq_ident = "m_%s_ptr" % param.name
696
697        code('''
698int
699$c_ident::getNumControllers()
700{
701    return m_num_controllers;
702}
703
704MessageBuffer*
705$c_ident::getMandatoryQueue() const
706{
707    return $mq_ident;
708}
709
710Sequencer*
711$c_ident::getSequencer() const
712{
713    return $seq_ident;
714}
715
716const int &
717$c_ident::getVersion() const
718{
719    return m_version;
720}
721
722const string
723$c_ident::toString() const
724{
725    return "$c_ident";
726}
727
728const string
729$c_ident::getName() const
730{
731    return m_name;
732}
733
734void
735$c_ident::stallBuffer(MessageBuffer* buf, Address addr)
736{
737    if (m_waiting_buffers.count(addr) == 0) {
738        MsgVecType* msgVec = new MsgVecType;
739        msgVec->resize(m_max_in_port_rank, NULL);
740        m_waiting_buffers[addr] = msgVec;
741    }
742    (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
743}
744
745void
746$c_ident::wakeUpBuffers(Address addr)
747{
748    if (m_waiting_buffers.count(addr) > 0) {
749        //
750        // Wake up all possible lower rank (i.e. lower priority) buffers that could
751        // be waiting on this message.
752        //
753        for (int in_port_rank = m_cur_in_port_rank - 1;
754             in_port_rank >= 0;
755             in_port_rank--) {
756            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
757                (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
758            }
759        }
760        delete m_waiting_buffers[addr];
761        m_waiting_buffers.erase(addr);
762    }
763}
764
765void
766$c_ident::wakeUpAllBuffers()
767{
768    //
769    // Wake up all possible buffers that could be waiting on any message.
770    //
771
772    std::vector<MsgVecType*> wokeUpMsgVecs;
773
774    if(m_waiting_buffers.size() > 0) {
775        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
776             buf_iter != m_waiting_buffers.end();
777             ++buf_iter) {
778             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
779                  vec_iter != buf_iter->second->end();
780                  ++vec_iter) {
781                  if (*vec_iter != NULL) {
782                      (*vec_iter)->reanalyzeAllMessages();
783                  }
784             }
785             wokeUpMsgVecs.push_back(buf_iter->second);
786        }
787
788        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
789             wb_iter != wokeUpMsgVecs.end();
790             ++wb_iter) {
791             delete (*wb_iter);
792        }
793
794        m_waiting_buffers.clear();
795    }
796}
797
798void
799$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
800{
801    m_is_blocking = true;
802    m_block_map[addr] = port;
803}
804
805void
806$c_ident::unblock(Address addr)
807{
808    m_block_map.erase(addr);
809    if (m_block_map.size() == 0) {
810       m_is_blocking = false;
811    }
812}
813
814void
815$c_ident::print(ostream& out) const
816{
817    out << "[$c_ident " << m_version << "]";
818}
819
820void
821$c_ident::printStats(ostream& out) const
822{
823''')
824        #
825        # Cache and Memory Controllers have specific profilers associated with
826        # them.  Print out these stats before dumping state transition stats.
827        #
828        for param in self.config_parameters:
829            if param.type_ast.type.ident == "CacheMemory" or \
830               param.type_ast.type.ident == "DirectoryMemory" or \
831                   param.type_ast.type.ident == "MemoryControl":
832                assert(param.pointer)
833                code('    m_${{param.ident}}_ptr->printStats(out);')
834
835        code('''
836    if (m_version == 0) {
837        s_profileDumper.dumpStats(out);
838    }
839}
840
841void $c_ident::clearStats() {
842''')
843        #
844        # Cache and Memory Controllers have specific profilers associated with
845        # them.  These stats must be cleared too.
846        #
847        for param in self.config_parameters:
848            if param.type_ast.type.ident == "CacheMemory" or \
849                   param.type_ast.type.ident == "MemoryControl":
850                assert(param.pointer)
851                code('    m_${{param.ident}}_ptr->clearStats();')
852
853        code('''
854    m_profiler.clearStats();
855    AbstractController::clearStats();
856}
857''')
858
859        if self.EntryType != None:
860            code('''
861
862// Set and Reset for cache_entry variable
863void
864$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
865{
866  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
867}
868
869void
870$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
871{
872  m_cache_entry_ptr = 0;
873}
874''')
875
876        if self.TBEType != None:
877            code('''
878
879// Set and Reset for tbe variable
880void
881$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
882{
883  m_tbe_ptr = m_new_tbe;
884}
885
886void
887$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
888{
889  m_tbe_ptr = NULL;
890}
891''')
892
893        code('''
894
895void
896$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
897{
898''')
899        #
900        # Record cache contents for all associated caches.
901        #
902        code.indent()
903        for param in self.config_parameters:
904            if param.type_ast.type.ident == "CacheMemory":
905                assert(param.pointer)
906                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
907
908        code.dedent()
909        code('''
910}
911
912// Actions
913''')
914        if self.TBEType != None and self.EntryType != None:
915            for action in self.actions.itervalues():
916                if "c_code" not in action:
917                 continue
918
919                code('''
920/** \\brief ${{action.desc}} */
921void
922$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
923{
924    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
925    ${{action["c_code"]}}
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, const Address& 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, const Address& 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}}(const Address& 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 reads from messages buffered in the controller
978        code('''
979bool
980$c_ident::functionalReadBuffers(PacketPtr& pkt)
981{
982''')
983        for var in self.objects:
984            vtype = var.type
985            if vtype.isBuffer:
986                vid = "m_%s_ptr" % var.c_ident
987                code('if ($vid->functionalRead(pkt)) { return true; }')
988        code('''
989                return false;
990}
991''')
992
993        # Function for functional writes to messages buffered in the controller
994        code('''
995uint32_t
996$c_ident::functionalWriteBuffers(PacketPtr& pkt)
997{
998    uint32_t num_functional_writes = 0;
999''')
1000        for var in self.objects:
1001            vtype = var.type
1002            if vtype.isBuffer:
1003                vid = "m_%s_ptr" % var.c_ident
1004                code('num_functional_writes += $vid->functionalWrite(pkt);')
1005        code('''
1006    return num_functional_writes;
1007}
1008''')
1009
1010        code.write(path, "%s.cc" % c_ident)
1011
1012    def printCWakeup(self, path, includes):
1013        '''Output the wakeup loop for the events'''
1014
1015        code = self.symtab.codeFormatter()
1016        ident = self.ident
1017
1018        outputRequest_types = True
1019        if len(self.request_types) == 0:
1020            outputRequest_types = False
1021
1022        code('''
1023// Auto generated C++ code started by $__file__:$__line__
1024// ${ident}: ${{self.short}}
1025
1026#include <sys/types.h>
1027#include <unistd.h>
1028
1029#include <cassert>
1030
1031#include "base/misc.hh"
1032#include "debug/RubySlicc.hh"
1033#include "mem/protocol/${ident}_Controller.hh"
1034#include "mem/protocol/${ident}_Event.hh"
1035#include "mem/protocol/${ident}_State.hh"
1036''')
1037
1038        if outputRequest_types:
1039            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1040
1041        code('''
1042#include "mem/protocol/Types.hh"
1043#include "mem/ruby/common/Global.hh"
1044#include "mem/ruby/system/System.hh"
1045''')
1046
1047
1048        for include_path in includes:
1049            code('#include "${{include_path}}"')
1050
1051        code('''
1052
1053using namespace std;
1054
1055void
1056${ident}_Controller::wakeup()
1057{
1058    int counter = 0;
1059    while (true) {
1060        // Some cases will put us into an infinite loop without this limit
1061        assert(counter <= m_transitions_per_cycle);
1062        if (counter == m_transitions_per_cycle) {
1063            // Count how often we are fully utilized
1064            m_fully_busy_cycles++;
1065
1066            // Wakeup in another cycle and try again
1067            scheduleEvent(Cycles(1));
1068            break;
1069        }
1070''')
1071
1072        code.indent()
1073        code.indent()
1074
1075        # InPorts
1076        #
1077        for port in self.in_ports:
1078            code.indent()
1079            code('// ${ident}InPort $port')
1080            if port.pairs.has_key("rank"):
1081                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1082            else:
1083                code('m_cur_in_port_rank = 0;')
1084            code('${{port["c_code_in_port"]}}')
1085            code.dedent()
1086
1087            code('')
1088
1089        code.dedent()
1090        code.dedent()
1091        code('''
1092        break;  // If we got this far, we have nothing left todo
1093    }
1094}
1095''')
1096
1097        code.write(path, "%s_Wakeup.cc" % self.ident)
1098
1099    def printCSwitch(self, path):
1100        '''Output switch statement for transition table'''
1101
1102        code = self.symtab.codeFormatter()
1103        ident = self.ident
1104
1105        code('''
1106// Auto generated C++ code started by $__file__:$__line__
1107// ${ident}: ${{self.short}}
1108
1109#include <cassert>
1110
1111#include "base/misc.hh"
1112#include "base/trace.hh"
1113#include "debug/ProtocolTrace.hh"
1114#include "debug/RubyGenerated.hh"
1115#include "mem/protocol/${ident}_Controller.hh"
1116#include "mem/protocol/${ident}_Event.hh"
1117#include "mem/protocol/${ident}_State.hh"
1118#include "mem/protocol/Types.hh"
1119#include "mem/ruby/common/Global.hh"
1120#include "mem/ruby/system/System.hh"
1121
1122#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1123
1124#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1125#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1126
1127TransitionResult
1128${ident}_Controller::doTransition(${ident}_Event event,
1129''')
1130        if self.EntryType != None:
1131            code('''
1132                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1133''')
1134        if self.TBEType != None:
1135            code('''
1136                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1137''')
1138        code('''
1139                                  const Address &addr)
1140{
1141''')
1142        if self.TBEType != None and self.EntryType != None:
1143            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1144        elif self.TBEType != None:
1145            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1146        elif self.EntryType != None:
1147            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1148        else:
1149            code('${ident}_State state = getState(addr);')
1150
1151        code('''
1152    ${ident}_State next_state = state;
1153
1154    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1155            *this, curCycle(), ${ident}_State_to_string(state),
1156            ${ident}_Event_to_string(event), addr);
1157
1158    TransitionResult result =
1159''')
1160        if self.TBEType != None and self.EntryType != None:
1161            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1162        elif self.TBEType != None:
1163            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1164        elif self.EntryType != None:
1165            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1166        else:
1167            code('doTransitionWorker(event, state, next_state, addr);')
1168
1169        code('''
1170    if (result == TransitionResult_Valid) {
1171        DPRINTF(RubyGenerated, "next_state: %s\\n",
1172                ${ident}_State_to_string(next_state));
1173        m_profiler.countTransition(state, event);
1174        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1175                 curTick(), m_version, "${ident}",
1176                 ${ident}_Event_to_string(event),
1177                 ${ident}_State_to_string(state),
1178                 ${ident}_State_to_string(next_state),
1179                 addr, GET_TRANSITION_COMMENT());
1180
1181        CLEAR_TRANSITION_COMMENT();
1182''')
1183        if self.TBEType != None and self.EntryType != None:
1184            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1185            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1186        elif self.TBEType != None:
1187            code('setState(m_tbe_ptr, addr, next_state);')
1188            code('setAccessPermission(addr, next_state);')
1189        elif self.EntryType != None:
1190            code('setState(m_cache_entry_ptr, addr, next_state);')
1191            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1192        else:
1193            code('setState(addr, next_state);')
1194            code('setAccessPermission(addr, next_state);')
1195
1196        code('''
1197    } else if (result == TransitionResult_ResourceStall) {
1198        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1199                 curTick(), m_version, "${ident}",
1200                 ${ident}_Event_to_string(event),
1201                 ${ident}_State_to_string(state),
1202                 ${ident}_State_to_string(next_state),
1203                 addr, "Resource Stall");
1204    } else if (result == TransitionResult_ProtocolStall) {
1205        DPRINTF(RubyGenerated, "stalling\\n");
1206        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1207                 curTick(), m_version, "${ident}",
1208                 ${ident}_Event_to_string(event),
1209                 ${ident}_State_to_string(state),
1210                 ${ident}_State_to_string(next_state),
1211                 addr, "Protocol Stall");
1212    }
1213
1214    return result;
1215}
1216
1217TransitionResult
1218${ident}_Controller::doTransitionWorker(${ident}_Event event,
1219                                        ${ident}_State state,
1220                                        ${ident}_State& next_state,
1221''')
1222
1223        if self.TBEType != None:
1224            code('''
1225                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1226''')
1227        if self.EntryType != None:
1228                  code('''
1229                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1230''')
1231        code('''
1232                                        const Address& addr)
1233{
1234    switch(HASH_FUN(state, event)) {
1235''')
1236
1237        # This map will allow suppress generating duplicate code
1238        cases = orderdict()
1239
1240        for trans in self.transitions:
1241            case_string = "%s_State_%s, %s_Event_%s" % \
1242                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1243
1244            case = self.symtab.codeFormatter()
1245            # Only set next_state if it changes
1246            if trans.state != trans.nextState:
1247                ns_ident = trans.nextState.ident
1248                case('next_state = ${ident}_State_${ns_ident};')
1249
1250            actions = trans.actions
1251            request_types = trans.request_types
1252
1253            # Check for resources
1254            case_sorter = []
1255            res = trans.resources
1256            for key,val in res.iteritems():
1257                if key.type.ident != "DNUCAStopTable":
1258                    val = '''
1259if (!%s.areNSlotsAvailable(%s))
1260    return TransitionResult_ResourceStall;
1261''' % (key.code, val)
1262                case_sorter.append(val)
1263
1264            # Check all of the request_types for resource constraints
1265            for request_type in request_types:
1266                val = '''
1267if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1268    return TransitionResult_ResourceStall;
1269}
1270''' % (self.ident, request_type.ident)
1271                case_sorter.append(val)
1272
1273            # Emit the code sequences in a sorted order.  This makes the
1274            # output deterministic (without this the output order can vary
1275            # since Map's keys() on a vector of pointers is not deterministic
1276            for c in sorted(case_sorter):
1277                case("$c")
1278
1279            # Record access types for this transition
1280            for request_type in request_types:
1281                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1282
1283            # Figure out if we stall
1284            stall = False
1285            for action in actions:
1286                if action.ident == "z_stall":
1287                    stall = True
1288                    break
1289
1290            if stall:
1291                case('return TransitionResult_ProtocolStall;')
1292            else:
1293                if self.TBEType != None and self.EntryType != None:
1294                    for action in actions:
1295                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1296                elif self.TBEType != None:
1297                    for action in actions:
1298                        case('${{action.ident}}(m_tbe_ptr, addr);')
1299                elif self.EntryType != None:
1300                    for action in actions:
1301                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1302                else:
1303                    for action in actions:
1304                        case('${{action.ident}}(addr);')
1305                case('return TransitionResult_Valid;')
1306
1307            case = str(case)
1308
1309            # Look to see if this transition code is unique.
1310            if case not in cases:
1311                cases[case] = []
1312
1313            cases[case].append(case_string)
1314
1315        # Walk through all of the unique code blocks and spit out the
1316        # corresponding case statement elements
1317        for case,transitions in cases.iteritems():
1318            # Iterative over all the multiple transitions that share
1319            # the same code
1320            for trans in transitions:
1321                code('  case HASH_FUN($trans):')
1322            code('    $case')
1323
1324        code('''
1325      default:
1326        fatal("Invalid transition\\n"
1327              "%s time: %d addr: %s event: %s state: %s\\n",
1328              name(), curCycle(), addr, event, state);
1329    }
1330    return TransitionResult_Valid;
1331}
1332''')
1333        code.write(path, "%s_Transitions.cc" % self.ident)
1334
1335    def printProfileDumperHH(self, path):
1336        code = self.symtab.codeFormatter()
1337        ident = self.ident
1338
1339        code('''
1340// Auto generated C++ code started by $__file__:$__line__
1341// ${ident}: ${{self.short}}
1342
1343#ifndef __${ident}_PROFILE_DUMPER_HH__
1344#define __${ident}_PROFILE_DUMPER_HH__
1345
1346#include <cassert>
1347#include <iostream>
1348#include <vector>
1349
1350#include "${ident}_Event.hh"
1351#include "${ident}_Profiler.hh"
1352
1353typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1354
1355class ${ident}_ProfileDumper
1356{
1357  public:
1358    ${ident}_ProfileDumper();
1359    void registerProfiler(${ident}_Profiler* profiler);
1360    void dumpStats(std::ostream& out) const;
1361
1362  private:
1363    ${ident}_profilers m_profilers;
1364};
1365
1366#endif // __${ident}_PROFILE_DUMPER_HH__
1367''')
1368        code.write(path, "%s_ProfileDumper.hh" % self.ident)
1369
1370    def printProfileDumperCC(self, path):
1371        code = self.symtab.codeFormatter()
1372        ident = self.ident
1373
1374        code('''
1375// Auto generated C++ code started by $__file__:$__line__
1376// ${ident}: ${{self.short}}
1377
1378#include "mem/protocol/${ident}_ProfileDumper.hh"
1379
1380${ident}_ProfileDumper::${ident}_ProfileDumper()
1381{
1382}
1383
1384void
1385${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1386{
1387    m_profilers.push_back(profiler);
1388}
1389
1390void
1391${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1392{
1393    out << " --- ${ident} ---\\n";
1394    out << " - Event Counts -\\n";
1395    for (${ident}_Event event = ${ident}_Event_FIRST;
1396         event < ${ident}_Event_NUM;
1397         ++event) {
1398        out << (${ident}_Event) event << " [";
1399        uint64 total = 0;
1400        for (int i = 0; i < m_profilers.size(); i++) {
1401             out << m_profilers[i]->getEventCount(event) << " ";
1402             total += m_profilers[i]->getEventCount(event);
1403        }
1404        out << "] " << total << "\\n";
1405    }
1406    out << "\\n";
1407    out << " - Transitions -\\n";
1408    for (${ident}_State state = ${ident}_State_FIRST;
1409         state < ${ident}_State_NUM;
1410         ++state) {
1411        for (${ident}_Event event = ${ident}_Event_FIRST;
1412             event < ${ident}_Event_NUM;
1413             ++event) {
1414            if (m_profilers[0]->isPossible(state, event)) {
1415                out << (${ident}_State) state << "  "
1416                    << (${ident}_Event) event << " [";
1417                uint64 total = 0;
1418                for (int i = 0; i < m_profilers.size(); i++) {
1419                     out << m_profilers[i]->getTransitionCount(state, event) << " ";
1420                     total += m_profilers[i]->getTransitionCount(state, event);
1421                }
1422                out << "] " << total << "\\n";
1423            }
1424        }
1425        out << "\\n";
1426    }
1427}
1428''')
1429        code.write(path, "%s_ProfileDumper.cc" % self.ident)
1430
1431    def printProfilerHH(self, path):
1432        code = self.symtab.codeFormatter()
1433        ident = self.ident
1434
1435        code('''
1436// Auto generated C++ code started by $__file__:$__line__
1437// ${ident}: ${{self.short}}
1438
1439#ifndef __${ident}_PROFILER_HH__
1440#define __${ident}_PROFILER_HH__
1441
1442#include <cassert>
1443#include <iostream>
1444
1445#include "mem/protocol/${ident}_Event.hh"
1446#include "mem/protocol/${ident}_State.hh"
1447#include "mem/ruby/common/TypeDefines.hh"
1448
1449class ${ident}_Profiler
1450{
1451  public:
1452    ${ident}_Profiler();
1453    void setVersion(int version);
1454    void countTransition(${ident}_State state, ${ident}_Event event);
1455    void possibleTransition(${ident}_State state, ${ident}_Event event);
1456    uint64 getEventCount(${ident}_Event event);
1457    bool isPossible(${ident}_State state, ${ident}_Event event);
1458    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1459    void clearStats();
1460
1461  private:
1462    int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1463    int m_event_counters[${ident}_Event_NUM];
1464    bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1465    int m_version;
1466};
1467
1468#endif // __${ident}_PROFILER_HH__
1469''')
1470        code.write(path, "%s_Profiler.hh" % self.ident)
1471
1472    def printProfilerCC(self, path):
1473        code = self.symtab.codeFormatter()
1474        ident = self.ident
1475
1476        code('''
1477// Auto generated C++ code started by $__file__:$__line__
1478// ${ident}: ${{self.short}}
1479
1480#include <cassert>
1481
1482#include "mem/protocol/${ident}_Profiler.hh"
1483
1484${ident}_Profiler::${ident}_Profiler()
1485{
1486    for (int state = 0; state < ${ident}_State_NUM; state++) {
1487        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1488            m_possible[state][event] = false;
1489            m_counters[state][event] = 0;
1490        }
1491    }
1492    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1493        m_event_counters[event] = 0;
1494    }
1495}
1496
1497void
1498${ident}_Profiler::setVersion(int version)
1499{
1500    m_version = version;
1501}
1502
1503void
1504${ident}_Profiler::clearStats()
1505{
1506    for (int state = 0; state < ${ident}_State_NUM; state++) {
1507        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1508            m_counters[state][event] = 0;
1509        }
1510    }
1511
1512    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1513        m_event_counters[event] = 0;
1514    }
1515}
1516void
1517${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1518{
1519    assert(m_possible[state][event]);
1520    m_counters[state][event]++;
1521    m_event_counters[event]++;
1522}
1523void
1524${ident}_Profiler::possibleTransition(${ident}_State state,
1525                                      ${ident}_Event event)
1526{
1527    m_possible[state][event] = true;
1528}
1529
1530uint64
1531${ident}_Profiler::getEventCount(${ident}_Event event)
1532{
1533    return m_event_counters[event];
1534}
1535
1536bool
1537${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1538{
1539    return m_possible[state][event];
1540}
1541
1542uint64
1543${ident}_Profiler::getTransitionCount(${ident}_State state,
1544                                      ${ident}_Event event)
1545{
1546    return m_counters[state][event];
1547}
1548
1549''')
1550        code.write(path, "%s_Profiler.cc" % self.ident)
1551
1552    # **************************
1553    # ******* HTML Files *******
1554    # **************************
1555    def frameRef(self, click_href, click_target, over_href, over_num, text):
1556        code = self.symtab.codeFormatter(fix_newlines=False)
1557        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1558    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1559        parent.frames[$over_num].location='$over_href'
1560    }\">
1561    ${{html.formatShorthand(text)}}
1562    </A>""")
1563        return str(code)
1564
1565    def writeHTMLFiles(self, path):
1566        # Create table with no row hilighted
1567        self.printHTMLTransitions(path, None)
1568
1569        # Generate transition tables
1570        for state in self.states.itervalues():
1571            self.printHTMLTransitions(path, state)
1572
1573        # Generate action descriptions
1574        for action in self.actions.itervalues():
1575            name = "%s_action_%s.html" % (self.ident, action.ident)
1576            code = html.createSymbol(action, "Action")
1577            code.write(path, name)
1578
1579        # Generate state descriptions
1580        for state in self.states.itervalues():
1581            name = "%s_State_%s.html" % (self.ident, state.ident)
1582            code = html.createSymbol(state, "State")
1583            code.write(path, name)
1584
1585        # Generate event descriptions
1586        for event in self.events.itervalues():
1587            name = "%s_Event_%s.html" % (self.ident, event.ident)
1588            code = html.createSymbol(event, "Event")
1589            code.write(path, name)
1590
1591    def printHTMLTransitions(self, path, active_state):
1592        code = self.symtab.codeFormatter()
1593
1594        code('''
1595<HTML>
1596<BODY link="blue" vlink="blue">
1597
1598<H1 align="center">${{html.formatShorthand(self.short)}}:
1599''')
1600        code.indent()
1601        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1602            mid = machine.ident
1603            if i != 0:
1604                extra = " - "
1605            else:
1606                extra = ""
1607            if machine == self:
1608                code('$extra$mid')
1609            else:
1610                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1611        code.dedent()
1612
1613        code("""
1614</H1>
1615
1616<TABLE border=1>
1617<TR>
1618  <TH> </TH>
1619""")
1620
1621        for event in self.events.itervalues():
1622            href = "%s_Event_%s.html" % (self.ident, event.ident)
1623            ref = self.frameRef(href, "Status", href, "1", event.short)
1624            code('<TH bgcolor=white>$ref</TH>')
1625
1626        code('</TR>')
1627        # -- Body of table
1628        for state in self.states.itervalues():
1629            # -- Each row
1630            if state == active_state:
1631                color = "yellow"
1632            else:
1633                color = "white"
1634
1635            click = "%s_table_%s.html" % (self.ident, state.ident)
1636            over = "%s_State_%s.html" % (self.ident, state.ident)
1637            text = html.formatShorthand(state.short)
1638            ref = self.frameRef(click, "Table", over, "1", state.short)
1639            code('''
1640<TR>
1641  <TH bgcolor=$color>$ref</TH>
1642''')
1643
1644            # -- One column for each event
1645            for event in self.events.itervalues():
1646                trans = self.table.get((state,event), None)
1647                if trans is None:
1648                    # This is the no transition case
1649                    if state == active_state:
1650                        color = "#C0C000"
1651                    else:
1652                        color = "lightgrey"
1653
1654                    code('<TD bgcolor=$color>&nbsp;</TD>')
1655                    continue
1656
1657                next = trans.nextState
1658                stall_action = False
1659
1660                # -- Get the actions
1661                for action in trans.actions:
1662                    if action.ident == "z_stall" or \
1663                       action.ident == "zz_recycleMandatoryQueue":
1664                        stall_action = True
1665
1666                # -- Print out "actions/next-state"
1667                if stall_action:
1668                    if state == active_state:
1669                        color = "#C0C000"
1670                    else:
1671                        color = "lightgrey"
1672
1673                elif active_state and next.ident == active_state.ident:
1674                    color = "aqua"
1675                elif state == active_state:
1676                    color = "yellow"
1677                else:
1678                    color = "white"
1679
1680                code('<TD bgcolor=$color>')
1681                for action in trans.actions:
1682                    href = "%s_action_%s.html" % (self.ident, action.ident)
1683                    ref = self.frameRef(href, "Status", href, "1",
1684                                        action.short)
1685                    code('  $ref')
1686                if next != state:
1687                    if trans.actions:
1688                        code('/')
1689                    click = "%s_table_%s.html" % (self.ident, next.ident)
1690                    over = "%s_State_%s.html" % (self.ident, next.ident)
1691                    ref = self.frameRef(click, "Table", over, "1", next.short)
1692                    code("$ref")
1693                code("</TD>")
1694
1695            # -- Each row
1696            if state == active_state:
1697                color = "yellow"
1698            else:
1699                color = "white"
1700
1701            click = "%s_table_%s.html" % (self.ident, state.ident)
1702            over = "%s_State_%s.html" % (self.ident, state.ident)
1703            ref = self.frameRef(click, "Table", over, "1", state.short)
1704            code('''
1705  <TH bgcolor=$color>$ref</TH>
1706</TR>
1707''')
1708        code('''
1709<!- Column footer->
1710<TR>
1711  <TH> </TH>
1712''')
1713
1714        for event in self.events.itervalues():
1715            href = "%s_Event_%s.html" % (self.ident, event.ident)
1716            ref = self.frameRef(href, "Status", href, "1", event.short)
1717            code('<TH bgcolor=white>$ref</TH>')
1718        code('''
1719</TR>
1720</TABLE>
1721</BODY></HTML>
1722''')
1723
1724
1725        if active_state:
1726            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1727        else:
1728            name = "%s_table.html" % self.ident
1729        code.write(path, name)
1730
1731__all__ = [ "StateMachine" ]
1732