StateMachine.py revision 9366:bf8eb26c7b7e
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
531    m_machineID.type = MachineType_${ident};
532    m_machineID.num = m_version;
533
534    // initialize objects
535    m_profiler.setVersion(m_version);
536    s_profileDumper.registerProfiler(&m_profiler);
537
538''')
539
540        code.indent()
541        for var in self.objects:
542            vtype = var.type
543            vid = "m_%s_ptr" % var.c_ident
544            if "network" not in var:
545                # Not a network port object
546                if "primitive" in vtype:
547                    code('$vid = new ${{vtype.c_ident}};')
548                    if "default" in var:
549                        code('(*$vid) = ${{var["default"]}};')
550                else:
551                    # Normal Object
552                    # added by SS
553                    if "factory" in var:
554                        code('$vid = ${{var["factory"]}};')
555                    elif var.ident.find("mandatoryQueue") < 0:
556                        th = var.get("template", "")
557                        expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
558                        args = ""
559                        if "non_obj" not in vtype and not vtype.isEnumeration:
560                            args = var.get("constructor", "")
561                        code('$expr($args);')
562
563                    code('assert($vid != NULL);')
564
565                    if "default" in var:
566                        code('*$vid = ${{var["default"]}}; // Object default')
567                    elif "default" in vtype:
568                        comment = "Type %s default" % vtype.ident
569                        code('*$vid = ${{vtype["default"]}}; // $comment')
570
571                    # Set ordering
572                    if "ordered" in var and "trigger_queue" not in var:
573                        # A buffer
574                        code('$vid->setOrdering(${{var["ordered"]}});')
575
576                    # Set randomization
577                    if "random" in var:
578                        # A buffer
579                        code('$vid->setRandomization(${{var["random"]}});')
580
581                    # Set Priority
582                    if vtype.isBuffer and \
583                           "rank" in var and "trigger_queue" not in var:
584                        code('$vid->setPriority(${{var["rank"]}});')
585
586            else:
587                # Network port object
588                network = var["network"]
589                ordered =  var["ordered"]
590                vnet = var["virtual_network"]
591                vnet_type = var["vnet_type"]
592
593                assert var.machine is not None
594                code('''
595machine_type = string_to_MachineType("${{var.machine.ident}}");
596base = MachineType_base_number(machine_type);
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        # Set the queue consumers
642        code()
643        for port in self.in_ports:
644            code('${{port.code}}.setConsumer(this);')
645
646        # Set the queue descriptions
647        code()
648        for port in self.in_ports:
649            code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
650
651        # Initialize the transition profiling
652        code()
653        for trans in self.transitions:
654            # Figure out if we stall
655            stall = False
656            for action in trans.actions:
657                if action.ident == "z_stall":
658                    stall = True
659
660            # Only possible if it is not a 'z' case
661            if not stall:
662                state = "%s_State_%s" % (self.ident, trans.state.ident)
663                event = "%s_Event_%s" % (self.ident, trans.event.ident)
664                code('m_profiler.possibleTransition($state, $event);')
665
666        code.dedent()
667        code('}')
668
669        has_mandatory_q = False
670        for port in self.in_ports:
671            if port.code.find("mandatoryQueue_ptr") >= 0:
672                has_mandatory_q = True
673
674        if has_mandatory_q:
675            mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
676        else:
677            mq_ident = "NULL"
678
679        seq_ident = "NULL"
680        for param in self.config_parameters:
681            if param.name == "sequencer":
682                assert(param.pointer)
683                seq_ident = "m_%s_ptr" % param.name
684
685        code('''
686int
687$c_ident::getNumControllers()
688{
689    return m_num_controllers;
690}
691
692MessageBuffer*
693$c_ident::getMandatoryQueue() const
694{
695    return $mq_ident;
696}
697
698Sequencer*
699$c_ident::getSequencer() const
700{
701    return $seq_ident;
702}
703
704const int &
705$c_ident::getVersion() const
706{
707    return m_version;
708}
709
710const string
711$c_ident::toString() const
712{
713    return "$c_ident";
714}
715
716const string
717$c_ident::getName() const
718{
719    return m_name;
720}
721
722void
723$c_ident::stallBuffer(MessageBuffer* buf, Address addr)
724{
725    if (m_waiting_buffers.count(addr) == 0) {
726        MsgVecType* msgVec = new MsgVecType;
727        msgVec->resize(m_max_in_port_rank, NULL);
728        m_waiting_buffers[addr] = msgVec;
729    }
730    (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
731}
732
733void
734$c_ident::wakeUpBuffers(Address addr)
735{
736    if (m_waiting_buffers.count(addr) > 0) {
737        //
738        // Wake up all possible lower rank (i.e. lower priority) buffers that could
739        // be waiting on this message.
740        //
741        for (int in_port_rank = m_cur_in_port_rank - 1;
742             in_port_rank >= 0;
743             in_port_rank--) {
744            if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
745                (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
746            }
747        }
748        delete m_waiting_buffers[addr];
749        m_waiting_buffers.erase(addr);
750    }
751}
752
753void
754$c_ident::wakeUpAllBuffers()
755{
756    //
757    // Wake up all possible buffers that could be waiting on any message.
758    //
759
760    std::vector<MsgVecType*> wokeUpMsgVecs;
761
762    if(m_waiting_buffers.size() > 0) {
763        for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
764             buf_iter != m_waiting_buffers.end();
765             ++buf_iter) {
766             for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
767                  vec_iter != buf_iter->second->end();
768                  ++vec_iter) {
769                  if (*vec_iter != NULL) {
770                      (*vec_iter)->reanalyzeAllMessages();
771                  }
772             }
773             wokeUpMsgVecs.push_back(buf_iter->second);
774        }
775
776        for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
777             wb_iter != wokeUpMsgVecs.end();
778             ++wb_iter) {
779             delete (*wb_iter);
780        }
781
782        m_waiting_buffers.clear();
783    }
784}
785
786void
787$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
788{
789    m_is_blocking = true;
790    m_block_map[addr] = port;
791}
792
793void
794$c_ident::unblock(Address addr)
795{
796    m_block_map.erase(addr);
797    if (m_block_map.size() == 0) {
798       m_is_blocking = false;
799    }
800}
801
802void
803$c_ident::print(ostream& out) const
804{
805    out << "[$c_ident " << m_version << "]";
806}
807
808void
809$c_ident::printStats(ostream& out) const
810{
811''')
812        #
813        # Cache and Memory Controllers have specific profilers associated with
814        # them.  Print out these stats before dumping state transition stats.
815        #
816        for param in self.config_parameters:
817            if param.type_ast.type.ident == "CacheMemory" or \
818               param.type_ast.type.ident == "DirectoryMemory" or \
819                   param.type_ast.type.ident == "MemoryControl":
820                assert(param.pointer)
821                code('    m_${{param.ident}}_ptr->printStats(out);')
822
823        code('''
824    if (m_version == 0) {
825        s_profileDumper.dumpStats(out);
826    }
827}
828
829void $c_ident::clearStats() {
830''')
831        #
832        # Cache and Memory Controllers have specific profilers associated with
833        # them.  These stats must be cleared too.
834        #
835        for param in self.config_parameters:
836            if param.type_ast.type.ident == "CacheMemory" or \
837                   param.type_ast.type.ident == "MemoryControl":
838                assert(param.pointer)
839                code('    m_${{param.ident}}_ptr->clearStats();')
840
841        code('''
842    m_profiler.clearStats();
843}
844''')
845
846        if self.EntryType != None:
847            code('''
848
849// Set and Reset for cache_entry variable
850void
851$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
852{
853  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
854}
855
856void
857$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
858{
859  m_cache_entry_ptr = 0;
860}
861''')
862
863        if self.TBEType != None:
864            code('''
865
866// Set and Reset for tbe variable
867void
868$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
869{
870  m_tbe_ptr = m_new_tbe;
871}
872
873void
874$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
875{
876  m_tbe_ptr = NULL;
877}
878''')
879
880        code('''
881
882void
883$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
884{
885''')
886        #
887        # Record cache contents for all associated caches.
888        #
889        code.indent()
890        for param in self.config_parameters:
891            if param.type_ast.type.ident == "CacheMemory":
892                assert(param.pointer)
893                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
894
895        code.dedent()
896        code('''
897}
898
899// Actions
900''')
901        if self.TBEType != None and self.EntryType != None:
902            for action in self.actions.itervalues():
903                if "c_code" not in action:
904                 continue
905
906                code('''
907/** \\brief ${{action.desc}} */
908void
909$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
910{
911    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
912    ${{action["c_code"]}}
913}
914
915''')
916        elif self.TBEType != None:
917            for action in self.actions.itervalues():
918                if "c_code" not in action:
919                 continue
920
921                code('''
922/** \\brief ${{action.desc}} */
923void
924$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
925{
926    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
927    ${{action["c_code"]}}
928}
929
930''')
931        elif self.EntryType != None:
932            for action in self.actions.itervalues():
933                if "c_code" not in action:
934                 continue
935
936                code('''
937/** \\brief ${{action.desc}} */
938void
939$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
940{
941    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
942    ${{action["c_code"]}}
943}
944
945''')
946        else:
947            for action in self.actions.itervalues():
948                if "c_code" not in action:
949                 continue
950
951                code('''
952/** \\brief ${{action.desc}} */
953void
954$c_ident::${{action.ident}}(const Address& addr)
955{
956    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
957    ${{action["c_code"]}}
958}
959
960''')
961        for func in self.functions:
962            code(func.generateCode())
963
964        # Function for functional reads from messages buffered in the controller
965        code('''
966bool
967$c_ident::functionalReadBuffers(PacketPtr& pkt)
968{
969''')
970        for var in self.objects:
971            vtype = var.type
972            if vtype.isBuffer:
973                vid = "m_%s_ptr" % var.c_ident
974                code('if ($vid->functionalRead(pkt)) { return true; }')
975        code('''
976                return false;
977}
978''')
979
980        # Function for functional writes to messages buffered in the controller
981        code('''
982uint32_t
983$c_ident::functionalWriteBuffers(PacketPtr& pkt)
984{
985    uint32_t num_functional_writes = 0;
986''')
987        for var in self.objects:
988            vtype = var.type
989            if vtype.isBuffer:
990                vid = "m_%s_ptr" % var.c_ident
991                code('num_functional_writes += $vid->functionalWrite(pkt);')
992        code('''
993    return num_functional_writes;
994}
995''')
996
997        code.write(path, "%s.cc" % c_ident)
998
999    def printCWakeup(self, path, includes):
1000        '''Output the wakeup loop for the events'''
1001
1002        code = self.symtab.codeFormatter()
1003        ident = self.ident
1004
1005        outputRequest_types = True
1006        if len(self.request_types) == 0:
1007            outputRequest_types = False
1008
1009        code('''
1010// Auto generated C++ code started by $__file__:$__line__
1011// ${ident}: ${{self.short}}
1012
1013#include <sys/types.h>
1014#include <unistd.h>
1015
1016#include <cassert>
1017
1018#include "base/misc.hh"
1019#include "debug/RubySlicc.hh"
1020#include "mem/protocol/${ident}_Controller.hh"
1021#include "mem/protocol/${ident}_Event.hh"
1022#include "mem/protocol/${ident}_State.hh"
1023''')
1024
1025        if outputRequest_types:
1026            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1027
1028        code('''
1029#include "mem/protocol/Types.hh"
1030#include "mem/ruby/common/Global.hh"
1031#include "mem/ruby/system/System.hh"
1032''')
1033
1034
1035        for include_path in includes:
1036            code('#include "${{include_path}}"')
1037
1038        code('''
1039
1040using namespace std;
1041
1042void
1043${ident}_Controller::wakeup()
1044{
1045    int counter = 0;
1046    while (true) {
1047        // Some cases will put us into an infinite loop without this limit
1048        assert(counter <= m_transitions_per_cycle);
1049        if (counter == m_transitions_per_cycle) {
1050            // Count how often we are fully utilized
1051            g_system_ptr->getProfiler()->controllerBusy(m_machineID);
1052
1053            // Wakeup in another cycle and try again
1054            scheduleEvent(1);
1055            break;
1056        }
1057''')
1058
1059        code.indent()
1060        code.indent()
1061
1062        # InPorts
1063        #
1064        for port in self.in_ports:
1065            code.indent()
1066            code('// ${ident}InPort $port')
1067            if port.pairs.has_key("rank"):
1068                code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1069            else:
1070                code('m_cur_in_port_rank = 0;')
1071            code('${{port["c_code_in_port"]}}')
1072            code.dedent()
1073
1074            code('')
1075
1076        code.dedent()
1077        code.dedent()
1078        code('''
1079        break;  // If we got this far, we have nothing left todo
1080    }
1081}
1082''')
1083
1084        code.write(path, "%s_Wakeup.cc" % self.ident)
1085
1086    def printCSwitch(self, path):
1087        '''Output switch statement for transition table'''
1088
1089        code = self.symtab.codeFormatter()
1090        ident = self.ident
1091
1092        code('''
1093// Auto generated C++ code started by $__file__:$__line__
1094// ${ident}: ${{self.short}}
1095
1096#include <cassert>
1097
1098#include "base/misc.hh"
1099#include "base/trace.hh"
1100#include "debug/ProtocolTrace.hh"
1101#include "debug/RubyGenerated.hh"
1102#include "mem/protocol/${ident}_Controller.hh"
1103#include "mem/protocol/${ident}_Event.hh"
1104#include "mem/protocol/${ident}_State.hh"
1105#include "mem/protocol/Types.hh"
1106#include "mem/ruby/common/Global.hh"
1107#include "mem/ruby/system/System.hh"
1108
1109#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1110
1111#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1112#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1113
1114TransitionResult
1115${ident}_Controller::doTransition(${ident}_Event event,
1116''')
1117        if self.EntryType != None:
1118            code('''
1119                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1120''')
1121        if self.TBEType != None:
1122            code('''
1123                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1124''')
1125        code('''
1126                                  const Address &addr)
1127{
1128''')
1129        if self.TBEType != None and self.EntryType != None:
1130            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1131        elif self.TBEType != None:
1132            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1133        elif self.EntryType != None:
1134            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1135        else:
1136            code('${ident}_State state = getState(addr);')
1137
1138        code('''
1139    ${ident}_State next_state = state;
1140
1141    DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1142            *this, g_system_ptr->getTime(), ${ident}_State_to_string(state),
1143            ${ident}_Event_to_string(event), addr);
1144
1145    TransitionResult result =
1146''')
1147        if self.TBEType != None and self.EntryType != None:
1148            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1149        elif self.TBEType != None:
1150            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1151        elif self.EntryType != None:
1152            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1153        else:
1154            code('doTransitionWorker(event, state, next_state, addr);')
1155
1156        code('''
1157    if (result == TransitionResult_Valid) {
1158        DPRINTF(RubyGenerated, "next_state: %s\\n",
1159                ${ident}_State_to_string(next_state));
1160        m_profiler.countTransition(state, event);
1161        DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1162                 curTick(), m_version, "${ident}",
1163                 ${ident}_Event_to_string(event),
1164                 ${ident}_State_to_string(state),
1165                 ${ident}_State_to_string(next_state),
1166                 addr, GET_TRANSITION_COMMENT());
1167
1168        CLEAR_TRANSITION_COMMENT();
1169''')
1170        if self.TBEType != None and self.EntryType != None:
1171            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1172            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1173        elif self.TBEType != None:
1174            code('setState(m_tbe_ptr, addr, next_state);')
1175            code('setAccessPermission(addr, next_state);')
1176        elif self.EntryType != None:
1177            code('setState(m_cache_entry_ptr, addr, next_state);')
1178            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1179        else:
1180            code('setState(addr, next_state);')
1181            code('setAccessPermission(addr, next_state);')
1182
1183        code('''
1184    } else if (result == TransitionResult_ResourceStall) {
1185        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1186                 curTick(), m_version, "${ident}",
1187                 ${ident}_Event_to_string(event),
1188                 ${ident}_State_to_string(state),
1189                 ${ident}_State_to_string(next_state),
1190                 addr, "Resource Stall");
1191    } else if (result == TransitionResult_ProtocolStall) {
1192        DPRINTF(RubyGenerated, "stalling\\n");
1193        DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1194                 curTick(), m_version, "${ident}",
1195                 ${ident}_Event_to_string(event),
1196                 ${ident}_State_to_string(state),
1197                 ${ident}_State_to_string(next_state),
1198                 addr, "Protocol Stall");
1199    }
1200
1201    return result;
1202}
1203
1204TransitionResult
1205${ident}_Controller::doTransitionWorker(${ident}_Event event,
1206                                        ${ident}_State state,
1207                                        ${ident}_State& next_state,
1208''')
1209
1210        if self.TBEType != None:
1211            code('''
1212                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1213''')
1214        if self.EntryType != None:
1215                  code('''
1216                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1217''')
1218        code('''
1219                                        const Address& addr)
1220{
1221    switch(HASH_FUN(state, event)) {
1222''')
1223
1224        # This map will allow suppress generating duplicate code
1225        cases = orderdict()
1226
1227        for trans in self.transitions:
1228            case_string = "%s_State_%s, %s_Event_%s" % \
1229                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1230
1231            case = self.symtab.codeFormatter()
1232            # Only set next_state if it changes
1233            if trans.state != trans.nextState:
1234                ns_ident = trans.nextState.ident
1235                case('next_state = ${ident}_State_${ns_ident};')
1236
1237            actions = trans.actions
1238            request_types = trans.request_types
1239
1240            # Check for resources
1241            case_sorter = []
1242            res = trans.resources
1243            for key,val in res.iteritems():
1244                if key.type.ident != "DNUCAStopTable":
1245                    val = '''
1246if (!%s.areNSlotsAvailable(%s))
1247    return TransitionResult_ResourceStall;
1248''' % (key.code, val)
1249                case_sorter.append(val)
1250
1251            # Check all of the request_types for resource constraints
1252            for request_type in request_types:
1253                val = '''
1254if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1255    return TransitionResult_ResourceStall;
1256}
1257''' % (self.ident, request_type.ident)
1258                case_sorter.append(val)
1259
1260            # Emit the code sequences in a sorted order.  This makes the
1261            # output deterministic (without this the output order can vary
1262            # since Map's keys() on a vector of pointers is not deterministic
1263            for c in sorted(case_sorter):
1264                case("$c")
1265
1266            # Record access types for this transition
1267            for request_type in request_types:
1268                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1269
1270            # Figure out if we stall
1271            stall = False
1272            for action in actions:
1273                if action.ident == "z_stall":
1274                    stall = True
1275                    break
1276
1277            if stall:
1278                case('return TransitionResult_ProtocolStall;')
1279            else:
1280                if self.TBEType != None and self.EntryType != None:
1281                    for action in actions:
1282                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1283                elif self.TBEType != None:
1284                    for action in actions:
1285                        case('${{action.ident}}(m_tbe_ptr, addr);')
1286                elif self.EntryType != None:
1287                    for action in actions:
1288                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1289                else:
1290                    for action in actions:
1291                        case('${{action.ident}}(addr);')
1292                case('return TransitionResult_Valid;')
1293
1294            case = str(case)
1295
1296            # Look to see if this transition code is unique.
1297            if case not in cases:
1298                cases[case] = []
1299
1300            cases[case].append(case_string)
1301
1302        # Walk through all of the unique code blocks and spit out the
1303        # corresponding case statement elements
1304        for case,transitions in cases.iteritems():
1305            # Iterative over all the multiple transitions that share
1306            # the same code
1307            for trans in transitions:
1308                code('  case HASH_FUN($trans):')
1309            code('    $case')
1310
1311        code('''
1312      default:
1313        fatal("Invalid transition\\n"
1314              "%s time: %d addr: %s event: %s state: %s\\n",
1315              name(), g_system_ptr->getTime(), addr, event, state);
1316    }
1317    return TransitionResult_Valid;
1318}
1319''')
1320        code.write(path, "%s_Transitions.cc" % self.ident)
1321
1322    def printProfileDumperHH(self, path):
1323        code = self.symtab.codeFormatter()
1324        ident = self.ident
1325
1326        code('''
1327// Auto generated C++ code started by $__file__:$__line__
1328// ${ident}: ${{self.short}}
1329
1330#ifndef __${ident}_PROFILE_DUMPER_HH__
1331#define __${ident}_PROFILE_DUMPER_HH__
1332
1333#include <cassert>
1334#include <iostream>
1335#include <vector>
1336
1337#include "${ident}_Event.hh"
1338#include "${ident}_Profiler.hh"
1339
1340typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1341
1342class ${ident}_ProfileDumper
1343{
1344  public:
1345    ${ident}_ProfileDumper();
1346    void registerProfiler(${ident}_Profiler* profiler);
1347    void dumpStats(std::ostream& out) const;
1348
1349  private:
1350    ${ident}_profilers m_profilers;
1351};
1352
1353#endif // __${ident}_PROFILE_DUMPER_HH__
1354''')
1355        code.write(path, "%s_ProfileDumper.hh" % self.ident)
1356
1357    def printProfileDumperCC(self, path):
1358        code = self.symtab.codeFormatter()
1359        ident = self.ident
1360
1361        code('''
1362// Auto generated C++ code started by $__file__:$__line__
1363// ${ident}: ${{self.short}}
1364
1365#include "mem/protocol/${ident}_ProfileDumper.hh"
1366
1367${ident}_ProfileDumper::${ident}_ProfileDumper()
1368{
1369}
1370
1371void
1372${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1373{
1374    m_profilers.push_back(profiler);
1375}
1376
1377void
1378${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1379{
1380    out << " --- ${ident} ---\\n";
1381    out << " - Event Counts -\\n";
1382    for (${ident}_Event event = ${ident}_Event_FIRST;
1383         event < ${ident}_Event_NUM;
1384         ++event) {
1385        out << (${ident}_Event) event << " [";
1386        uint64 total = 0;
1387        for (int i = 0; i < m_profilers.size(); i++) {
1388             out << m_profilers[i]->getEventCount(event) << " ";
1389             total += m_profilers[i]->getEventCount(event);
1390        }
1391        out << "] " << total << "\\n";
1392    }
1393    out << "\\n";
1394    out << " - Transitions -\\n";
1395    for (${ident}_State state = ${ident}_State_FIRST;
1396         state < ${ident}_State_NUM;
1397         ++state) {
1398        for (${ident}_Event event = ${ident}_Event_FIRST;
1399             event < ${ident}_Event_NUM;
1400             ++event) {
1401            if (m_profilers[0]->isPossible(state, event)) {
1402                out << (${ident}_State) state << "  "
1403                    << (${ident}_Event) event << " [";
1404                uint64 total = 0;
1405                for (int i = 0; i < m_profilers.size(); i++) {
1406                     out << m_profilers[i]->getTransitionCount(state, event) << " ";
1407                     total += m_profilers[i]->getTransitionCount(state, event);
1408                }
1409                out << "] " << total << "\\n";
1410            }
1411        }
1412        out << "\\n";
1413    }
1414}
1415''')
1416        code.write(path, "%s_ProfileDumper.cc" % self.ident)
1417
1418    def printProfilerHH(self, path):
1419        code = self.symtab.codeFormatter()
1420        ident = self.ident
1421
1422        code('''
1423// Auto generated C++ code started by $__file__:$__line__
1424// ${ident}: ${{self.short}}
1425
1426#ifndef __${ident}_PROFILER_HH__
1427#define __${ident}_PROFILER_HH__
1428
1429#include <cassert>
1430#include <iostream>
1431
1432#include "mem/protocol/${ident}_Event.hh"
1433#include "mem/protocol/${ident}_State.hh"
1434#include "mem/ruby/common/TypeDefines.hh"
1435
1436class ${ident}_Profiler
1437{
1438  public:
1439    ${ident}_Profiler();
1440    void setVersion(int version);
1441    void countTransition(${ident}_State state, ${ident}_Event event);
1442    void possibleTransition(${ident}_State state, ${ident}_Event event);
1443    uint64 getEventCount(${ident}_Event event);
1444    bool isPossible(${ident}_State state, ${ident}_Event event);
1445    uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1446    void clearStats();
1447
1448  private:
1449    int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1450    int m_event_counters[${ident}_Event_NUM];
1451    bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1452    int m_version;
1453};
1454
1455#endif // __${ident}_PROFILER_HH__
1456''')
1457        code.write(path, "%s_Profiler.hh" % self.ident)
1458
1459    def printProfilerCC(self, path):
1460        code = self.symtab.codeFormatter()
1461        ident = self.ident
1462
1463        code('''
1464// Auto generated C++ code started by $__file__:$__line__
1465// ${ident}: ${{self.short}}
1466
1467#include <cassert>
1468
1469#include "mem/protocol/${ident}_Profiler.hh"
1470
1471${ident}_Profiler::${ident}_Profiler()
1472{
1473    for (int state = 0; state < ${ident}_State_NUM; state++) {
1474        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1475            m_possible[state][event] = false;
1476            m_counters[state][event] = 0;
1477        }
1478    }
1479    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1480        m_event_counters[event] = 0;
1481    }
1482}
1483
1484void
1485${ident}_Profiler::setVersion(int version)
1486{
1487    m_version = version;
1488}
1489
1490void
1491${ident}_Profiler::clearStats()
1492{
1493    for (int state = 0; state < ${ident}_State_NUM; state++) {
1494        for (int event = 0; event < ${ident}_Event_NUM; event++) {
1495            m_counters[state][event] = 0;
1496        }
1497    }
1498
1499    for (int event = 0; event < ${ident}_Event_NUM; event++) {
1500        m_event_counters[event] = 0;
1501    }
1502}
1503void
1504${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1505{
1506    assert(m_possible[state][event]);
1507    m_counters[state][event]++;
1508    m_event_counters[event]++;
1509}
1510void
1511${ident}_Profiler::possibleTransition(${ident}_State state,
1512                                      ${ident}_Event event)
1513{
1514    m_possible[state][event] = true;
1515}
1516
1517uint64
1518${ident}_Profiler::getEventCount(${ident}_Event event)
1519{
1520    return m_event_counters[event];
1521}
1522
1523bool
1524${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1525{
1526    return m_possible[state][event];
1527}
1528
1529uint64
1530${ident}_Profiler::getTransitionCount(${ident}_State state,
1531                                      ${ident}_Event event)
1532{
1533    return m_counters[state][event];
1534}
1535
1536''')
1537        code.write(path, "%s_Profiler.cc" % self.ident)
1538
1539    # **************************
1540    # ******* HTML Files *******
1541    # **************************
1542    def frameRef(self, click_href, click_target, over_href, over_num, text):
1543        code = self.symtab.codeFormatter(fix_newlines=False)
1544        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1545    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1546        parent.frames[$over_num].location='$over_href'
1547    }\">
1548    ${{html.formatShorthand(text)}}
1549    </A>""")
1550        return str(code)
1551
1552    def writeHTMLFiles(self, path):
1553        # Create table with no row hilighted
1554        self.printHTMLTransitions(path, None)
1555
1556        # Generate transition tables
1557        for state in self.states.itervalues():
1558            self.printHTMLTransitions(path, state)
1559
1560        # Generate action descriptions
1561        for action in self.actions.itervalues():
1562            name = "%s_action_%s.html" % (self.ident, action.ident)
1563            code = html.createSymbol(action, "Action")
1564            code.write(path, name)
1565
1566        # Generate state descriptions
1567        for state in self.states.itervalues():
1568            name = "%s_State_%s.html" % (self.ident, state.ident)
1569            code = html.createSymbol(state, "State")
1570            code.write(path, name)
1571
1572        # Generate event descriptions
1573        for event in self.events.itervalues():
1574            name = "%s_Event_%s.html" % (self.ident, event.ident)
1575            code = html.createSymbol(event, "Event")
1576            code.write(path, name)
1577
1578    def printHTMLTransitions(self, path, active_state):
1579        code = self.symtab.codeFormatter()
1580
1581        code('''
1582<HTML>
1583<BODY link="blue" vlink="blue">
1584
1585<H1 align="center">${{html.formatShorthand(self.short)}}:
1586''')
1587        code.indent()
1588        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1589            mid = machine.ident
1590            if i != 0:
1591                extra = " - "
1592            else:
1593                extra = ""
1594            if machine == self:
1595                code('$extra$mid')
1596            else:
1597                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1598        code.dedent()
1599
1600        code("""
1601</H1>
1602
1603<TABLE border=1>
1604<TR>
1605  <TH> </TH>
1606""")
1607
1608        for event in self.events.itervalues():
1609            href = "%s_Event_%s.html" % (self.ident, event.ident)
1610            ref = self.frameRef(href, "Status", href, "1", event.short)
1611            code('<TH bgcolor=white>$ref</TH>')
1612
1613        code('</TR>')
1614        # -- Body of table
1615        for state in self.states.itervalues():
1616            # -- Each row
1617            if state == active_state:
1618                color = "yellow"
1619            else:
1620                color = "white"
1621
1622            click = "%s_table_%s.html" % (self.ident, state.ident)
1623            over = "%s_State_%s.html" % (self.ident, state.ident)
1624            text = html.formatShorthand(state.short)
1625            ref = self.frameRef(click, "Table", over, "1", state.short)
1626            code('''
1627<TR>
1628  <TH bgcolor=$color>$ref</TH>
1629''')
1630
1631            # -- One column for each event
1632            for event in self.events.itervalues():
1633                trans = self.table.get((state,event), None)
1634                if trans is None:
1635                    # This is the no transition case
1636                    if state == active_state:
1637                        color = "#C0C000"
1638                    else:
1639                        color = "lightgrey"
1640
1641                    code('<TD bgcolor=$color>&nbsp;</TD>')
1642                    continue
1643
1644                next = trans.nextState
1645                stall_action = False
1646
1647                # -- Get the actions
1648                for action in trans.actions:
1649                    if action.ident == "z_stall" or \
1650                       action.ident == "zz_recycleMandatoryQueue":
1651                        stall_action = True
1652
1653                # -- Print out "actions/next-state"
1654                if stall_action:
1655                    if state == active_state:
1656                        color = "#C0C000"
1657                    else:
1658                        color = "lightgrey"
1659
1660                elif active_state and next.ident == active_state.ident:
1661                    color = "aqua"
1662                elif state == active_state:
1663                    color = "yellow"
1664                else:
1665                    color = "white"
1666
1667                code('<TD bgcolor=$color>')
1668                for action in trans.actions:
1669                    href = "%s_action_%s.html" % (self.ident, action.ident)
1670                    ref = self.frameRef(href, "Status", href, "1",
1671                                        action.short)
1672                    code('  $ref')
1673                if next != state:
1674                    if trans.actions:
1675                        code('/')
1676                    click = "%s_table_%s.html" % (self.ident, next.ident)
1677                    over = "%s_State_%s.html" % (self.ident, next.ident)
1678                    ref = self.frameRef(click, "Table", over, "1", next.short)
1679                    code("$ref")
1680                code("</TD>")
1681
1682            # -- Each row
1683            if state == active_state:
1684                color = "yellow"
1685            else:
1686                color = "white"
1687
1688            click = "%s_table_%s.html" % (self.ident, state.ident)
1689            over = "%s_State_%s.html" % (self.ident, state.ident)
1690            ref = self.frameRef(click, "Table", over, "1", state.short)
1691            code('''
1692  <TH bgcolor=$color>$ref</TH>
1693</TR>
1694''')
1695        code('''
1696<!- Column footer->
1697<TR>
1698  <TH> </TH>
1699''')
1700
1701        for event in self.events.itervalues():
1702            href = "%s_Event_%s.html" % (self.ident, event.ident)
1703            ref = self.frameRef(href, "Status", href, "1", event.short)
1704            code('<TH bgcolor=white>$ref</TH>')
1705        code('''
1706</TR>
1707</TABLE>
1708</BODY></HTML>
1709''')
1710
1711
1712        if active_state:
1713            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1714        else:
1715            name = "%s_table.html" % self.ident
1716        code.write(path, name)
1717
1718__all__ = [ "StateMachine" ]
1719