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