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