StateMachine.py revision 11118
16928SBrad.Beckmann@amd.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
26928SBrad.Beckmann@amd.com# Copyright (c) 2009 The Hewlett-Packard Development Company
36928SBrad.Beckmann@amd.com# Copyright (c) 2013 Advanced Micro Devices, Inc.
46928SBrad.Beckmann@amd.com# All rights reserved.
56928SBrad.Beckmann@amd.com#
66928SBrad.Beckmann@amd.com# Redistribution and use in source and binary forms, with or without
76928SBrad.Beckmann@amd.com# modification, are permitted provided that the following conditions are
86928SBrad.Beckmann@amd.com# met: redistributions of source code must retain the above copyright
96928SBrad.Beckmann@amd.com# notice, this list of conditions and the following disclaimer;
106928SBrad.Beckmann@amd.com# redistributions in binary form must reproduce the above copyright
116928SBrad.Beckmann@amd.com# notice, this list of conditions and the following disclaimer in the
126928SBrad.Beckmann@amd.com# documentation and/or other materials provided with the distribution;
136928SBrad.Beckmann@amd.com# neither the name of the copyright holders nor the names of its
146928SBrad.Beckmann@amd.com# contributors may be used to endorse or promote products derived from
156928SBrad.Beckmann@amd.com# this software without specific prior written permission.
166928SBrad.Beckmann@amd.com#
176928SBrad.Beckmann@amd.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186928SBrad.Beckmann@amd.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196928SBrad.Beckmann@amd.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206928SBrad.Beckmann@amd.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216928SBrad.Beckmann@amd.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226928SBrad.Beckmann@amd.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236928SBrad.Beckmann@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246928SBrad.Beckmann@amd.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256928SBrad.Beckmann@amd.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266928SBrad.Beckmann@amd.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276928SBrad.Beckmann@amd.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286928SBrad.Beckmann@amd.com
296928SBrad.Beckmann@amd.comfrom m5.util import orderdict
306928SBrad.Beckmann@amd.com
316928SBrad.Beckmann@amd.comfrom slicc.symbols.Symbol import Symbol
326928SBrad.Beckmann@amd.comfrom slicc.symbols.Var import Var
336928SBrad.Beckmann@amd.comimport slicc.generate.html as html
346928SBrad.Beckmann@amd.comimport re
356928SBrad.Beckmann@amd.com
366928SBrad.Beckmann@amd.compython_class_map = {
3711670Sandreas.hansson@arm.com                    "int": "Int",
386928SBrad.Beckmann@amd.com                    "uint32_t" : "UInt32",
3911670Sandreas.hansson@arm.com                    "std::string": "String",
4011682Sandreas.hansson@arm.com                    "bool": "Bool",
416928SBrad.Beckmann@amd.com                    "CacheMemory": "RubyCache",
426928SBrad.Beckmann@amd.com                    "WireBuffer": "RubyWireBuffer",
438920Snilay@cs.wisc.edu                    "Sequencer": "RubySequencer",
446928SBrad.Beckmann@amd.com                    "DirectoryMemory": "RubyDirectoryMemory",
457570SBrad.Beckmann@amd.com                    "MemoryControl": "MemoryControl",
467570SBrad.Beckmann@amd.com                    "MessageBuffer": "MessageBuffer",
476928SBrad.Beckmann@amd.com                    "DMASequencer": "DMASequencer",
486928SBrad.Beckmann@amd.com                    "Prefetcher":"Prefetcher",
496928SBrad.Beckmann@amd.com                    "Cycles":"Cycles",
506928SBrad.Beckmann@amd.com                   }
517570SBrad.Beckmann@amd.com
527570SBrad.Beckmann@amd.comclass StateMachine(Symbol):
537570SBrad.Beckmann@amd.com    def __init__(self, symtab, ident, location, pairs, config_parameters):
547570SBrad.Beckmann@amd.com        super(StateMachine, self).__init__(symtab, ident, location, pairs)
557570SBrad.Beckmann@amd.com        self.table = None
567570SBrad.Beckmann@amd.com
577570SBrad.Beckmann@amd.com        # Data members in the State Machine that have been declared before
587570SBrad.Beckmann@amd.com        # the opening brace '{'  of the machine.  Note that these along with
597570SBrad.Beckmann@amd.com        # the members in self.objects form the entire set of data members.
607570SBrad.Beckmann@amd.com        self.config_parameters = config_parameters
617570SBrad.Beckmann@amd.com
629841Snilay@cs.wisc.edu        self.prefetchers = []
637570SBrad.Beckmann@amd.com
648933SBrad.Beckmann@amd.com        for param in config_parameters:
658933SBrad.Beckmann@amd.com            if param.pointer:
668933SBrad.Beckmann@amd.com                var = Var(symtab, param.ident, location, param.type_ast.type,
678933SBrad.Beckmann@amd.com                          "(*m_%s_ptr)" % param.ident, {}, self)
688933SBrad.Beckmann@amd.com            else:
697570SBrad.Beckmann@amd.com                var = Var(symtab, param.ident, location, param.type_ast.type,
706928SBrad.Beckmann@amd.com                          "m_%s" % param.ident, {}, self)
716928SBrad.Beckmann@amd.com
728933SBrad.Beckmann@amd.com            self.symtab.registerSym(param.ident, var)
738940SBrad.Beckmann@amd.com
746928SBrad.Beckmann@amd.com            if str(param.type_ast.type) == "Prefetcher":
7510300Scastilloe@unican.es                self.prefetchers.append(var)
7610300Scastilloe@unican.es
7710524Snilay@cs.wisc.edu        self.states = orderdict()
7810300Scastilloe@unican.es        self.events = orderdict()
799827Sakash.bagdia@arm.com        self.actions = orderdict()
809827Sakash.bagdia@arm.com        self.request_types = orderdict()
819827Sakash.bagdia@arm.com        self.transitions = []
829827Sakash.bagdia@arm.com        self.in_ports = []
836928SBrad.Beckmann@amd.com        self.functions = []
849826Sandreas.hansson@arm.com
859826Sandreas.hansson@arm.com        # Data members in the State Machine that have been declared inside
8610519Snilay@cs.wisc.edu        # the {} machine.  Note that these along with the config params
876928SBrad.Beckmann@amd.com        # form the entire set of data members of the machine.
889793Sakash.bagdia@arm.com        self.objects = []
899827Sakash.bagdia@arm.com        self.TBEType   = None
909827Sakash.bagdia@arm.com        self.EntryType = None
919793Sakash.bagdia@arm.com        self.debug_flags = set()
9210120Snilay@cs.wisc.edu        self.debug_flags.add('RubyGenerated')
936928SBrad.Beckmann@amd.com        self.debug_flags.add('RubySlicc')
9411267SBrad.Beckmann@amd.com
9511267SBrad.Beckmann@amd.com    def __repr__(self):
966928SBrad.Beckmann@amd.com        return "[StateMachine: %s]" % self.ident
976928SBrad.Beckmann@amd.com
986928SBrad.Beckmann@amd.com    def addState(self, state):
996928SBrad.Beckmann@amd.com        assert self.table is None
1006928SBrad.Beckmann@amd.com        self.states[state.ident] = state
1016928SBrad.Beckmann@amd.com
10210120Snilay@cs.wisc.edu    def addEvent(self, event):
1036928SBrad.Beckmann@amd.com        assert self.table is None
1048940SBrad.Beckmann@amd.com        self.events[event.ident] = event
1056928SBrad.Beckmann@amd.com
10611267SBrad.Beckmann@amd.com    def addAction(self, action):
10711267SBrad.Beckmann@amd.com        assert self.table is None
10811267SBrad.Beckmann@amd.com
10911267SBrad.Beckmann@amd.com        # Check for duplicate action
11011267SBrad.Beckmann@amd.com        for other in self.actions.itervalues():
11111267SBrad.Beckmann@amd.com            if action.ident == other.ident:
11211267SBrad.Beckmann@amd.com                action.warning("Duplicate action definition: %s" % action.ident)
11311267SBrad.Beckmann@amd.com                action.error("Duplicate action definition: %s" % action.ident)
11411267SBrad.Beckmann@amd.com            if action.short == other.short:
1156928SBrad.Beckmann@amd.com                other.warning("Duplicate action shorthand: %s" % other.ident)
1166928SBrad.Beckmann@amd.com                other.warning("    shorthand = %s" % other.short)
1176928SBrad.Beckmann@amd.com                action.warning("Duplicate action shorthand: %s" % action.ident)
1186928SBrad.Beckmann@amd.com                action.error("    shorthand = %s" % action.short)
1196928SBrad.Beckmann@amd.com
1206928SBrad.Beckmann@amd.com        self.actions[action.ident] = action
1216928SBrad.Beckmann@amd.com
1226928SBrad.Beckmann@amd.com    def addDebugFlag(self, flag):
1236928SBrad.Beckmann@amd.com        self.debug_flags.add(flag)
1246928SBrad.Beckmann@amd.com
1256928SBrad.Beckmann@amd.com    def addRequestType(self, request_type):
1268801Sgblack@eecs.umich.edu        assert self.table is None
1276928SBrad.Beckmann@amd.com        self.request_types[request_type.ident] = request_type
1286928SBrad.Beckmann@amd.com
1296928SBrad.Beckmann@amd.com    def addTransition(self, trans):
1306928SBrad.Beckmann@amd.com        assert self.table is None
131        self.transitions.append(trans)
132
133    def addInPort(self, var):
134        self.in_ports.append(var)
135
136    def addFunc(self, func):
137        # register func in the symbol table
138        self.symtab.registerSym(str(func), func)
139        self.functions.append(func)
140
141    def addObject(self, obj):
142        self.symtab.registerSym(str(obj), obj)
143        self.objects.append(obj)
144
145    def addType(self, type):
146        type_ident = '%s' % type.c_ident
147
148        if type_ident == "%s_TBE" %self.ident:
149            if self.TBEType != None:
150                self.error("Multiple Transaction Buffer types in a " \
151                           "single machine.");
152            self.TBEType = type
153
154        elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
155            if "main" in type and "false" == type["main"].lower():
156                pass # this isn't the EntryType
157            else:
158                if self.EntryType != None:
159                    self.error("Multiple AbstractCacheEntry types in a " \
160                               "single machine.");
161                self.EntryType = type
162
163    # Needs to be called before accessing the table
164    def buildTable(self):
165        assert self.table is None
166
167        table = {}
168
169        for trans in self.transitions:
170            # Track which actions we touch so we know if we use them
171            # all -- really this should be done for all symbols as
172            # part of the symbol table, then only trigger it for
173            # Actions, States, Events, etc.
174
175            for action in trans.actions:
176                action.used = True
177
178            index = (trans.state, trans.event)
179            if index in table:
180                table[index].warning("Duplicate transition: %s" % table[index])
181                trans.error("Duplicate transition: %s" % trans)
182            table[index] = trans
183
184        # Look at all actions to make sure we used them all
185        for action in self.actions.itervalues():
186            if not action.used:
187                error_msg = "Unused action: %s" % action.ident
188                if "desc" in action:
189                    error_msg += ", "  + action.desc
190                action.warning(error_msg)
191        self.table = table
192
193    # determine the port->msg buffer mappings
194    def getBufferMaps(self, ident):
195        msg_bufs = []
196        port_to_buf_map = {}
197        in_msg_bufs = {}
198        for port in self.in_ports:
199            buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name
200            msg_bufs.append(buf_name)
201            port_to_buf_map[port] = msg_bufs.index(buf_name)
202            if buf_name not in in_msg_bufs:
203                in_msg_bufs[buf_name] = [port]
204            else:
205                in_msg_bufs[buf_name].append(port)
206        return port_to_buf_map, in_msg_bufs, msg_bufs
207
208    def writeCodeFiles(self, path, includes):
209        self.printControllerPython(path)
210        self.printControllerHH(path)
211        self.printControllerCC(path, includes)
212        self.printCSwitch(path)
213        self.printCWakeup(path, includes)
214
215    def printControllerPython(self, path):
216        code = self.symtab.codeFormatter()
217        ident = self.ident
218
219        py_ident = "%s_Controller" % ident
220        c_ident = "%s_Controller" % self.ident
221
222        code('''
223from m5.params import *
224from m5.SimObject import SimObject
225from Controller import RubyController
226
227class $py_ident(RubyController):
228    type = '$py_ident'
229    cxx_header = 'mem/protocol/${c_ident}.hh'
230''')
231        code.indent()
232        for param in self.config_parameters:
233            dflt_str = ''
234
235            if param.rvalue is not None:
236                dflt_str = str(param.rvalue.inline()) + ', '
237
238            if python_class_map.has_key(param.type_ast.type.c_ident):
239                python_type = python_class_map[param.type_ast.type.c_ident]
240                code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")')
241
242            else:
243                self.error("Unknown c++ to python class conversion for c++ " \
244                           "type: '%s'. Please update the python_class_map " \
245                           "in StateMachine.py", param.type_ast.type.c_ident)
246
247        code.dedent()
248        code.write(path, '%s.py' % py_ident)
249
250
251    def printControllerHH(self, path):
252        '''Output the method declarations for the class declaration'''
253        code = self.symtab.codeFormatter()
254        ident = self.ident
255        c_ident = "%s_Controller" % self.ident
256
257        code('''
258/** \\file $c_ident.hh
259 *
260 * Auto generated C++ code started by $__file__:$__line__
261 * Created by slicc definition of Module "${{self.short}}"
262 */
263
264#ifndef __${ident}_CONTROLLER_HH__
265#define __${ident}_CONTROLLER_HH__
266
267#include <iostream>
268#include <sstream>
269#include <string>
270
271#include "mem/protocol/TransitionResult.hh"
272#include "mem/protocol/Types.hh"
273#include "mem/ruby/common/Consumer.hh"
274#include "mem/ruby/slicc_interface/AbstractController.hh"
275#include "params/$c_ident.hh"
276
277''')
278
279        seen_types = set()
280        for var in self.objects:
281            if var.type.ident not in seen_types and not var.type.isPrimitive:
282                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
283                seen_types.add(var.type.ident)
284
285        # for adding information to the protocol debug trace
286        code('''
287extern std::stringstream ${ident}_transitionComment;
288
289class $c_ident : public AbstractController
290{
291  public:
292    typedef ${c_ident}Params Params;
293    $c_ident(const Params *p);
294    static int getNumControllers();
295    void init();
296
297    MessageBuffer *getMandatoryQueue() const;
298    MessageBuffer *getMemoryQueue() const;
299    void initNetQueues();
300
301    void print(std::ostream& out) const;
302    void wakeup();
303    void resetStats();
304    void regStats();
305    void collateStats();
306
307    void recordCacheTrace(int cntrl, CacheRecorder* tr);
308    Sequencer* getSequencer() const;
309
310    int functionalWriteBuffers(PacketPtr&);
311
312    void countTransition(${ident}_State state, ${ident}_Event event);
313    void possibleTransition(${ident}_State state, ${ident}_Event event);
314    uint64_t getEventCount(${ident}_Event event);
315    bool isPossible(${ident}_State state, ${ident}_Event event);
316    uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event);
317
318private:
319''')
320
321        code.indent()
322        # added by SS
323        for param in self.config_parameters:
324            if param.pointer:
325                code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
326            else:
327                code('${{param.type_ast.type}} m_${{param.ident}};')
328
329        code('''
330TransitionResult doTransition(${ident}_Event event,
331''')
332
333        if self.EntryType != None:
334            code('''
335                              ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
336''')
337        if self.TBEType != None:
338            code('''
339                              ${{self.TBEType.c_ident}}* m_tbe_ptr,
340''')
341
342        code('''
343                              Addr addr);
344
345TransitionResult doTransitionWorker(${ident}_Event event,
346                                    ${ident}_State state,
347                                    ${ident}_State& next_state,
348''')
349
350        if self.TBEType != None:
351            code('''
352                                    ${{self.TBEType.c_ident}}*& m_tbe_ptr,
353''')
354        if self.EntryType != None:
355            code('''
356                                    ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
357''')
358
359        code('''
360                                    Addr addr);
361
362int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
363int m_event_counters[${ident}_Event_NUM];
364bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
365
366static std::vector<Stats::Vector *> eventVec;
367static std::vector<std::vector<Stats::Vector *> > transVec;
368static int m_num_controllers;
369
370// Internal functions
371''')
372
373        for func in self.functions:
374            proto = func.prototype
375            if proto:
376                code('$proto')
377
378        if self.EntryType != None:
379            code('''
380
381// Set and Reset for cache_entry variable
382void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
383void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
384''')
385
386        if self.TBEType != None:
387            code('''
388
389// Set and Reset for tbe variable
390void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
391void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
392''')
393
394        # Prototype the actions that the controller can take
395        code('''
396
397// Actions
398''')
399        if self.TBEType != None and self.EntryType != None:
400            for action in self.actions.itervalues():
401                code('/** \\brief ${{action.desc}} */')
402                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
403                     'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
404                     'm_cache_entry_ptr, Addr addr);')
405        elif self.TBEType != None:
406            for action in self.actions.itervalues():
407                code('/** \\brief ${{action.desc}} */')
408                code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
409                     'm_tbe_ptr, Addr addr);')
410        elif self.EntryType != None:
411            for action in self.actions.itervalues():
412                code('/** \\brief ${{action.desc}} */')
413                code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
414                     'm_cache_entry_ptr, Addr addr);')
415        else:
416            for action in self.actions.itervalues():
417                code('/** \\brief ${{action.desc}} */')
418                code('void ${{action.ident}}(Addr addr);')
419
420        # the controller internal variables
421        code('''
422
423// Objects
424''')
425        for var in self.objects:
426            th = var.get("template", "")
427            code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;')
428
429        code.dedent()
430        code('};')
431        code('#endif // __${ident}_CONTROLLER_H__')
432        code.write(path, '%s.hh' % c_ident)
433
434    def printControllerCC(self, path, includes):
435        '''Output the actions for performing the actions'''
436
437        code = self.symtab.codeFormatter()
438        ident = self.ident
439        c_ident = "%s_Controller" % self.ident
440
441        code('''
442/** \\file $c_ident.cc
443 *
444 * Auto generated C++ code started by $__file__:$__line__
445 * Created by slicc definition of Module "${{self.short}}"
446 */
447
448#include <sys/types.h>
449#include <unistd.h>
450
451#include <cassert>
452#include <sstream>
453#include <string>
454#include <typeinfo>
455
456#include "base/compiler.hh"
457#include "base/cprintf.hh"
458
459''')
460        for f in self.debug_flags:
461            code('#include "debug/${{f}}.hh"')
462        code('''
463#include "mem/protocol/${ident}_Controller.hh"
464#include "mem/protocol/${ident}_Event.hh"
465#include "mem/protocol/${ident}_State.hh"
466#include "mem/protocol/Types.hh"
467#include "mem/ruby/system/RubySystem.hh"
468
469''')
470        for include_path in includes:
471            code('#include "${{include_path}}"')
472
473        code('''
474
475using namespace std;
476''')
477
478        # include object classes
479        seen_types = set()
480        for var in self.objects:
481            if var.type.ident not in seen_types and not var.type.isPrimitive:
482                code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
483            seen_types.add(var.type.ident)
484
485        num_in_ports = len(self.in_ports)
486
487        code('''
488$c_ident *
489${c_ident}Params::create()
490{
491    return new $c_ident(this);
492}
493
494int $c_ident::m_num_controllers = 0;
495std::vector<Stats::Vector *>  $c_ident::eventVec;
496std::vector<std::vector<Stats::Vector *> >  $c_ident::transVec;
497
498// for adding information to the protocol debug trace
499stringstream ${ident}_transitionComment;
500
501#ifndef NDEBUG
502#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
503#else
504#define APPEND_TRANSITION_COMMENT(str) do {} while (0)
505#endif
506
507/** \\brief constructor */
508$c_ident::$c_ident(const Params *p)
509    : AbstractController(p)
510{
511    m_machineID.type = MachineType_${ident};
512    m_machineID.num = m_version;
513    m_num_controllers++;
514
515    m_in_ports = $num_in_ports;
516''')
517        code.indent()
518
519        #
520        # After initializing the universal machine parameters, initialize the
521        # this machines config parameters.  Also if these configuration params
522        # include a sequencer, connect the it to the controller.
523        #
524        for param in self.config_parameters:
525            if param.pointer:
526                code('m_${{param.ident}}_ptr = p->${{param.ident}};')
527            else:
528                code('m_${{param.ident}} = p->${{param.ident}};')
529
530            if re.compile("sequencer").search(param.ident):
531                code('m_${{param.ident}}_ptr->setController(this);')
532
533        code('''
534
535for (int state = 0; state < ${ident}_State_NUM; state++) {
536    for (int event = 0; event < ${ident}_Event_NUM; event++) {
537        m_possible[state][event] = false;
538        m_counters[state][event] = 0;
539    }
540}
541for (int event = 0; event < ${ident}_Event_NUM; event++) {
542    m_event_counters[event] = 0;
543}
544''')
545        code.dedent()
546        code('''
547}
548
549void
550$c_ident::initNetQueues()
551{
552    MachineType machine_type = string_to_MachineType("${{self.ident}}");
553    int base M5_VAR_USED = MachineType_base_number(machine_type);
554
555''')
556        code.indent()
557
558        # set for maintaining the vnet, direction pairs already seen for this
559        # machine.  This map helps in implementing the check for avoiding
560        # multiple message buffers being mapped to the same vnet.
561        vnet_dir_set = set()
562
563        for var in self.config_parameters:
564            vid = "m_%s_ptr" % var.ident
565            if "network" in var:
566                vtype = var.type_ast.type
567                code('assert($vid != NULL);')
568
569                # Network port object
570                network = var["network"]
571
572                if "virtual_network" in var:
573                    vnet = var["virtual_network"]
574                    vnet_type = var["vnet_type"]
575
576                    assert (vnet, network) not in vnet_dir_set
577                    vnet_dir_set.add((vnet,network))
578
579                    code('''
580m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet,
581                                 "$vnet_type", $vid);
582''')
583                # Set Priority
584                if "rank" in var:
585                    code('$vid->setPriority(${{var["rank"]}})')
586
587        code.dedent()
588        code('''
589}
590
591void
592$c_ident::init()
593{
594    // initialize objects
595''')
596
597        code.indent()
598
599        for var in self.objects:
600            vtype = var.type
601            vid = "m_%s_ptr" % var.ident
602            if "network" not in var:
603                # Not a network port object
604                if "primitive" in vtype:
605                    code('$vid = new ${{vtype.c_ident}};')
606                    if "default" in var:
607                        code('(*$vid) = ${{var["default"]}};')
608                else:
609                    # Normal Object
610                    th = var.get("template", "")
611                    expr = "%s  = new %s%s" % (vid, vtype.c_ident, th)
612                    args = ""
613                    if "non_obj" not in vtype and not vtype.isEnumeration:
614                        args = var.get("constructor", "")
615
616                    code('$expr($args);')
617                    code('assert($vid != NULL);')
618
619                    if "default" in var:
620                        code('*$vid = ${{var["default"]}}; // Object default')
621                    elif "default" in vtype:
622                        comment = "Type %s default" % vtype.ident
623                        code('*$vid = ${{vtype["default"]}}; // $comment')
624
625        # Set the prefetchers
626        code()
627        for prefetcher in self.prefetchers:
628            code('${{prefetcher.code}}.setController(this);')
629
630        code()
631        for port in self.in_ports:
632            # Set the queue consumers
633            code('${{port.code}}.setConsumer(this);')
634
635        # Initialize the transition profiling
636        code()
637        for trans in self.transitions:
638            # Figure out if we stall
639            stall = False
640            for action in trans.actions:
641                if action.ident == "z_stall":
642                    stall = True
643
644            # Only possible if it is not a 'z' case
645            if not stall:
646                state = "%s_State_%s" % (self.ident, trans.state.ident)
647                event = "%s_Event_%s" % (self.ident, trans.event.ident)
648                code('possibleTransition($state, $event);')
649
650        code.dedent()
651        code('''
652    AbstractController::init();
653    resetStats();
654}
655''')
656
657        mq_ident = "NULL"
658        for port in self.in_ports:
659            if port.code.find("mandatoryQueue_ptr") >= 0:
660                mq_ident = "m_mandatoryQueue_ptr"
661
662        memq_ident = "NULL"
663        for port in self.in_ports:
664            if port.code.find("responseFromMemory_ptr") >= 0:
665                memq_ident = "m_responseFromMemory_ptr"
666
667        seq_ident = "NULL"
668        for param in self.config_parameters:
669            if param.ident == "sequencer":
670                assert(param.pointer)
671                seq_ident = "m_%s_ptr" % param.ident
672
673        code('''
674
675void
676$c_ident::regStats()
677{
678    AbstractController::regStats();
679
680    if (m_version == 0) {
681        for (${ident}_Event event = ${ident}_Event_FIRST;
682             event < ${ident}_Event_NUM; ++event) {
683            Stats::Vector *t = new Stats::Vector();
684            t->init(m_num_controllers);
685            t->name(params()->ruby_system->name() + ".${c_ident}." +
686                ${ident}_Event_to_string(event));
687            t->flags(Stats::pdf | Stats::total | Stats::oneline |
688                     Stats::nozero);
689
690            eventVec.push_back(t);
691        }
692
693        for (${ident}_State state = ${ident}_State_FIRST;
694             state < ${ident}_State_NUM; ++state) {
695
696            transVec.push_back(std::vector<Stats::Vector *>());
697
698            for (${ident}_Event event = ${ident}_Event_FIRST;
699                 event < ${ident}_Event_NUM; ++event) {
700
701                Stats::Vector *t = new Stats::Vector();
702                t->init(m_num_controllers);
703                t->name(params()->ruby_system->name() + ".${c_ident}." +
704                        ${ident}_State_to_string(state) +
705                        "." + ${ident}_Event_to_string(event));
706
707                t->flags(Stats::pdf | Stats::total | Stats::oneline |
708                         Stats::nozero);
709                transVec[state].push_back(t);
710            }
711        }
712    }
713}
714
715void
716$c_ident::collateStats()
717{
718    for (${ident}_Event event = ${ident}_Event_FIRST;
719         event < ${ident}_Event_NUM; ++event) {
720        for (unsigned int i = 0; i < m_num_controllers; ++i) {
721            RubySystem *rs = params()->ruby_system;
722            std::map<uint32_t, AbstractController *>::iterator it =
723                     rs->m_abstract_controls[MachineType_${ident}].find(i);
724            assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
725            (*eventVec[event])[i] =
726                (($c_ident *)(*it).second)->getEventCount(event);
727        }
728    }
729
730    for (${ident}_State state = ${ident}_State_FIRST;
731         state < ${ident}_State_NUM; ++state) {
732
733        for (${ident}_Event event = ${ident}_Event_FIRST;
734             event < ${ident}_Event_NUM; ++event) {
735
736            for (unsigned int i = 0; i < m_num_controllers; ++i) {
737                RubySystem *rs = params()->ruby_system;
738                std::map<uint32_t, AbstractController *>::iterator it =
739                         rs->m_abstract_controls[MachineType_${ident}].find(i);
740                assert(it != rs->m_abstract_controls[MachineType_${ident}].end());
741                (*transVec[state][event])[i] =
742                    (($c_ident *)(*it).second)->getTransitionCount(state, event);
743            }
744        }
745    }
746}
747
748void
749$c_ident::countTransition(${ident}_State state, ${ident}_Event event)
750{
751    assert(m_possible[state][event]);
752    m_counters[state][event]++;
753    m_event_counters[event]++;
754}
755void
756$c_ident::possibleTransition(${ident}_State state,
757                             ${ident}_Event event)
758{
759    m_possible[state][event] = true;
760}
761
762uint64_t
763$c_ident::getEventCount(${ident}_Event event)
764{
765    return m_event_counters[event];
766}
767
768bool
769$c_ident::isPossible(${ident}_State state, ${ident}_Event event)
770{
771    return m_possible[state][event];
772}
773
774uint64_t
775$c_ident::getTransitionCount(${ident}_State state,
776                             ${ident}_Event event)
777{
778    return m_counters[state][event];
779}
780
781int
782$c_ident::getNumControllers()
783{
784    return m_num_controllers;
785}
786
787MessageBuffer*
788$c_ident::getMandatoryQueue() const
789{
790    return $mq_ident;
791}
792
793MessageBuffer*
794$c_ident::getMemoryQueue() const
795{
796    return $memq_ident;
797}
798
799Sequencer*
800$c_ident::getSequencer() const
801{
802    return $seq_ident;
803}
804
805void
806$c_ident::print(ostream& out) const
807{
808    out << "[$c_ident " << m_version << "]";
809}
810
811void $c_ident::resetStats()
812{
813    for (int state = 0; state < ${ident}_State_NUM; state++) {
814        for (int event = 0; event < ${ident}_Event_NUM; event++) {
815            m_counters[state][event] = 0;
816        }
817    }
818
819    for (int event = 0; event < ${ident}_Event_NUM; event++) {
820        m_event_counters[event] = 0;
821    }
822
823    AbstractController::resetStats();
824}
825''')
826
827        if self.EntryType != None:
828            code('''
829
830// Set and Reset for cache_entry variable
831void
832$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
833{
834  m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
835}
836
837void
838$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
839{
840  m_cache_entry_ptr = 0;
841}
842''')
843
844        if self.TBEType != None:
845            code('''
846
847// Set and Reset for tbe variable
848void
849$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
850{
851  m_tbe_ptr = m_new_tbe;
852}
853
854void
855$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
856{
857  m_tbe_ptr = NULL;
858}
859''')
860
861        code('''
862
863void
864$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
865{
866''')
867        #
868        # Record cache contents for all associated caches.
869        #
870        code.indent()
871        for param in self.config_parameters:
872            if param.type_ast.type.ident == "CacheMemory":
873                assert(param.pointer)
874                code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
875
876        code.dedent()
877        code('''
878}
879
880// Actions
881''')
882        if self.TBEType != None and self.EntryType != None:
883            for action in self.actions.itervalues():
884                if "c_code" not in action:
885                 continue
886
887                code('''
888/** \\brief ${{action.desc}} */
889void
890$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
891{
892    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
893    try {
894       ${{action["c_code"]}}
895    } catch (const RejectException & e) {
896       fatal("Error in action ${{ident}}:${{action.ident}}: "
897             "executed a peek statement with the wrong message "
898             "type specified. ");
899    }
900}
901
902''')
903        elif self.TBEType != None:
904            for action in self.actions.itervalues():
905                if "c_code" not in action:
906                 continue
907
908                code('''
909/** \\brief ${{action.desc}} */
910void
911$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr)
912{
913    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
914    ${{action["c_code"]}}
915}
916
917''')
918        elif self.EntryType != None:
919            for action in self.actions.itervalues():
920                if "c_code" not in action:
921                 continue
922
923                code('''
924/** \\brief ${{action.desc}} */
925void
926$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr)
927{
928    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
929    ${{action["c_code"]}}
930}
931
932''')
933        else:
934            for action in self.actions.itervalues():
935                if "c_code" not in action:
936                 continue
937
938                code('''
939/** \\brief ${{action.desc}} */
940void
941$c_ident::${{action.ident}}(Addr addr)
942{
943    DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
944    ${{action["c_code"]}}
945}
946
947''')
948        for func in self.functions:
949            code(func.generateCode())
950
951        # Function for functional writes to messages buffered in the controller
952        code('''
953int
954$c_ident::functionalWriteBuffers(PacketPtr& pkt)
955{
956    int num_functional_writes = 0;
957''')
958        for var in self.objects:
959            vtype = var.type
960            if vtype.isBuffer:
961                vid = "m_%s_ptr" % var.ident
962                code('num_functional_writes += $vid->functionalWrite(pkt);')
963
964        for var in self.config_parameters:
965            vtype = var.type_ast.type
966            if vtype.isBuffer:
967                vid = "m_%s_ptr" % var.ident
968                code('num_functional_writes += $vid->functionalWrite(pkt);')
969
970        code('''
971    return num_functional_writes;
972}
973''')
974
975        code.write(path, "%s.cc" % c_ident)
976
977    def printCWakeup(self, path, includes):
978        '''Output the wakeup loop for the events'''
979
980        code = self.symtab.codeFormatter()
981        ident = self.ident
982
983        outputRequest_types = True
984        if len(self.request_types) == 0:
985            outputRequest_types = False
986
987        code('''
988// Auto generated C++ code started by $__file__:$__line__
989// ${ident}: ${{self.short}}
990
991#include <sys/types.h>
992#include <unistd.h>
993
994#include <cassert>
995#include <typeinfo>
996
997#include "base/misc.hh"
998
999''')
1000        for f in self.debug_flags:
1001            code('#include "debug/${{f}}.hh"')
1002        code('''
1003#include "mem/protocol/${ident}_Controller.hh"
1004#include "mem/protocol/${ident}_Event.hh"
1005#include "mem/protocol/${ident}_State.hh"
1006
1007''')
1008
1009        if outputRequest_types:
1010            code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1011
1012        code('''
1013#include "mem/protocol/Types.hh"
1014#include "mem/ruby/system/RubySystem.hh"
1015
1016''')
1017
1018
1019        for include_path in includes:
1020            code('#include "${{include_path}}"')
1021
1022        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1023
1024        code('''
1025
1026using namespace std;
1027
1028void
1029${ident}_Controller::wakeup()
1030{
1031    int counter = 0;
1032    while (true) {
1033        unsigned char rejected[${{len(msg_bufs)}}];
1034        memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}});
1035        // Some cases will put us into an infinite loop without this limit
1036        assert(counter <= m_transitions_per_cycle);
1037        if (counter == m_transitions_per_cycle) {
1038            // Count how often we are fully utilized
1039            m_fully_busy_cycles++;
1040
1041            // Wakeup in another cycle and try again
1042            scheduleEvent(Cycles(1));
1043            break;
1044        }
1045''')
1046
1047        code.indent()
1048        code.indent()
1049
1050        # InPorts
1051        #
1052        for port in self.in_ports:
1053            code.indent()
1054            code('// ${ident}InPort $port')
1055            if port.pairs.has_key("rank"):
1056                code('m_cur_in_port = ${{port.pairs["rank"]}};')
1057            else:
1058                code('m_cur_in_port = 0;')
1059            if port in port_to_buf_map:
1060                code('try {')
1061                code.indent()
1062            code('${{port["c_code_in_port"]}}')
1063
1064            if port in port_to_buf_map:
1065                code.dedent()
1066                code('''
1067            } catch (const RejectException & e) {
1068                rejected[${{port_to_buf_map[port]}}]++;
1069            }
1070''')
1071            code.dedent()
1072            code('')
1073
1074        code.dedent()
1075        code.dedent()
1076        code('''
1077        // If we got this far, we have nothing left todo or something went
1078        // wrong''')
1079        for buf_name, ports in in_msg_bufs.items():
1080            if len(ports) > 1:
1081                # only produce checks when a buffer is shared by multiple ports
1082                code('''
1083        if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}})
1084        {
1085            // no port claimed the message on the top of this buffer
1086            panic("Runtime Error at Ruby Time: %d. "
1087                  "All ports rejected a message. "
1088                  "You are probably sending a message type to this controller "
1089                  "over a virtual network that do not define an in_port for "
1090                  "the incoming message type.\\n",
1091                  Cycles(1));
1092        }
1093''')
1094        code('''
1095        break;
1096    }
1097}
1098''')
1099
1100        code.write(path, "%s_Wakeup.cc" % self.ident)
1101
1102    def printCSwitch(self, path):
1103        '''Output switch statement for transition table'''
1104
1105        code = self.symtab.codeFormatter()
1106        ident = self.ident
1107
1108        code('''
1109// Auto generated C++ code started by $__file__:$__line__
1110// ${ident}: ${{self.short}}
1111
1112#include <cassert>
1113
1114#include "base/misc.hh"
1115#include "base/trace.hh"
1116#include "debug/ProtocolTrace.hh"
1117#include "debug/RubyGenerated.hh"
1118#include "mem/protocol/${ident}_Controller.hh"
1119#include "mem/protocol/${ident}_Event.hh"
1120#include "mem/protocol/${ident}_State.hh"
1121#include "mem/protocol/Types.hh"
1122#include "mem/ruby/system/RubySystem.hh"
1123
1124#define HASH_FUN(state, event)  ((int(state)*${ident}_Event_NUM)+int(event))
1125
1126#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1127#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1128
1129TransitionResult
1130${ident}_Controller::doTransition(${ident}_Event event,
1131''')
1132        if self.EntryType != None:
1133            code('''
1134                                  ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1135''')
1136        if self.TBEType != None:
1137            code('''
1138                                  ${{self.TBEType.c_ident}}* m_tbe_ptr,
1139''')
1140        code('''
1141                                  Addr addr)
1142{
1143''')
1144        code.indent()
1145
1146        if self.TBEType != None and self.EntryType != None:
1147            code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1148        elif self.TBEType != None:
1149            code('${ident}_State state = getState(m_tbe_ptr, addr);')
1150        elif self.EntryType != None:
1151            code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1152        else:
1153            code('${ident}_State state = getState(addr);')
1154
1155        code('''
1156${ident}_State next_state = state;
1157
1158DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n",
1159        *this, curCycle(), ${ident}_State_to_string(state),
1160        ${ident}_Event_to_string(event), addr);
1161
1162TransitionResult result =
1163''')
1164        if self.TBEType != None and self.EntryType != None:
1165            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1166        elif self.TBEType != None:
1167            code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1168        elif self.EntryType != None:
1169            code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1170        else:
1171            code('doTransitionWorker(event, state, next_state, addr);')
1172
1173        port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident)
1174
1175        code('''
1176
1177if (result == TransitionResult_Valid) {
1178    DPRINTF(RubyGenerated, "next_state: %s\\n",
1179            ${ident}_State_to_string(next_state));
1180    countTransition(state, event);
1181
1182    DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n",
1183             curTick(), m_version, "${ident}",
1184             ${ident}_Event_to_string(event),
1185             ${ident}_State_to_string(state),
1186             ${ident}_State_to_string(next_state),
1187             printAddress(addr), GET_TRANSITION_COMMENT());
1188
1189    CLEAR_TRANSITION_COMMENT();
1190''')
1191        if self.TBEType != None and self.EntryType != None:
1192            code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1193            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1194        elif self.TBEType != None:
1195            code('setState(m_tbe_ptr, addr, next_state);')
1196            code('setAccessPermission(addr, next_state);')
1197        elif self.EntryType != None:
1198            code('setState(m_cache_entry_ptr, addr, next_state);')
1199            code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1200        else:
1201            code('setState(addr, next_state);')
1202            code('setAccessPermission(addr, next_state);')
1203
1204        code('''
1205} else if (result == TransitionResult_ResourceStall) {
1206    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1207             curTick(), m_version, "${ident}",
1208             ${ident}_Event_to_string(event),
1209             ${ident}_State_to_string(state),
1210             ${ident}_State_to_string(next_state),
1211             printAddress(addr), "Resource Stall");
1212} else if (result == TransitionResult_ProtocolStall) {
1213    DPRINTF(RubyGenerated, "stalling\\n");
1214    DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n",
1215             curTick(), m_version, "${ident}",
1216             ${ident}_Event_to_string(event),
1217             ${ident}_State_to_string(state),
1218             ${ident}_State_to_string(next_state),
1219             printAddress(addr), "Protocol Stall");
1220}
1221
1222return result;
1223''')
1224        code.dedent()
1225        code('''
1226}
1227
1228TransitionResult
1229${ident}_Controller::doTransitionWorker(${ident}_Event event,
1230                                        ${ident}_State state,
1231                                        ${ident}_State& next_state,
1232''')
1233
1234        if self.TBEType != None:
1235            code('''
1236                                        ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1237''')
1238        if self.EntryType != None:
1239                  code('''
1240                                        ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1241''')
1242        code('''
1243                                        Addr addr)
1244{
1245    switch(HASH_FUN(state, event)) {
1246''')
1247
1248        # This map will allow suppress generating duplicate code
1249        cases = orderdict()
1250
1251        for trans in self.transitions:
1252            case_string = "%s_State_%s, %s_Event_%s" % \
1253                (self.ident, trans.state.ident, self.ident, trans.event.ident)
1254
1255            case = self.symtab.codeFormatter()
1256            # Only set next_state if it changes
1257            if trans.state != trans.nextState:
1258                if trans.nextState.isWildcard():
1259                    # When * is encountered as an end state of a transition,
1260                    # the next state is determined by calling the
1261                    # machine-specific getNextState function. The next state
1262                    # is determined before any actions of the transition
1263                    # execute, and therefore the next state calculation cannot
1264                    # depend on any of the transitionactions.
1265                    case('next_state = getNextState(addr);')
1266                else:
1267                    ns_ident = trans.nextState.ident
1268                    case('next_state = ${ident}_State_${ns_ident};')
1269
1270            actions = trans.actions
1271            request_types = trans.request_types
1272
1273            # Check for resources
1274            case_sorter = []
1275            res = trans.resources
1276            for key,val in res.iteritems():
1277                val = '''
1278if (!%s.areNSlotsAvailable(%s, clockEdge()))
1279    return TransitionResult_ResourceStall;
1280''' % (key.code, val)
1281                case_sorter.append(val)
1282
1283            # Check all of the request_types for resource constraints
1284            for request_type in request_types:
1285                val = '''
1286if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1287    return TransitionResult_ResourceStall;
1288}
1289''' % (self.ident, request_type.ident)
1290                case_sorter.append(val)
1291
1292            # Emit the code sequences in a sorted order.  This makes the
1293            # output deterministic (without this the output order can vary
1294            # since Map's keys() on a vector of pointers is not deterministic
1295            for c in sorted(case_sorter):
1296                case("$c")
1297
1298            # Record access types for this transition
1299            for request_type in request_types:
1300                case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1301
1302            # Figure out if we stall
1303            stall = False
1304            for action in actions:
1305                if action.ident == "z_stall":
1306                    stall = True
1307                    break
1308
1309            if stall:
1310                case('return TransitionResult_ProtocolStall;')
1311            else:
1312                if self.TBEType != None and self.EntryType != None:
1313                    for action in actions:
1314                        case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1315                elif self.TBEType != None:
1316                    for action in actions:
1317                        case('${{action.ident}}(m_tbe_ptr, addr);')
1318                elif self.EntryType != None:
1319                    for action in actions:
1320                        case('${{action.ident}}(m_cache_entry_ptr, addr);')
1321                else:
1322                    for action in actions:
1323                        case('${{action.ident}}(addr);')
1324                case('return TransitionResult_Valid;')
1325
1326            case = str(case)
1327
1328            # Look to see if this transition code is unique.
1329            if case not in cases:
1330                cases[case] = []
1331
1332            cases[case].append(case_string)
1333
1334        # Walk through all of the unique code blocks and spit out the
1335        # corresponding case statement elements
1336        for case,transitions in cases.iteritems():
1337            # Iterative over all the multiple transitions that share
1338            # the same code
1339            for trans in transitions:
1340                code('  case HASH_FUN($trans):')
1341            code('    $case\n')
1342
1343        code('''
1344      default:
1345        panic("Invalid transition\\n"
1346              "%s time: %d addr: %s event: %s state: %s\\n",
1347              name(), curCycle(), addr, event, state);
1348    }
1349
1350    return TransitionResult_Valid;
1351}
1352''')
1353        code.write(path, "%s_Transitions.cc" % self.ident)
1354
1355
1356    # **************************
1357    # ******* HTML Files *******
1358    # **************************
1359    def frameRef(self, click_href, click_target, over_href, over_num, text):
1360        code = self.symtab.codeFormatter(fix_newlines=False)
1361        code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1362    if (parent.frames[$over_num].location != parent.location + '$over_href') {
1363        parent.frames[$over_num].location='$over_href'
1364    }\">
1365    ${{html.formatShorthand(text)}}
1366    </A>""")
1367        return str(code)
1368
1369    def writeHTMLFiles(self, path):
1370        # Create table with no row hilighted
1371        self.printHTMLTransitions(path, None)
1372
1373        # Generate transition tables
1374        for state in self.states.itervalues():
1375            self.printHTMLTransitions(path, state)
1376
1377        # Generate action descriptions
1378        for action in self.actions.itervalues():
1379            name = "%s_action_%s.html" % (self.ident, action.ident)
1380            code = html.createSymbol(action, "Action")
1381            code.write(path, name)
1382
1383        # Generate state descriptions
1384        for state in self.states.itervalues():
1385            name = "%s_State_%s.html" % (self.ident, state.ident)
1386            code = html.createSymbol(state, "State")
1387            code.write(path, name)
1388
1389        # Generate event descriptions
1390        for event in self.events.itervalues():
1391            name = "%s_Event_%s.html" % (self.ident, event.ident)
1392            code = html.createSymbol(event, "Event")
1393            code.write(path, name)
1394
1395    def printHTMLTransitions(self, path, active_state):
1396        code = self.symtab.codeFormatter()
1397
1398        code('''
1399<HTML>
1400<BODY link="blue" vlink="blue">
1401
1402<H1 align="center">${{html.formatShorthand(self.short)}}:
1403''')
1404        code.indent()
1405        for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1406            mid = machine.ident
1407            if i != 0:
1408                extra = " - "
1409            else:
1410                extra = ""
1411            if machine == self:
1412                code('$extra$mid')
1413            else:
1414                code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1415        code.dedent()
1416
1417        code("""
1418</H1>
1419
1420<TABLE border=1>
1421<TR>
1422  <TH> </TH>
1423""")
1424
1425        for event in self.events.itervalues():
1426            href = "%s_Event_%s.html" % (self.ident, event.ident)
1427            ref = self.frameRef(href, "Status", href, "1", event.short)
1428            code('<TH bgcolor=white>$ref</TH>')
1429
1430        code('</TR>')
1431        # -- Body of table
1432        for state in self.states.itervalues():
1433            # -- Each row
1434            if state == active_state:
1435                color = "yellow"
1436            else:
1437                color = "white"
1438
1439            click = "%s_table_%s.html" % (self.ident, state.ident)
1440            over = "%s_State_%s.html" % (self.ident, state.ident)
1441            text = html.formatShorthand(state.short)
1442            ref = self.frameRef(click, "Table", over, "1", state.short)
1443            code('''
1444<TR>
1445  <TH bgcolor=$color>$ref</TH>
1446''')
1447
1448            # -- One column for each event
1449            for event in self.events.itervalues():
1450                trans = self.table.get((state,event), None)
1451                if trans is None:
1452                    # This is the no transition case
1453                    if state == active_state:
1454                        color = "#C0C000"
1455                    else:
1456                        color = "lightgrey"
1457
1458                    code('<TD bgcolor=$color>&nbsp;</TD>')
1459                    continue
1460
1461                next = trans.nextState
1462                stall_action = False
1463
1464                # -- Get the actions
1465                for action in trans.actions:
1466                    if action.ident == "z_stall" or \
1467                       action.ident == "zz_recycleMandatoryQueue":
1468                        stall_action = True
1469
1470                # -- Print out "actions/next-state"
1471                if stall_action:
1472                    if state == active_state:
1473                        color = "#C0C000"
1474                    else:
1475                        color = "lightgrey"
1476
1477                elif active_state and next.ident == active_state.ident:
1478                    color = "aqua"
1479                elif state == active_state:
1480                    color = "yellow"
1481                else:
1482                    color = "white"
1483
1484                code('<TD bgcolor=$color>')
1485                for action in trans.actions:
1486                    href = "%s_action_%s.html" % (self.ident, action.ident)
1487                    ref = self.frameRef(href, "Status", href, "1",
1488                                        action.short)
1489                    code('  $ref')
1490                if next != state:
1491                    if trans.actions:
1492                        code('/')
1493                    click = "%s_table_%s.html" % (self.ident, next.ident)
1494                    over = "%s_State_%s.html" % (self.ident, next.ident)
1495                    ref = self.frameRef(click, "Table", over, "1", next.short)
1496                    code("$ref")
1497                code("</TD>")
1498
1499            # -- Each row
1500            if state == active_state:
1501                color = "yellow"
1502            else:
1503                color = "white"
1504
1505            click = "%s_table_%s.html" % (self.ident, state.ident)
1506            over = "%s_State_%s.html" % (self.ident, state.ident)
1507            ref = self.frameRef(click, "Table", over, "1", state.short)
1508            code('''
1509  <TH bgcolor=$color>$ref</TH>
1510</TR>
1511''')
1512        code('''
1513<!- Column footer->
1514<TR>
1515  <TH> </TH>
1516''')
1517
1518        for event in self.events.itervalues():
1519            href = "%s_Event_%s.html" % (self.ident, event.ident)
1520            ref = self.frameRef(href, "Status", href, "1", event.short)
1521            code('<TH bgcolor=white>$ref</TH>')
1522        code('''
1523</TR>
1524</TABLE>
1525</BODY></HTML>
1526''')
1527
1528
1529        if active_state:
1530            name = "%s_table_%s.html" % (self.ident, active_state.ident)
1531        else:
1532            name = "%s_table.html" % self.ident
1533        code.write(path, name)
1534
1535__all__ = [ "StateMachine" ]
1536