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