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