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