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