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