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