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