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