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