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