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