Deleted Added
sdiff udiff text old ( 6999:f226c098c393 ) new ( 7002:48a19d52d939 )
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
33
34python_class_map = {"int": "Int",
35 "string": "String",
36 "bool": "Bool",
37 "CacheMemory": "RubyCache",
38 "Sequencer": "RubySequencer",
39 "DirectoryMemory": "RubyDirectoryMemory",
40 "MemoryControl": "RubyMemoryControl",
41 "DMASequencer": "DMASequencer"
42 }
43
44class StateMachine(Symbol):
45 def __init__(self, symtab, ident, location, pairs, config_parameters):
46 super(StateMachine, self).__init__(symtab, ident, location, pairs)
47 self.table = None
48 self.config_parameters = config_parameters
49 for param in config_parameters:
50 if param.pointer:
51 var = Var(symtab, param.name, location, param.type_ast.type,
52 "(*m_%s_ptr)" % param.name, {}, self)
53 else:
54 var = Var(symtab, param.name, location, param.type_ast.type,
55 "m_%s" % param.name, {}, self)
56 self.symtab.registerSym(param.name, var)
57
58 self.states = orderdict()
59 self.events = orderdict()
60 self.actions = orderdict()
61 self.transitions = []
62 self.in_ports = []
63 self.functions = []
64 self.objects = []
65
66 self.message_buffer_names = []
67
68 def __repr__(self):
69 return "[StateMachine: %s]" % self.ident
70
71 def addState(self, state):
72 assert self.table is None
73 self.states[state.ident] = state
74
75 def addEvent(self, event):
76 assert self.table is None
77 self.events[event.ident] = event
78
79 def addAction(self, action):
80 assert self.table is None
81
82 # Check for duplicate action
83 for other in self.actions.itervalues():
84 if action.ident == other.ident:
85 action.warning("Duplicate action definition: %s" % action.ident)
86 action.error("Duplicate action definition: %s" % action.ident)
87 if action.short == other.short:
88 other.warning("Duplicate action shorthand: %s" % other.ident)
89 other.warning(" shorthand = %s" % other.short)
90 action.warning("Duplicate action shorthand: %s" % action.ident)
91 action.error(" shorthand = %s" % action.short)
92
93 self.actions[action.ident] = action
94
95 def addTransition(self, trans):
96 assert self.table is None
97 self.transitions.append(trans)
98
99 def addInPort(self, var):
100 self.in_ports.append(var)
101
102 def addFunc(self, func):
103 # register func in the symbol table
104 self.symtab.registerSym(str(func), func)
105 self.functions.append(func)
106
107 def addObject(self, obj):
108 self.objects.append(obj)
109
110 # Needs to be called before accessing the table
111 def buildTable(self):
112 assert self.table is None
113
114 table = {}
115
116 for trans in self.transitions:
117 # Track which actions we touch so we know if we use them
118 # all -- really this should be done for all symbols as
119 # part of the symbol table, then only trigger it for
120 # Actions, States, Events, etc.
121
122 for action in trans.actions:
123 action.used = True
124
125 index = (trans.state, trans.event)
126 if index in table:
127 table[index].warning("Duplicate transition: %s" % table[index])
128 trans.error("Duplicate transition: %s" % trans)
129 table[index] = trans
130
131 # Look at all actions to make sure we used them all
132 for action in self.actions.itervalues():
133 if not action.used:
134 error_msg = "Unused action: %s" % action.ident
135 if "desc" in action:
136 error_msg += ", " + action.desc
137 action.warning(error_msg)
138 self.table = table
139
140 def writeCodeFiles(self, path):
141 self.printControllerPython(path)
142 self.printControllerHH(path)
143 self.printControllerCC(path)
144 self.printCSwitch(path)
145 self.printCWakeup(path)
146 self.printProfilerCC(path)
147 self.printProfilerHH(path)
148
149 for func in self.functions:
150 func.writeCodeFiles(path)
151
152 def printControllerPython(self, path):
153 code = self.symtab.codeFormatter()
154 ident = self.ident
155 py_ident = "%s_Controller" % ident
156 c_ident = "%s_Controller" % self.ident
157 code('''
158from m5.params import *
159from m5.SimObject import SimObject
160from Controller import RubyController
161
162class $py_ident(RubyController):
163 type = '$py_ident'
164''')
165 code.indent()
166 for param in self.config_parameters:
167 dflt_str = ''
168 if param.default is not None:
169 dflt_str = str(param.default) + ', '
170 if python_class_map.has_key(param.type_ast.type.c_ident):
171 python_type = python_class_map[param.type_ast.type.c_ident]
172 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
173 else:
174 self.error("Unknown c++ to python class conversion for c++ " \
175 "type: '%s'. Please update the python_class_map " \
176 "in StateMachine.py", param.type_ast.type.c_ident)
177 code.dedent()
178 code.write(path, '%s.py' % py_ident)
179
180
181 def printControllerHH(self, path):
182 '''Output the method declarations for the class declaration'''
183 code = self.symtab.codeFormatter()
184 ident = self.ident
185 c_ident = "%s_Controller" % self.ident
186
187 self.message_buffer_names = []
188
189 code('''
190/** \\file $ident.hh
191 *
192 * Auto generated C++ code started by $__file__:$__line__
193 * Created by slicc definition of Module "${{self.short}}"
194 */
195
196#ifndef ${ident}_CONTROLLER_H
197#define ${ident}_CONTROLLER_H
198
199#include "params/$c_ident.hh"
200
201#include "mem/ruby/common/Global.hh"
202#include "mem/ruby/common/Consumer.hh"
203#include "mem/ruby/slicc_interface/AbstractController.hh"
204#include "mem/protocol/TransitionResult.hh"
205#include "mem/protocol/Types.hh"
206#include "mem/protocol/${ident}_Profiler.hh"
207''')
208
209 seen_types = set()
210 for var in self.objects:
211 if var.type.ident not in seen_types and not var.type.isPrimitive:
212 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
213 seen_types.add(var.type.ident)
214
215 # for adding information to the protocol debug trace
216 code('''
217extern stringstream ${ident}_transitionComment;
218
219class $c_ident : public AbstractController {
220#ifdef CHECK_COHERENCE
221#endif /* CHECK_COHERENCE */
222public:
223 typedef ${c_ident}Params Params;
224 $c_ident(const Params *p);
225 static int getNumControllers();
226 void init();
227 MessageBuffer* getMandatoryQueue() const;
228 const int & getVersion() const;
229 const string toString() const;
230 const string getName() const;
231 const MachineType getMachineType() const;
232 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
233 void print(ostream& out) const;
234 void printConfig(ostream& out) const;
235 void wakeup();
236 void printStats(ostream& out) const;
237 void clearStats();
238 void blockOnQueue(Address addr, MessageBuffer* port);
239 void unblock(Address addr);
240private:
241''')
242
243 code.indent()
244 # added by SS
245 for param in self.config_parameters:
246 if param.pointer:
247 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
248 else:
249 code('${{param.type_ast.type}} m_${{param.ident}};')
250
251 code('''
252int m_number_of_TBEs;
253
254TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc
255TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc
256string m_name;
257int m_transitions_per_cycle;
258int m_buffer_size;
259int m_recycle_latency;
260map< string, string > m_cfg;
261NodeID m_version;
262Network* m_net_ptr;
263MachineID m_machineID;
264bool m_is_blocking;
265map< Address, MessageBuffer* > m_block_map;
266${ident}_Profiler s_profiler;
267static int m_num_controllers;
268// Internal functions
269''')
270
271 for func in self.functions:
272 proto = func.prototype
273 if proto:
274 code('$proto')
275
276 code('''
277
278// Actions
279''')
280 for action in self.actions.itervalues():
281 code('/** \\brief ${{action.desc}} */')
282 code('void ${{action.ident}}(const Address& addr);')
283
284 # the controller internal variables
285 code('''
286
287// Object
288''')
289 for var in self.objects:
290 th = var.get("template_hack", "")
291 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
292
293 if var.type.ident == "MessageBuffer":
294 self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
295
296 code.dedent()
297 code('};')
298 code('#endif // ${ident}_CONTROLLER_H')
299 code.write(path, '%s.hh' % c_ident)
300
301 def printControllerCC(self, path):
302 '''Output the actions for performing the actions'''
303
304 code = self.symtab.codeFormatter()
305 ident = self.ident
306 c_ident = "%s_Controller" % self.ident
307
308 code('''
309/** \\file $ident.cc
310 *
311 * Auto generated C++ code started by $__file__:$__line__
312 * Created by slicc definition of Module "${{self.short}}"
313 */
314
315#include "mem/ruby/common/Global.hh"
316#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
317#include "mem/protocol/${ident}_Controller.hh"
318#include "mem/protocol/${ident}_State.hh"
319#include "mem/protocol/${ident}_Event.hh"
320#include "mem/protocol/Types.hh"
321#include "mem/ruby/system/System.hh"
322''')
323
324 # include object classes
325 seen_types = set()
326 for var in self.objects:
327 if var.type.ident not in seen_types and not var.type.isPrimitive:
328 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
329 seen_types.add(var.type.ident)
330
331 code('''
332$c_ident *
333${c_ident}Params::create()
334{
335 return new $c_ident(this);
336}
337
338
339int $c_ident::m_num_controllers = 0;
340
341stringstream ${ident}_transitionComment;
342#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
343/** \\brief constructor */
344$c_ident::$c_ident(const Params *p)
345 : AbstractController(p)
346{
347 m_version = p->version;
348 m_transitions_per_cycle = p->transitions_per_cycle;
349 m_buffer_size = p->buffer_size;
350 m_recycle_latency = p->recycle_latency;
351 m_number_of_TBEs = p->number_of_TBEs;
352 m_is_blocking = false;
353''')
354 code.indent()
355
356 #
357 # After initializing the universal machine parameters, initialize the
358 # this machines config parameters. Also detemine if these configuration
359 # params include a sequencer. This information will be used later for
360 # contecting the sequencer back to the L1 cache controller.
361 #
362 contains_sequencer = False
363 for param in self.config_parameters:
364 if param.name == "sequencer" or param.name == "dma_sequencer":
365 contains_sequencer = True
366 if param.pointer:
367 code('m_${{param.name}}_ptr = p->${{param.name}};')
368 else:
369 code('m_${{param.name}} = p->${{param.name}};')
370
371 #
372 # For the l1 cache controller, add the special atomic support which
373 # includes passing the sequencer a pointer to the controller.
374 #
375 if self.ident == "L1Cache":
376 if not contains_sequencer:
377 self.error("The L1Cache controller must include the sequencer " \
378 "configuration parameter")
379
380 code('''
381m_sequencer_ptr->setController(this);
382''')
383 #
384 # For the DMA controller, pass the sequencer a pointer to the
385 # controller.
386 #
387 if self.ident == "DMA":
388 if not contains_sequencer:
389 self.error("The DMA controller must include the sequencer " \
390 "configuration parameter")
391
392 code('''
393m_dma_sequencer_ptr->setController(this);
394''')
395
396 code('m_num_controllers++;')
397 for var in self.objects:
398 if var.ident.find("mandatoryQueue") >= 0:
399 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
400
401 code.dedent()
402 code('''
403}
404
405void $c_ident::init()
406{
407 m_machineID.type = MachineType_${ident};
408 m_machineID.num = m_version;
409
410 // Objects
411 s_profiler.setVersion(m_version);
412''')
413
414 code.indent()
415 for var in self.objects:
416 vtype = var.type
417 vid = "m_%s_ptr" % var.c_ident
418 if "network" not in var:
419 # Not a network port object
420 if "primitive" in vtype:
421 code('$vid = new ${{vtype.c_ident}};')
422 if "default" in var:
423 code('(*$vid) = ${{var["default"]}};')
424 else:
425 # Normal Object
426 # added by SS
427 if "factory" in var:
428 code('$vid = ${{var["factory"]}};')
429 elif var.ident.find("mandatoryQueue") < 0:
430 th = var.get("template_hack", "")
431 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
432
433 args = ""
434 if "non_obj" not in vtype and not vtype.isEnumeration:
435 if expr.find("TBETable") >= 0:
436 args = "m_number_of_TBEs"
437 else:
438 args = var.get("constructor_hack", "")
439 args = "(%s)" % args
440
441 code('$expr$args;')
442 else:
443 code(';')
444
445 code('assert($vid != NULL);')
446
447 if "default" in var:
448 code('(*$vid) = ${{var["default"]}}; // Object default')
449 elif "default" in vtype:
450 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default')
451
452 # Set ordering
453 if "ordered" in var and "trigger_queue" not in var:
454 # A buffer
455 code('$vid->setOrdering(${{var["ordered"]}});')
456
457 # Set randomization
458 if "random" in var:
459 # A buffer
460 code('$vid->setRandomization(${{var["random"]}});')
461
462 # Set Priority
463 if vtype.isBuffer and \
464 "rank" in var and "trigger_queue" not in var:
465 code('$vid->setPriority(${{var["rank"]}});')
466 else:
467 # Network port object
468 network = var["network"]
469 ordered = var["ordered"]
470 vnet = var["virtual_network"]
471
472 assert var.machine is not None
473 code('''
474$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet);
475''')
476
477 code('assert($vid != NULL);')
478
479 # Set ordering
480 if "ordered" in var:
481 # A buffer
482 code('$vid->setOrdering(${{var["ordered"]}});')
483
484 # Set randomization
485 if "random" in var:
486 # A buffer
487 code('$vid->setRandomization(${{var["random"]}})')
488
489 # Set Priority
490 if "rank" in var:
491 code('$vid->setPriority(${{var["rank"]}})')
492
493 # Set buffer size
494 if vtype.isBuffer:
495 code('''
496if (m_buffer_size > 0) {
497 $vid->setSize(m_buffer_size);
498}
499''')
500
501 # set description (may be overriden later by port def)
502 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");')
503
504 # Set the queue consumers
505 code.insert_newline()
506 for port in self.in_ports:
507 code('${{port.code}}.setConsumer(this);')
508
509 # Set the queue descriptions
510 code.insert_newline()
511 for port in self.in_ports:
512 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");')
513
514 # Initialize the transition profiling
515 code.insert_newline()
516 for trans in self.transitions:
517 # Figure out if we stall
518 stall = False
519 for action in trans.actions:
520 if action.ident == "z_stall":
521 stall = True
522
523 # Only possible if it is not a 'z' case
524 if not stall:
525 state = "%s_State_%s" % (self.ident, trans.state.ident)
526 event = "%s_Event_%s" % (self.ident, trans.event.ident)
527 code('s_profiler.possibleTransition($state, $event);')
528
529 # added by SS to initialize recycle_latency of message buffers
530 for buf in self.message_buffer_names:
531 code("$buf->setRecycleLatency(m_recycle_latency);")
532
533 code.dedent()
534 code('}')
535
536 has_mandatory_q = False
537 for port in self.in_ports:
538 if port.code.find("mandatoryQueue_ptr") >= 0:
539 has_mandatory_q = True
540
541 if has_mandatory_q:
542 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
543 else:
544 mq_ident = "NULL"
545
546 code('''
547int $c_ident::getNumControllers() {
548 return m_num_controllers;
549}
550
551MessageBuffer* $c_ident::getMandatoryQueue() const {
552 return $mq_ident;
553}
554
555const int & $c_ident::getVersion() const{
556 return m_version;
557}
558
559const string $c_ident::toString() const{
560 return "$c_ident";
561}
562
563const string $c_ident::getName() const{
564 return m_name;
565}
566const MachineType $c_ident::getMachineType() const{
567 return MachineType_${ident};
568}
569
570void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) {
571 m_is_blocking = true;
572 m_block_map[addr] = port;
573}
574void $c_ident::unblock(Address addr) {
575 m_block_map.erase(addr);
576 if (m_block_map.size() == 0) {
577 m_is_blocking = false;
578 }
579}
580
581void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; }
582
583void $c_ident::printConfig(ostream& out) const {
584 out << "$c_ident config: " << m_name << endl;
585 out << " version: " << m_version << endl;
586 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) {
587 out << " " << (*it).first << ": " << (*it).second << endl;
588 }
589}
590
591void $c_ident::printStats(ostream& out) const {
592''')
593 #
594 # Cache and Memory Controllers have specific profilers associated with
595 # them. Print out these stats before dumping state transition stats.
596 #
597 for param in self.config_parameters:
598 if param.type_ast.type.ident == "CacheMemory" or \
599 param.type_ast.type.ident == "MemoryControl":
600 assert(param.pointer)
601 code(' m_${{param.ident}}_ptr->printStats(out);')
602
603 code('''
604 s_profiler.dumpStats(out);
605}
606
607void $c_ident::clearStats() {
608''')
609 #
610 # Cache and Memory Controllers have specific profilers associated with
611 # them. These stats must be cleared too.
612 #
613 for param in self.config_parameters:
614 if param.type_ast.type.ident == "CacheMemory" or \
615 param.type_ast.type.ident == "MemoryControl":
616 assert(param.pointer)
617 code(' m_${{param.ident}}_ptr->clearStats();')
618
619 code('''
620 s_profiler.clearStats();
621}
622
623// Actions
624''')
625
626 for action in self.actions.itervalues():
627 if "c_code" not in action:
628 continue
629
630 code('''
631/** \\brief ${{action.desc}} */
632void $c_ident::${{action.ident}}(const Address& addr)
633{
634 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
635 ${{action["c_code"]}}
636}
637
638''')
639 code.write(path, "%s.cc" % c_ident)
640
641 def printCWakeup(self, path):
642 '''Output the wakeup loop for the events'''
643
644 code = self.symtab.codeFormatter()
645 ident = self.ident
646
647 code('''
648// Auto generated C++ code started by $__file__:$__line__
649// ${ident}: ${{self.short}}
650
651#include "mem/ruby/common/Global.hh"
652#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
653#include "mem/protocol/${ident}_Controller.hh"
654#include "mem/protocol/${ident}_State.hh"
655#include "mem/protocol/${ident}_Event.hh"
656#include "mem/protocol/Types.hh"
657#include "mem/ruby/system/System.hh"
658
659void ${ident}_Controller::wakeup()
660{
661
662 int counter = 0;
663 while (true) {
664 // Some cases will put us into an infinite loop without this limit
665 assert(counter <= m_transitions_per_cycle);
666 if (counter == m_transitions_per_cycle) {
667 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized
668 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again
669 break;
670 }
671''')
672
673 code.indent()
674 code.indent()
675
676 # InPorts
677 #
678 for port in self.in_ports:
679 code.indent()
680 code('// ${ident}InPort $port')
681 code('${{port["c_code_in_port"]}}')
682 code.dedent()
683
684 code('')
685
686 code.dedent()
687 code.dedent()
688 code('''
689 break; // If we got this far, we have nothing left todo
690 }
691}
692''')
693
694 code.write(path, "%s_Wakeup.cc" % self.ident)
695
696 def printCSwitch(self, path):
697 '''Output switch statement for transition table'''
698
699 code = self.symtab.codeFormatter()
700 ident = self.ident
701
702 code('''
703// Auto generated C++ code started by $__file__:$__line__
704// ${ident}: ${{self.short}}
705
706#include "mem/ruby/common/Global.hh"
707#include "mem/protocol/${ident}_Controller.hh"
708#include "mem/protocol/${ident}_State.hh"
709#include "mem/protocol/${ident}_Event.hh"
710#include "mem/protocol/Types.hh"
711#include "mem/ruby/system/System.hh"
712
713#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
714
715#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
716#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
717
718TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr
719)
720{
721 ${ident}_State next_state = state;
722
723 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
724 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
725 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
726 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
727 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
728 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
729
730 TransitionResult result = doTransitionWorker(event, state, next_state, addr);
731
732 if (result == TransitionResult_Valid) {
733 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
734 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
735 s_profiler.countTransition(state, event);
736 if (Debug::getProtocolTrace()) {
737 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
738 ${ident}_State_to_string(state),
739 ${ident}_Event_to_string(event),
740 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT());
741 }
742 CLEAR_TRANSITION_COMMENT();
743 ${ident}_setState(addr, next_state);
744
745 } else if (result == TransitionResult_ResourceStall) {
746 if (Debug::getProtocolTrace()) {
747 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
748 ${ident}_State_to_string(state),
749 ${ident}_Event_to_string(event),
750 ${ident}_State_to_string(next_state),
751 "Resource Stall");
752 }
753 } else if (result == TransitionResult_ProtocolStall) {
754 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
755 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
756 if (Debug::getProtocolTrace()) {
757 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
758 ${ident}_State_to_string(state),
759 ${ident}_Event_to_string(event),
760 ${ident}_State_to_string(next_state),
761 "Protocol Stall");
762 }
763 }
764
765 return result;
766}
767
768TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr
769)
770{
771 switch(HASH_FUN(state, event)) {
772''')
773
774 # This map will allow suppress generating duplicate code
775 cases = orderdict()
776
777 for trans in self.transitions:
778 case_string = "%s_State_%s, %s_Event_%s" % \
779 (self.ident, trans.state.ident, self.ident, trans.event.ident)
780
781 case = self.symtab.codeFormatter()
782 # Only set next_state if it changes
783 if trans.state != trans.nextState:
784 ns_ident = trans.nextState.ident
785 case('next_state = ${ident}_State_${ns_ident};')
786
787 actions = trans.actions
788
789 # Check for resources
790 case_sorter = []
791 res = trans.resources
792 for key,val in res.iteritems():
793 if key.type.ident != "DNUCAStopTable":
794 val = '''
795if (!%s.areNSlotsAvailable(%s)) {
796 return TransitionResult_ResourceStall;
797}
798''' % (key.code, val)
799 case_sorter.append(val)
800
801
802 # Emit the code sequences in a sorted order. This makes the
803 # output deterministic (without this the output order can vary
804 # since Map's keys() on a vector of pointers is not deterministic
805 for c in sorted(case_sorter):
806 case("$c")
807
808 # Figure out if we stall
809 stall = False
810 for action in actions:
811 if action.ident == "z_stall":
812 stall = True
813 break
814
815 if stall:
816 case('return TransitionResult_ProtocolStall;')
817 else:
818 for action in actions:
819 case('${{action.ident}}(addr);')
820 case('return TransitionResult_Valid;')
821
822 case = str(case)
823
824 # Look to see if this transition code is unique.
825 if case not in cases:
826 cases[case] = []
827
828 cases[case].append(case_string)
829
830 # Walk through all of the unique code blocks and spit out the
831 # corresponding case statement elements
832 for case,transitions in cases.iteritems():
833 # Iterative over all the multiple transitions that share
834 # the same code
835 for trans in transitions:
836 code(' case HASH_FUN($trans):')
837 code(' {')
838 code(' $case')
839 code(' }')
840
841 code('''
842 default:
843 WARN_EXPR(m_version);
844 WARN_EXPR(g_eventQueue_ptr->getTime());
845 WARN_EXPR(addr);
846 WARN_EXPR(event);
847 WARN_EXPR(state);
848 ERROR_MSG(\"Invalid transition\");
849 }
850 return TransitionResult_Valid;
851}
852''')
853 code.write(path, "%s_Transitions.cc" % self.ident)
854
855 def printProfilerHH(self, path):
856 code = self.symtab.codeFormatter()
857 ident = self.ident
858
859 code('''
860// Auto generated C++ code started by $__file__:$__line__
861// ${ident}: ${{self.short}}
862
863#ifndef ${ident}_PROFILER_H
864#define ${ident}_PROFILER_H
865
866#include "mem/ruby/common/Global.hh"
867#include "mem/protocol/${ident}_State.hh"
868#include "mem/protocol/${ident}_Event.hh"
869
870class ${ident}_Profiler {
871 public:
872 ${ident}_Profiler();
873 void setVersion(int version);
874 void countTransition(${ident}_State state, ${ident}_Event event);
875 void possibleTransition(${ident}_State state, ${ident}_Event event);
876 void dumpStats(ostream& out) const;
877 void clearStats();
878
879 private:
880 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
881 int m_event_counters[${ident}_Event_NUM];
882 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
883 int m_version;
884};
885
886#endif // ${ident}_PROFILER_H
887''')
888 code.write(path, "%s_Profiler.hh" % self.ident)
889
890 def printProfilerCC(self, path):
891 code = self.symtab.codeFormatter()
892 ident = self.ident
893
894 code('''
895// Auto generated C++ code started by $__file__:$__line__
896// ${ident}: ${{self.short}}
897
898#include "mem/protocol/${ident}_Profiler.hh"
899
900${ident}_Profiler::${ident}_Profiler()
901{
902 for (int state = 0; state < ${ident}_State_NUM; state++) {
903 for (int event = 0; event < ${ident}_Event_NUM; event++) {
904 m_possible[state][event] = false;
905 m_counters[state][event] = 0;
906 }
907 }
908 for (int event = 0; event < ${ident}_Event_NUM; event++) {
909 m_event_counters[event] = 0;
910 }
911}
912void ${ident}_Profiler::setVersion(int version)
913{
914 m_version = version;
915}
916void ${ident}_Profiler::clearStats()
917{
918 for (int state = 0; state < ${ident}_State_NUM; state++) {
919 for (int event = 0; event < ${ident}_Event_NUM; event++) {
920 m_counters[state][event] = 0;
921 }
922 }
923
924 for (int event = 0; event < ${ident}_Event_NUM; event++) {
925 m_event_counters[event] = 0;
926 }
927}
928void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
929{
930 assert(m_possible[state][event]);
931 m_counters[state][event]++;
932 m_event_counters[event]++;
933}
934void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event)
935{
936 m_possible[state][event] = true;
937}
938void ${ident}_Profiler::dumpStats(ostream& out) const
939{
940 out << " --- ${ident} " << m_version << " ---" << endl;
941 out << " - Event Counts -" << endl;
942 for (int event = 0; event < ${ident}_Event_NUM; event++) {
943 int count = m_event_counters[event];
944 out << (${ident}_Event) event << " " << count << endl;
945 }
946 out << endl;
947 out << " - Transitions -" << endl;
948 for (int state = 0; state < ${ident}_State_NUM; state++) {
949 for (int event = 0; event < ${ident}_Event_NUM; event++) {
950 if (m_possible[state][event]) {
951 int count = m_counters[state][event];
952 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count;
953 if (count == 0) {
954 out << " <-- ";
955 }
956 out << endl;
957 }
958 }
959 out << endl;
960 }
961}
962''')
963 code.write(path, "%s_Profiler.cc" % self.ident)
964
965 # **************************
966 # ******* HTML Files *******
967 # **************************
968 def frameRef(self, click_href, click_target, over_href, over_target_num,
969 text):
970 code = self.symtab.codeFormatter(fix_newlines=False)
971 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""")
972 return str(code)
973
974 def writeHTMLFiles(self, path):
975 # Create table with no row hilighted
976 self.printHTMLTransitions(path, None)
977
978 # Generate transition tables
979 for state in self.states.itervalues():
980 self.printHTMLTransitions(path, state)
981
982 # Generate action descriptions
983 for action in self.actions.itervalues():
984 name = "%s_action_%s.html" % (self.ident, action.ident)
985 code = html.createSymbol(action, "Action")
986 code.write(path, name)
987
988 # Generate state descriptions
989 for state in self.states.itervalues():
990 name = "%s_State_%s.html" % (self.ident, state.ident)
991 code = html.createSymbol(state, "State")
992 code.write(path, name)
993
994 # Generate event descriptions
995 for event in self.events.itervalues():
996 name = "%s_Event_%s.html" % (self.ident, event.ident)
997 code = html.createSymbol(event, "Event")
998 code.write(path, name)
999
1000 def printHTMLTransitions(self, path, active_state):
1001 code = self.symtab.codeFormatter()
1002
1003 code('''
1004<HTML><BODY link="blue" vlink="blue">
1005
1006<H1 align="center">${{html.formatShorthand(self.short)}}:
1007''')
1008 code.indent()
1009 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1010 mid = machine.ident
1011 if i != 0:
1012 extra = " - "
1013 else:
1014 extra = ""
1015 if machine == self:
1016 code('$extra$mid')
1017 else:
1018 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1019 code.dedent()
1020
1021 code("""
1022</H1>
1023
1024<TABLE border=1>
1025<TR>
1026 <TH> </TH>
1027""")
1028
1029 for event in self.events.itervalues():
1030 href = "%s_Event_%s.html" % (self.ident, event.ident)
1031 ref = self.frameRef(href, "Status", href, "1", event.short)
1032 code('<TH bgcolor=white>$ref</TH>')
1033
1034 code('</TR>')
1035 # -- Body of table
1036 for state in self.states.itervalues():
1037 # -- Each row
1038 if state == active_state:
1039 color = "yellow"
1040 else:
1041 color = "white"
1042
1043 click = "%s_table_%s.html" % (self.ident, state.ident)
1044 over = "%s_State_%s.html" % (self.ident, state.ident)
1045 text = html.formatShorthand(state.short)
1046 ref = self.frameRef(click, "Table", over, "1", state.short)
1047 code('''
1048<TR>
1049 <TH bgcolor=$color>$ref</TH>
1050''')
1051
1052 # -- One column for each event
1053 for event in self.events.itervalues():
1054 trans = self.table.get((state,event), None)
1055 if trans is None:
1056 # This is the no transition case
1057 if state == active_state:
1058 color = "#C0C000"
1059 else:
1060 color = "lightgrey"
1061
1062 code('<TD bgcolor=$color>&nbsp;</TD>')
1063 continue
1064
1065 next = trans.nextState
1066 stall_action = False
1067
1068 # -- Get the actions
1069 for action in trans.actions:
1070 if action.ident == "z_stall" or \
1071 action.ident == "zz_recycleMandatoryQueue":
1072 stall_action = True
1073
1074 # -- Print out "actions/next-state"
1075 if stall_action:
1076 if state == active_state:
1077 color = "#C0C000"
1078 else:
1079 color = "lightgrey"
1080
1081 elif active_state and next.ident == active_state.ident:
1082 color = "aqua"
1083 elif state == active_state:
1084 color = "yellow"
1085 else:
1086 color = "white"
1087
1088 fix = code.nofix()
1089 code('<TD bgcolor=$color>')
1090 for action in trans.actions:
1091 href = "%s_action_%s.html" % (self.ident, action.ident)
1092 ref = self.frameRef(href, "Status", href, "1",
1093 action.short)
1094 code(' $ref\n')
1095 if next != state:
1096 if trans.actions:
1097 code('/')
1098 click = "%s_table_%s.html" % (self.ident, next.ident)
1099 over = "%s_State_%s.html" % (self.ident, next.ident)
1100 ref = self.frameRef(click, "Table", over, "1", next.short)
1101 code("$ref")
1102 code("</TD>\n")
1103 code.fix(fix)
1104
1105 # -- Each row
1106 if state == active_state:
1107 color = "yellow"
1108 else:
1109 color = "white"
1110
1111 click = "%s_table_%s.html" % (self.ident, state.ident)
1112 over = "%s_State_%s.html" % (self.ident, state.ident)
1113 ref = self.frameRef(click, "Table", over, "1", state.short)
1114 code('''
1115 <TH bgcolor=$color>$ref</TH>
1116</TR>
1117''')
1118 code('''
1119<TR>
1120 <TH> </TH>
1121''')
1122
1123 for event in self.events.itervalues():
1124 href = "%s_Event_%s.html" % (self.ident, event.ident)
1125 ref = self.frameRef(href, "Status", href, "1", event.short)
1126 code('<TH bgcolor=white>$ref</TH>')
1127 code('''
1128</TR>
1129</TABLE>
1130</BODY></HTML>
1131''')
1132
1133
1134 if active_state:
1135 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1136 else:
1137 name = "%s_table.html" % self.ident
1138 code.write(path, name)
1139
1140__all__ = [ "StateMachine" ]