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