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