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