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