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