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