StateMachine.py (7542:49327b849c7f) StateMachine.py (7566:6919df046bba)
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
33
34python_class_map = {"int": "Int",
35 "std::string": "String",
36 "bool": "Bool",
37 "CacheMemory": "RubyCache",
38 "Sequencer": "RubySequencer",
39 "DirectoryMemory": "RubyDirectoryMemory",
40 "MemoryControl": "RubyMemoryControl",
41 "DMASequencer": "DMASequencer"
42 }
43
44class StateMachine(Symbol):
45 def __init__(self, symtab, ident, location, pairs, config_parameters):
46 super(StateMachine, self).__init__(symtab, ident, location, pairs)
47 self.table = None
48 self.config_parameters = config_parameters
49 for param in config_parameters:
50 if param.pointer:
51 var = Var(symtab, param.name, location, param.type_ast.type,
52 "(*m_%s_ptr)" % param.name, {}, self)
53 else:
54 var = Var(symtab, param.name, location, param.type_ast.type,
55 "m_%s" % param.name, {}, self)
56 self.symtab.registerSym(param.name, var)
57
58 self.states = orderdict()
59 self.events = orderdict()
60 self.actions = orderdict()
61 self.transitions = []
62 self.in_ports = []
63 self.functions = []
64 self.objects = []
65
66 self.message_buffer_names = []
67
68 def __repr__(self):
69 return "[StateMachine: %s]" % self.ident
70
71 def addState(self, state):
72 assert self.table is None
73 self.states[state.ident] = state
74
75 def addEvent(self, event):
76 assert self.table is None
77 self.events[event.ident] = event
78
79 def addAction(self, action):
80 assert self.table is None
81
82 # Check for duplicate action
83 for other in self.actions.itervalues():
84 if action.ident == other.ident:
85 action.warning("Duplicate action definition: %s" % action.ident)
86 action.error("Duplicate action definition: %s" % action.ident)
87 if action.short == other.short:
88 other.warning("Duplicate action shorthand: %s" % other.ident)
89 other.warning(" shorthand = %s" % other.short)
90 action.warning("Duplicate action shorthand: %s" % action.ident)
91 action.error(" shorthand = %s" % action.short)
92
93 self.actions[action.ident] = action
94
95 def addTransition(self, trans):
96 assert self.table is None
97 self.transitions.append(trans)
98
99 def addInPort(self, var):
100 self.in_ports.append(var)
101
102 def addFunc(self, func):
103 # register func in the symbol table
104 self.symtab.registerSym(str(func), func)
105 self.functions.append(func)
106
107 def addObject(self, obj):
108 self.objects.append(obj)
109
110 # Needs to be called before accessing the table
111 def buildTable(self):
112 assert self.table is None
113
114 table = {}
115
116 for trans in self.transitions:
117 # Track which actions we touch so we know if we use them
118 # all -- really this should be done for all symbols as
119 # part of the symbol table, then only trigger it for
120 # Actions, States, Events, etc.
121
122 for action in trans.actions:
123 action.used = True
124
125 index = (trans.state, trans.event)
126 if index in table:
127 table[index].warning("Duplicate transition: %s" % table[index])
128 trans.error("Duplicate transition: %s" % trans)
129 table[index] = trans
130
131 # Look at all actions to make sure we used them all
132 for action in self.actions.itervalues():
133 if not action.used:
134 error_msg = "Unused action: %s" % action.ident
135 if "desc" in action:
136 error_msg += ", " + action.desc
137 action.warning(error_msg)
138 self.table = table
139
140 def writeCodeFiles(self, path):
141 self.printControllerPython(path)
142 self.printControllerHH(path)
143 self.printControllerCC(path)
144 self.printCSwitch(path)
145 self.printCWakeup(path)
146 self.printProfilerCC(path)
147 self.printProfilerHH(path)
148 self.printProfileDumperCC(path)
149 self.printProfileDumperHH(path)
150
151 for func in self.functions:
152 func.writeCodeFiles(path)
153
154 def printControllerPython(self, path):
155 code = self.symtab.codeFormatter()
156 ident = self.ident
157 py_ident = "%s_Controller" % ident
158 c_ident = "%s_Controller" % self.ident
159 code('''
160from m5.params import *
161from m5.SimObject import SimObject
162from Controller import RubyController
163
164class $py_ident(RubyController):
165 type = '$py_ident'
166''')
167 code.indent()
168 for param in self.config_parameters:
169 dflt_str = ''
170 if param.default is not None:
171 dflt_str = str(param.default) + ', '
172 if python_class_map.has_key(param.type_ast.type.c_ident):
173 python_type = python_class_map[param.type_ast.type.c_ident]
174 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
175 else:
176 self.error("Unknown c++ to python class conversion for c++ " \
177 "type: '%s'. Please update the python_class_map " \
178 "in StateMachine.py", param.type_ast.type.c_ident)
179 code.dedent()
180 code.write(path, '%s.py' % py_ident)
181
182
183 def printControllerHH(self, path):
184 '''Output the method declarations for the class declaration'''
185 code = self.symtab.codeFormatter()
186 ident = self.ident
187 c_ident = "%s_Controller" % self.ident
188
189 self.message_buffer_names = []
190
191 code('''
192/** \\file $c_ident.hh
193 *
194 * Auto generated C++ code started by $__file__:$__line__
195 * Created by slicc definition of Module "${{self.short}}"
196 */
197
198#ifndef __${ident}_CONTROLLER_HH__
199#define __${ident}_CONTROLLER_HH__
200
201#include <iostream>
202#include <sstream>
203#include <string>
204
205#include "params/$c_ident.hh"
206
207#include "mem/ruby/common/Global.hh"
208#include "mem/ruby/common/Consumer.hh"
209#include "mem/ruby/slicc_interface/AbstractController.hh"
210#include "mem/protocol/TransitionResult.hh"
211#include "mem/protocol/Types.hh"
212#include "mem/protocol/${ident}_Profiler.hh"
213#include "mem/protocol/${ident}_ProfileDumper.hh"
214''')
215
216 seen_types = set()
217 for var in self.objects:
218 if var.type.ident not in seen_types and not var.type.isPrimitive:
219 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
220 seen_types.add(var.type.ident)
221
222 # for adding information to the protocol debug trace
223 code('''
224extern std::stringstream ${ident}_transitionComment;
225
226class $c_ident : public AbstractController
227{
228// the coherence checker needs to call isBlockExclusive() and isBlockShared()
229// making the Chip a friend class is an easy way to do this for now
230
231public:
232 typedef ${c_ident}Params Params;
233 $c_ident(const Params *p);
234 static int getNumControllers();
235 void init();
236 MessageBuffer* getMandatoryQueue() const;
237 const int & getVersion() const;
238 const std::string toString() const;
239 const std::string getName() const;
240 const MachineType getMachineType() const;
241 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
242 void print(std::ostream& out) const;
243 void printConfig(std::ostream& out) const;
244 void wakeup();
245 void printStats(std::ostream& out) const;
246 void clearStats();
247 void blockOnQueue(Address addr, MessageBuffer* port);
248 void unblock(Address addr);
249
250private:
251''')
252
253 code.indent()
254 # added by SS
255 for param in self.config_parameters:
256 if param.pointer:
257 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
258 else:
259 code('${{param.type_ast.type}} m_${{param.ident}};')
260
261 code('''
262int m_number_of_TBEs;
263
264TransitionResult doTransition(${ident}_Event event,
265 ${ident}_State state,
266 const Address& addr);
267
268TransitionResult doTransitionWorker(${ident}_Event event,
269 ${ident}_State state,
270 ${ident}_State& next_state,
271 const Address& addr);
272
273std::string m_name;
274int m_transitions_per_cycle;
275int m_buffer_size;
276int m_recycle_latency;
277std::map<std::string, std::string> m_cfg;
278NodeID m_version;
279Network* m_net_ptr;
280MachineID m_machineID;
281bool m_is_blocking;
282std::map<Address, MessageBuffer*> m_block_map;
283static ${ident}_ProfileDumper s_profileDumper;
284${ident}_Profiler m_profiler;
285static int m_num_controllers;
286
287// Internal functions
288''')
289
290 for func in self.functions:
291 proto = func.prototype
292 if proto:
293 code('$proto')
294
295 code('''
296
297// Actions
298''')
299 for action in self.actions.itervalues():
300 code('/** \\brief ${{action.desc}} */')
301 code('void ${{action.ident}}(const Address& addr);')
302
303 # the controller internal variables
304 code('''
305
306// Objects
307''')
308 for var in self.objects:
309 th = var.get("template_hack", "")
310 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
311
312 if var.type.ident == "MessageBuffer":
313 self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
314
315 code.dedent()
316 code('};')
317 code('#endif // __${ident}_CONTROLLER_H__')
318 code.write(path, '%s.hh' % c_ident)
319
320 def printControllerCC(self, path):
321 '''Output the actions for performing the actions'''
322
323 code = self.symtab.codeFormatter()
324 ident = self.ident
325 c_ident = "%s_Controller" % self.ident
326
327 code('''
328/** \\file $c_ident.cc
329 *
330 * Auto generated C++ code started by $__file__:$__line__
331 * Created by slicc definition of Module "${{self.short}}"
332 */
333
334#include <sstream>
335#include <string>
336
337#include "base/cprintf.hh"
338#include "mem/protocol/${ident}_Controller.hh"
339#include "mem/protocol/${ident}_State.hh"
340#include "mem/protocol/${ident}_Event.hh"
341#include "mem/protocol/Types.hh"
342#include "mem/ruby/common/Global.hh"
343#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
344#include "mem/ruby/system/System.hh"
345
346using namespace std;
347''')
348
349 # include object classes
350 seen_types = set()
351 for var in self.objects:
352 if var.type.ident not in seen_types and not var.type.isPrimitive:
353 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
354 seen_types.add(var.type.ident)
355
356 code('''
357$c_ident *
358${c_ident}Params::create()
359{
360 return new $c_ident(this);
361}
362
363int $c_ident::m_num_controllers = 0;
364${ident}_ProfileDumper $c_ident::s_profileDumper;
365
366// for adding information to the protocol debug trace
367stringstream ${ident}_transitionComment;
368#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
369
370/** \\brief constructor */
371$c_ident::$c_ident(const Params *p)
372 : AbstractController(p)
373{
374 m_version = p->version;
375 m_transitions_per_cycle = p->transitions_per_cycle;
376 m_buffer_size = p->buffer_size;
377 m_recycle_latency = p->recycle_latency;
378 m_number_of_TBEs = p->number_of_TBEs;
379 m_is_blocking = false;
380''')
381 code.indent()
382
383 #
384 # After initializing the universal machine parameters, initialize the
385 # this machines config parameters. Also detemine if these configuration
386 # params include a sequencer. This information will be used later for
387 # contecting the sequencer back to the L1 cache controller.
388 #
389 contains_sequencer = False
390 for param in self.config_parameters:
391 if param.name == "sequencer" or param.name == "dma_sequencer":
392 contains_sequencer = True
393 if param.pointer:
394 code('m_${{param.name}}_ptr = p->${{param.name}};')
395 else:
396 code('m_${{param.name}} = p->${{param.name}};')
397
398 #
399 # For the l1 cache controller, add the special atomic support which
400 # includes passing the sequencer a pointer to the controller.
401 #
402 if self.ident == "L1Cache":
403 if not contains_sequencer:
404 self.error("The L1Cache controller must include the sequencer " \
405 "configuration parameter")
406
407 code('''
408m_sequencer_ptr->setController(this);
409''')
410 #
411 # For the DMA controller, pass the sequencer a pointer to the
412 # controller.
413 #
414 if self.ident == "DMA":
415 if not contains_sequencer:
416 self.error("The DMA controller must include the sequencer " \
417 "configuration parameter")
418
419 code('''
420m_dma_sequencer_ptr->setController(this);
421''')
422
423 code('m_num_controllers++;')
424 for var in self.objects:
425 if var.ident.find("mandatoryQueue") >= 0:
426 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
427
428 code.dedent()
429 code('''
430}
431
432void
433$c_ident::init()
434{
435 MachineType machine_type;
436 int base;
437
438 m_machineID.type = MachineType_${ident};
439 m_machineID.num = m_version;
440
441 // initialize objects
442 m_profiler.setVersion(m_version);
443 s_profileDumper.registerProfiler(&m_profiler);
444
445''')
446
447 code.indent()
448 for var in self.objects:
449 vtype = var.type
450 vid = "m_%s_ptr" % var.c_ident
451 if "network" not in var:
452 # Not a network port object
453 if "primitive" in vtype:
454 code('$vid = new ${{vtype.c_ident}};')
455 if "default" in var:
456 code('(*$vid) = ${{var["default"]}};')
457 else:
458 # Normal Object
459 # added by SS
460 if "factory" in var:
461 code('$vid = ${{var["factory"]}};')
462 elif var.ident.find("mandatoryQueue") < 0:
463 th = var.get("template_hack", "")
464 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
465
466 args = ""
467 if "non_obj" not in vtype and not vtype.isEnumeration:
468 if expr.find("TBETable") >= 0:
469 args = "m_number_of_TBEs"
470 else:
471 args = var.get("constructor_hack", "")
472
473 code('$expr($args);')
474
475 code('assert($vid != NULL);')
476
477 if "default" in var:
478 code('*$vid = ${{var["default"]}}; // Object default')
479 elif "default" in vtype:
480 comment = "Type %s default" % vtype.ident
481 code('*$vid = ${{vtype["default"]}}; // $comment')
482
483 # Set ordering
484 if "ordered" in var and "trigger_queue" not in var:
485 # A buffer
486 code('$vid->setOrdering(${{var["ordered"]}});')
487
488 # Set randomization
489 if "random" in var:
490 # A buffer
491 code('$vid->setRandomization(${{var["random"]}});')
492
493 # Set Priority
494 if vtype.isBuffer and \
495 "rank" in var and "trigger_queue" not in var:
496 code('$vid->setPriority(${{var["rank"]}});')
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
33
34python_class_map = {"int": "Int",
35 "std::string": "String",
36 "bool": "Bool",
37 "CacheMemory": "RubyCache",
38 "Sequencer": "RubySequencer",
39 "DirectoryMemory": "RubyDirectoryMemory",
40 "MemoryControl": "RubyMemoryControl",
41 "DMASequencer": "DMASequencer"
42 }
43
44class StateMachine(Symbol):
45 def __init__(self, symtab, ident, location, pairs, config_parameters):
46 super(StateMachine, self).__init__(symtab, ident, location, pairs)
47 self.table = None
48 self.config_parameters = config_parameters
49 for param in config_parameters:
50 if param.pointer:
51 var = Var(symtab, param.name, location, param.type_ast.type,
52 "(*m_%s_ptr)" % param.name, {}, self)
53 else:
54 var = Var(symtab, param.name, location, param.type_ast.type,
55 "m_%s" % param.name, {}, self)
56 self.symtab.registerSym(param.name, var)
57
58 self.states = orderdict()
59 self.events = orderdict()
60 self.actions = orderdict()
61 self.transitions = []
62 self.in_ports = []
63 self.functions = []
64 self.objects = []
65
66 self.message_buffer_names = []
67
68 def __repr__(self):
69 return "[StateMachine: %s]" % self.ident
70
71 def addState(self, state):
72 assert self.table is None
73 self.states[state.ident] = state
74
75 def addEvent(self, event):
76 assert self.table is None
77 self.events[event.ident] = event
78
79 def addAction(self, action):
80 assert self.table is None
81
82 # Check for duplicate action
83 for other in self.actions.itervalues():
84 if action.ident == other.ident:
85 action.warning("Duplicate action definition: %s" % action.ident)
86 action.error("Duplicate action definition: %s" % action.ident)
87 if action.short == other.short:
88 other.warning("Duplicate action shorthand: %s" % other.ident)
89 other.warning(" shorthand = %s" % other.short)
90 action.warning("Duplicate action shorthand: %s" % action.ident)
91 action.error(" shorthand = %s" % action.short)
92
93 self.actions[action.ident] = action
94
95 def addTransition(self, trans):
96 assert self.table is None
97 self.transitions.append(trans)
98
99 def addInPort(self, var):
100 self.in_ports.append(var)
101
102 def addFunc(self, func):
103 # register func in the symbol table
104 self.symtab.registerSym(str(func), func)
105 self.functions.append(func)
106
107 def addObject(self, obj):
108 self.objects.append(obj)
109
110 # Needs to be called before accessing the table
111 def buildTable(self):
112 assert self.table is None
113
114 table = {}
115
116 for trans in self.transitions:
117 # Track which actions we touch so we know if we use them
118 # all -- really this should be done for all symbols as
119 # part of the symbol table, then only trigger it for
120 # Actions, States, Events, etc.
121
122 for action in trans.actions:
123 action.used = True
124
125 index = (trans.state, trans.event)
126 if index in table:
127 table[index].warning("Duplicate transition: %s" % table[index])
128 trans.error("Duplicate transition: %s" % trans)
129 table[index] = trans
130
131 # Look at all actions to make sure we used them all
132 for action in self.actions.itervalues():
133 if not action.used:
134 error_msg = "Unused action: %s" % action.ident
135 if "desc" in action:
136 error_msg += ", " + action.desc
137 action.warning(error_msg)
138 self.table = table
139
140 def writeCodeFiles(self, path):
141 self.printControllerPython(path)
142 self.printControllerHH(path)
143 self.printControllerCC(path)
144 self.printCSwitch(path)
145 self.printCWakeup(path)
146 self.printProfilerCC(path)
147 self.printProfilerHH(path)
148 self.printProfileDumperCC(path)
149 self.printProfileDumperHH(path)
150
151 for func in self.functions:
152 func.writeCodeFiles(path)
153
154 def printControllerPython(self, path):
155 code = self.symtab.codeFormatter()
156 ident = self.ident
157 py_ident = "%s_Controller" % ident
158 c_ident = "%s_Controller" % self.ident
159 code('''
160from m5.params import *
161from m5.SimObject import SimObject
162from Controller import RubyController
163
164class $py_ident(RubyController):
165 type = '$py_ident'
166''')
167 code.indent()
168 for param in self.config_parameters:
169 dflt_str = ''
170 if param.default is not None:
171 dflt_str = str(param.default) + ', '
172 if python_class_map.has_key(param.type_ast.type.c_ident):
173 python_type = python_class_map[param.type_ast.type.c_ident]
174 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
175 else:
176 self.error("Unknown c++ to python class conversion for c++ " \
177 "type: '%s'. Please update the python_class_map " \
178 "in StateMachine.py", param.type_ast.type.c_ident)
179 code.dedent()
180 code.write(path, '%s.py' % py_ident)
181
182
183 def printControllerHH(self, path):
184 '''Output the method declarations for the class declaration'''
185 code = self.symtab.codeFormatter()
186 ident = self.ident
187 c_ident = "%s_Controller" % self.ident
188
189 self.message_buffer_names = []
190
191 code('''
192/** \\file $c_ident.hh
193 *
194 * Auto generated C++ code started by $__file__:$__line__
195 * Created by slicc definition of Module "${{self.short}}"
196 */
197
198#ifndef __${ident}_CONTROLLER_HH__
199#define __${ident}_CONTROLLER_HH__
200
201#include <iostream>
202#include <sstream>
203#include <string>
204
205#include "params/$c_ident.hh"
206
207#include "mem/ruby/common/Global.hh"
208#include "mem/ruby/common/Consumer.hh"
209#include "mem/ruby/slicc_interface/AbstractController.hh"
210#include "mem/protocol/TransitionResult.hh"
211#include "mem/protocol/Types.hh"
212#include "mem/protocol/${ident}_Profiler.hh"
213#include "mem/protocol/${ident}_ProfileDumper.hh"
214''')
215
216 seen_types = set()
217 for var in self.objects:
218 if var.type.ident not in seen_types and not var.type.isPrimitive:
219 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
220 seen_types.add(var.type.ident)
221
222 # for adding information to the protocol debug trace
223 code('''
224extern std::stringstream ${ident}_transitionComment;
225
226class $c_ident : public AbstractController
227{
228// the coherence checker needs to call isBlockExclusive() and isBlockShared()
229// making the Chip a friend class is an easy way to do this for now
230
231public:
232 typedef ${c_ident}Params Params;
233 $c_ident(const Params *p);
234 static int getNumControllers();
235 void init();
236 MessageBuffer* getMandatoryQueue() const;
237 const int & getVersion() const;
238 const std::string toString() const;
239 const std::string getName() const;
240 const MachineType getMachineType() const;
241 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
242 void print(std::ostream& out) const;
243 void printConfig(std::ostream& out) const;
244 void wakeup();
245 void printStats(std::ostream& out) const;
246 void clearStats();
247 void blockOnQueue(Address addr, MessageBuffer* port);
248 void unblock(Address addr);
249
250private:
251''')
252
253 code.indent()
254 # added by SS
255 for param in self.config_parameters:
256 if param.pointer:
257 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
258 else:
259 code('${{param.type_ast.type}} m_${{param.ident}};')
260
261 code('''
262int m_number_of_TBEs;
263
264TransitionResult doTransition(${ident}_Event event,
265 ${ident}_State state,
266 const Address& addr);
267
268TransitionResult doTransitionWorker(${ident}_Event event,
269 ${ident}_State state,
270 ${ident}_State& next_state,
271 const Address& addr);
272
273std::string m_name;
274int m_transitions_per_cycle;
275int m_buffer_size;
276int m_recycle_latency;
277std::map<std::string, std::string> m_cfg;
278NodeID m_version;
279Network* m_net_ptr;
280MachineID m_machineID;
281bool m_is_blocking;
282std::map<Address, MessageBuffer*> m_block_map;
283static ${ident}_ProfileDumper s_profileDumper;
284${ident}_Profiler m_profiler;
285static int m_num_controllers;
286
287// Internal functions
288''')
289
290 for func in self.functions:
291 proto = func.prototype
292 if proto:
293 code('$proto')
294
295 code('''
296
297// Actions
298''')
299 for action in self.actions.itervalues():
300 code('/** \\brief ${{action.desc}} */')
301 code('void ${{action.ident}}(const Address& addr);')
302
303 # the controller internal variables
304 code('''
305
306// Objects
307''')
308 for var in self.objects:
309 th = var.get("template_hack", "")
310 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
311
312 if var.type.ident == "MessageBuffer":
313 self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
314
315 code.dedent()
316 code('};')
317 code('#endif // __${ident}_CONTROLLER_H__')
318 code.write(path, '%s.hh' % c_ident)
319
320 def printControllerCC(self, path):
321 '''Output the actions for performing the actions'''
322
323 code = self.symtab.codeFormatter()
324 ident = self.ident
325 c_ident = "%s_Controller" % self.ident
326
327 code('''
328/** \\file $c_ident.cc
329 *
330 * Auto generated C++ code started by $__file__:$__line__
331 * Created by slicc definition of Module "${{self.short}}"
332 */
333
334#include <sstream>
335#include <string>
336
337#include "base/cprintf.hh"
338#include "mem/protocol/${ident}_Controller.hh"
339#include "mem/protocol/${ident}_State.hh"
340#include "mem/protocol/${ident}_Event.hh"
341#include "mem/protocol/Types.hh"
342#include "mem/ruby/common/Global.hh"
343#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
344#include "mem/ruby/system/System.hh"
345
346using namespace std;
347''')
348
349 # include object classes
350 seen_types = set()
351 for var in self.objects:
352 if var.type.ident not in seen_types and not var.type.isPrimitive:
353 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
354 seen_types.add(var.type.ident)
355
356 code('''
357$c_ident *
358${c_ident}Params::create()
359{
360 return new $c_ident(this);
361}
362
363int $c_ident::m_num_controllers = 0;
364${ident}_ProfileDumper $c_ident::s_profileDumper;
365
366// for adding information to the protocol debug trace
367stringstream ${ident}_transitionComment;
368#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
369
370/** \\brief constructor */
371$c_ident::$c_ident(const Params *p)
372 : AbstractController(p)
373{
374 m_version = p->version;
375 m_transitions_per_cycle = p->transitions_per_cycle;
376 m_buffer_size = p->buffer_size;
377 m_recycle_latency = p->recycle_latency;
378 m_number_of_TBEs = p->number_of_TBEs;
379 m_is_blocking = false;
380''')
381 code.indent()
382
383 #
384 # After initializing the universal machine parameters, initialize the
385 # this machines config parameters. Also detemine if these configuration
386 # params include a sequencer. This information will be used later for
387 # contecting the sequencer back to the L1 cache controller.
388 #
389 contains_sequencer = False
390 for param in self.config_parameters:
391 if param.name == "sequencer" or param.name == "dma_sequencer":
392 contains_sequencer = True
393 if param.pointer:
394 code('m_${{param.name}}_ptr = p->${{param.name}};')
395 else:
396 code('m_${{param.name}} = p->${{param.name}};')
397
398 #
399 # For the l1 cache controller, add the special atomic support which
400 # includes passing the sequencer a pointer to the controller.
401 #
402 if self.ident == "L1Cache":
403 if not contains_sequencer:
404 self.error("The L1Cache controller must include the sequencer " \
405 "configuration parameter")
406
407 code('''
408m_sequencer_ptr->setController(this);
409''')
410 #
411 # For the DMA controller, pass the sequencer a pointer to the
412 # controller.
413 #
414 if self.ident == "DMA":
415 if not contains_sequencer:
416 self.error("The DMA controller must include the sequencer " \
417 "configuration parameter")
418
419 code('''
420m_dma_sequencer_ptr->setController(this);
421''')
422
423 code('m_num_controllers++;')
424 for var in self.objects:
425 if var.ident.find("mandatoryQueue") >= 0:
426 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
427
428 code.dedent()
429 code('''
430}
431
432void
433$c_ident::init()
434{
435 MachineType machine_type;
436 int base;
437
438 m_machineID.type = MachineType_${ident};
439 m_machineID.num = m_version;
440
441 // initialize objects
442 m_profiler.setVersion(m_version);
443 s_profileDumper.registerProfiler(&m_profiler);
444
445''')
446
447 code.indent()
448 for var in self.objects:
449 vtype = var.type
450 vid = "m_%s_ptr" % var.c_ident
451 if "network" not in var:
452 # Not a network port object
453 if "primitive" in vtype:
454 code('$vid = new ${{vtype.c_ident}};')
455 if "default" in var:
456 code('(*$vid) = ${{var["default"]}};')
457 else:
458 # Normal Object
459 # added by SS
460 if "factory" in var:
461 code('$vid = ${{var["factory"]}};')
462 elif var.ident.find("mandatoryQueue") < 0:
463 th = var.get("template_hack", "")
464 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
465
466 args = ""
467 if "non_obj" not in vtype and not vtype.isEnumeration:
468 if expr.find("TBETable") >= 0:
469 args = "m_number_of_TBEs"
470 else:
471 args = var.get("constructor_hack", "")
472
473 code('$expr($args);')
474
475 code('assert($vid != NULL);')
476
477 if "default" in var:
478 code('*$vid = ${{var["default"]}}; // Object default')
479 elif "default" in vtype:
480 comment = "Type %s default" % vtype.ident
481 code('*$vid = ${{vtype["default"]}}; // $comment')
482
483 # Set ordering
484 if "ordered" in var and "trigger_queue" not in var:
485 # A buffer
486 code('$vid->setOrdering(${{var["ordered"]}});')
487
488 # Set randomization
489 if "random" in var:
490 # A buffer
491 code('$vid->setRandomization(${{var["random"]}});')
492
493 # Set Priority
494 if vtype.isBuffer and \
495 "rank" in var and "trigger_queue" not in var:
496 code('$vid->setPriority(${{var["rank"]}});')
497
497 else:
498 # Network port object
499 network = var["network"]
500 ordered = var["ordered"]
501 vnet = var["virtual_network"]
502
503 assert var.machine is not None
504 code('''
505machine_type = string_to_MachineType("${{var.machine.ident}}");
506base = MachineType_base_number(machine_type);
507$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
508''')
509
510 code('assert($vid != NULL);')
511
512 # Set ordering
513 if "ordered" in var:
514 # A buffer
515 code('$vid->setOrdering(${{var["ordered"]}});')
516
517 # Set randomization
518 if "random" in var:
519 # A buffer
520 code('$vid->setRandomization(${{var["random"]}})')
521
522 # Set Priority
523 if "rank" in var:
524 code('$vid->setPriority(${{var["rank"]}})')
525
526 # Set buffer size
527 if vtype.isBuffer:
528 code('''
529if (m_buffer_size > 0) {
530 $vid->resize(m_buffer_size);
531}
532''')
533
534 # set description (may be overriden later by port def)
535 code('''
536$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
537
538''')
539
498 else:
499 # Network port object
500 network = var["network"]
501 ordered = var["ordered"]
502 vnet = var["virtual_network"]
503
504 assert var.machine is not None
505 code('''
506machine_type = string_to_MachineType("${{var.machine.ident}}");
507base = MachineType_base_number(machine_type);
508$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
509''')
510
511 code('assert($vid != NULL);')
512
513 # Set ordering
514 if "ordered" in var:
515 # A buffer
516 code('$vid->setOrdering(${{var["ordered"]}});')
517
518 # Set randomization
519 if "random" in var:
520 # A buffer
521 code('$vid->setRandomization(${{var["random"]}})')
522
523 # Set Priority
524 if "rank" in var:
525 code('$vid->setPriority(${{var["rank"]}})')
526
527 # Set buffer size
528 if vtype.isBuffer:
529 code('''
530if (m_buffer_size > 0) {
531 $vid->resize(m_buffer_size);
532}
533''')
534
535 # set description (may be overriden later by port def)
536 code('''
537$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
538
539''')
540
541 if vtype.isBuffer:
542 if "recycle_latency" in var:
543 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
544 else:
545 code('$vid->setRecycleLatency(m_recycle_latency);')
546
547
540 # Set the queue consumers
541 code.insert_newline()
542 for port in self.in_ports:
543 code('${{port.code}}.setConsumer(this);')
544
545 # Set the queue descriptions
546 code.insert_newline()
547 for port in self.in_ports:
548 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
549
550 # Initialize the transition profiling
551 code.insert_newline()
552 for trans in self.transitions:
553 # Figure out if we stall
554 stall = False
555 for action in trans.actions:
556 if action.ident == "z_stall":
557 stall = True
558
559 # Only possible if it is not a 'z' case
560 if not stall:
561 state = "%s_State_%s" % (self.ident, trans.state.ident)
562 event = "%s_Event_%s" % (self.ident, trans.event.ident)
563 code('m_profiler.possibleTransition($state, $event);')
564
548 # Set the queue consumers
549 code.insert_newline()
550 for port in self.in_ports:
551 code('${{port.code}}.setConsumer(this);')
552
553 # Set the queue descriptions
554 code.insert_newline()
555 for port in self.in_ports:
556 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
557
558 # Initialize the transition profiling
559 code.insert_newline()
560 for trans in self.transitions:
561 # Figure out if we stall
562 stall = False
563 for action in trans.actions:
564 if action.ident == "z_stall":
565 stall = True
566
567 # Only possible if it is not a 'z' case
568 if not stall:
569 state = "%s_State_%s" % (self.ident, trans.state.ident)
570 event = "%s_Event_%s" % (self.ident, trans.event.ident)
571 code('m_profiler.possibleTransition($state, $event);')
572
565 # added by SS to initialize recycle_latency of message buffers
566 for buf in self.message_buffer_names:
567 code("$buf->setRecycleLatency(m_recycle_latency);")
568
569 code.dedent()
570 code('}')
571
572 has_mandatory_q = False
573 for port in self.in_ports:
574 if port.code.find("mandatoryQueue_ptr") >= 0:
575 has_mandatory_q = True
576
577 if has_mandatory_q:
578 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
579 else:
580 mq_ident = "NULL"
581
582 code('''
583int
584$c_ident::getNumControllers()
585{
586 return m_num_controllers;
587}
588
589MessageBuffer*
590$c_ident::getMandatoryQueue() const
591{
592 return $mq_ident;
593}
594
595const int &
596$c_ident::getVersion() const
597{
598 return m_version;
599}
600
601const string
602$c_ident::toString() const
603{
604 return "$c_ident";
605}
606
607const string
608$c_ident::getName() const
609{
610 return m_name;
611}
612
613const MachineType
614$c_ident::getMachineType() const
615{
616 return MachineType_${ident};
617}
618
619void
620$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
621{
622 m_is_blocking = true;
623 m_block_map[addr] = port;
624}
625
626void
627$c_ident::unblock(Address addr)
628{
629 m_block_map.erase(addr);
630 if (m_block_map.size() == 0) {
631 m_is_blocking = false;
632 }
633}
634
635void
636$c_ident::print(ostream& out) const
637{
638 out << "[$c_ident " << m_version << "]";
639}
640
641void
642$c_ident::printConfig(ostream& out) const
643{
644 out << "$c_ident config: " << m_name << endl;
645 out << " version: " << m_version << endl;
646 map<string, string>::const_iterator it;
647 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
648 out << " " << it->first << ": " << it->second << endl;
649}
650
651void
652$c_ident::printStats(ostream& out) const
653{
654''')
655 #
656 # Cache and Memory Controllers have specific profilers associated with
657 # them. Print out these stats before dumping state transition stats.
658 #
659 for param in self.config_parameters:
660 if param.type_ast.type.ident == "CacheMemory" or \
661 param.type_ast.type.ident == "DirectoryMemory" or \
662 param.type_ast.type.ident == "MemoryControl":
663 assert(param.pointer)
664 code(' m_${{param.ident}}_ptr->printStats(out);')
665
666 code('''
667 if (m_version == 0) {
668 s_profileDumper.dumpStats(out);
669 }
670}
671
672void $c_ident::clearStats() {
673''')
674 #
675 # Cache and Memory Controllers have specific profilers associated with
676 # them. These stats must be cleared too.
677 #
678 for param in self.config_parameters:
679 if param.type_ast.type.ident == "CacheMemory" or \
680 param.type_ast.type.ident == "MemoryControl":
681 assert(param.pointer)
682 code(' m_${{param.ident}}_ptr->clearStats();')
683
684 code('''
685 m_profiler.clearStats();
686}
687
688// Actions
689''')
690
691 for action in self.actions.itervalues():
692 if "c_code" not in action:
693 continue
694
695 code('''
696/** \\brief ${{action.desc}} */
697void
698$c_ident::${{action.ident}}(const Address& addr)
699{
700 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
701 ${{action["c_code"]}}
702}
703
704''')
705 code.write(path, "%s.cc" % c_ident)
706
707 def printCWakeup(self, path):
708 '''Output the wakeup loop for the events'''
709
710 code = self.symtab.codeFormatter()
711 ident = self.ident
712
713 code('''
714// Auto generated C++ code started by $__file__:$__line__
715// ${ident}: ${{self.short}}
716
717#include "base/misc.hh"
718#include "mem/ruby/common/Global.hh"
719#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
720#include "mem/protocol/${ident}_Controller.hh"
721#include "mem/protocol/${ident}_State.hh"
722#include "mem/protocol/${ident}_Event.hh"
723#include "mem/protocol/Types.hh"
724#include "mem/ruby/system/System.hh"
725
726using namespace std;
727
728void
729${ident}_Controller::wakeup()
730{
731 // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this);
732 // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
733
734 int counter = 0;
735 while (true) {
736 // Some cases will put us into an infinite loop without this limit
737 assert(counter <= m_transitions_per_cycle);
738 if (counter == m_transitions_per_cycle) {
739 // Count how often we are fully utilized
740 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
741
742 // Wakeup in another cycle and try again
743 g_eventQueue_ptr->scheduleEvent(this, 1);
744 break;
745 }
746''')
747
748 code.indent()
749 code.indent()
750
751 # InPorts
752 #
753 for port in self.in_ports:
754 code.indent()
755 code('// ${ident}InPort $port')
756 code('${{port["c_code_in_port"]}}')
757 code.dedent()
758
759 code('')
760
761 code.dedent()
762 code.dedent()
763 code('''
764 break; // If we got this far, we have nothing left todo
765 }
766 // g_eventQueue_ptr->scheduleEvent(this, 1);
767 // DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
768}
769''')
770
771 code.write(path, "%s_Wakeup.cc" % self.ident)
772
773 def printCSwitch(self, path):
774 '''Output switch statement for transition table'''
775
776 code = self.symtab.codeFormatter()
777 ident = self.ident
778
779 code('''
780// Auto generated C++ code started by $__file__:$__line__
781// ${ident}: ${{self.short}}
782
783#include "mem/ruby/common/Global.hh"
784#include "mem/protocol/${ident}_Controller.hh"
785#include "mem/protocol/${ident}_State.hh"
786#include "mem/protocol/${ident}_Event.hh"
787#include "mem/protocol/Types.hh"
788#include "mem/ruby/system/System.hh"
789
790#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
791
792#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
793#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
794
795TransitionResult
796${ident}_Controller::doTransition(${ident}_Event event,
797 ${ident}_State state,
798 const Address &addr)
799{
800 ${ident}_State next_state = state;
801
802 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
803 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
804 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
805 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
806 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
807 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
808
809 TransitionResult result =
810 doTransitionWorker(event, state, next_state, addr);
811
812 if (result == TransitionResult_Valid) {
813 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
814 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
815 m_profiler.countTransition(state, event);
816 if (Debug::getProtocolTrace()) {
817 g_system_ptr->getProfiler()->profileTransition("${ident}",
818 m_version, addr,
819 ${ident}_State_to_string(state),
820 ${ident}_Event_to_string(event),
821 ${ident}_State_to_string(next_state),
822 GET_TRANSITION_COMMENT());
823 }
824 CLEAR_TRANSITION_COMMENT();
825 ${ident}_setState(addr, next_state);
826
827 } else if (result == TransitionResult_ResourceStall) {
828 if (Debug::getProtocolTrace()) {
829 g_system_ptr->getProfiler()->profileTransition("${ident}",
830 m_version, addr,
831 ${ident}_State_to_string(state),
832 ${ident}_Event_to_string(event),
833 ${ident}_State_to_string(next_state),
834 "Resource Stall");
835 }
836 } else if (result == TransitionResult_ProtocolStall) {
837 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
838 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
839 if (Debug::getProtocolTrace()) {
840 g_system_ptr->getProfiler()->profileTransition("${ident}",
841 m_version, addr,
842 ${ident}_State_to_string(state),
843 ${ident}_Event_to_string(event),
844 ${ident}_State_to_string(next_state),
845 "Protocol Stall");
846 }
847 }
848
849 return result;
850}
851
852TransitionResult
853${ident}_Controller::doTransitionWorker(${ident}_Event event,
854 ${ident}_State state,
855 ${ident}_State& next_state,
856 const Address& addr)
857{
858 switch(HASH_FUN(state, event)) {
859''')
860
861 # This map will allow suppress generating duplicate code
862 cases = orderdict()
863
864 for trans in self.transitions:
865 case_string = "%s_State_%s, %s_Event_%s" % \
866 (self.ident, trans.state.ident, self.ident, trans.event.ident)
867
868 case = self.symtab.codeFormatter()
869 # Only set next_state if it changes
870 if trans.state != trans.nextState:
871 ns_ident = trans.nextState.ident
872 case('next_state = ${ident}_State_${ns_ident};')
873
874 actions = trans.actions
875
876 # Check for resources
877 case_sorter = []
878 res = trans.resources
879 for key,val in res.iteritems():
880 if key.type.ident != "DNUCAStopTable":
881 val = '''
882if (!%s.areNSlotsAvailable(%s))
883 return TransitionResult_ResourceStall;
884''' % (key.code, val)
885 case_sorter.append(val)
886
887
888 # Emit the code sequences in a sorted order. This makes the
889 # output deterministic (without this the output order can vary
890 # since Map's keys() on a vector of pointers is not deterministic
891 for c in sorted(case_sorter):
892 case("$c")
893
894 # Figure out if we stall
895 stall = False
896 for action in actions:
897 if action.ident == "z_stall":
898 stall = True
899 break
900
901 if stall:
902 case('return TransitionResult_ProtocolStall;')
903 else:
904 for action in actions:
905 case('${{action.ident}}(addr);')
906 case('return TransitionResult_Valid;')
907
908 case = str(case)
909
910 # Look to see if this transition code is unique.
911 if case not in cases:
912 cases[case] = []
913
914 cases[case].append(case_string)
915
916 # Walk through all of the unique code blocks and spit out the
917 # corresponding case statement elements
918 for case,transitions in cases.iteritems():
919 # Iterative over all the multiple transitions that share
920 # the same code
921 for trans in transitions:
922 code(' case HASH_FUN($trans):')
923 code(' $case')
924
925 code('''
926 default:
927 WARN_EXPR(m_version);
928 WARN_EXPR(g_eventQueue_ptr->getTime());
929 WARN_EXPR(addr);
930 WARN_EXPR(event);
931 WARN_EXPR(state);
932 ERROR_MSG(\"Invalid transition\");
933 }
934 return TransitionResult_Valid;
935}
936''')
937 code.write(path, "%s_Transitions.cc" % self.ident)
938
939 def printProfileDumperHH(self, path):
940 code = self.symtab.codeFormatter()
941 ident = self.ident
942
943 code('''
944// Auto generated C++ code started by $__file__:$__line__
945// ${ident}: ${{self.short}}
946
947#ifndef __${ident}_PROFILE_DUMPER_HH__
948#define __${ident}_PROFILE_DUMPER_HH__
949
950#include <iostream>
951#include <vector>
952
953#include "${ident}_Profiler.hh"
954#include "${ident}_Event.hh"
955
956typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
957
958class ${ident}_ProfileDumper
959{
960 public:
961 ${ident}_ProfileDumper();
962 void registerProfiler(${ident}_Profiler* profiler);
963 void dumpStats(std::ostream& out) const;
964
965 private:
966 ${ident}_profilers m_profilers;
967};
968
969#endif // __${ident}_PROFILE_DUMPER_HH__
970''')
971 code.write(path, "%s_ProfileDumper.hh" % self.ident)
972
973 def printProfileDumperCC(self, path):
974 code = self.symtab.codeFormatter()
975 ident = self.ident
976
977 code('''
978// Auto generated C++ code started by $__file__:$__line__
979// ${ident}: ${{self.short}}
980
981#include "mem/protocol/${ident}_ProfileDumper.hh"
982
983${ident}_ProfileDumper::${ident}_ProfileDumper()
984{
985}
986
987void
988${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
989{
990 m_profilers.push_back(profiler);
991}
992
993void
994${ident}_ProfileDumper::dumpStats(std::ostream& out) const
995{
996 out << " --- ${ident} ---\\n";
997 out << " - Event Counts -\\n";
998 for (${ident}_Event event = ${ident}_Event_FIRST;
999 event < ${ident}_Event_NUM;
1000 ++event) {
1001 out << (${ident}_Event) event << " [";
1002 uint64 total = 0;
1003 for (int i = 0; i < m_profilers.size(); i++) {
1004 out << m_profilers[i]->getEventCount(event) << " ";
1005 total += m_profilers[i]->getEventCount(event);
1006 }
1007 out << "] " << total << "\\n";
1008 }
1009 out << "\\n";
1010 out << " - Transitions -\\n";
1011 for (${ident}_State state = ${ident}_State_FIRST;
1012 state < ${ident}_State_NUM;
1013 ++state) {
1014 for (${ident}_Event event = ${ident}_Event_FIRST;
1015 event < ${ident}_Event_NUM;
1016 ++event) {
1017 if (m_profilers[0]->isPossible(state, event)) {
1018 out << (${ident}_State) state << " "
1019 << (${ident}_Event) event << " [";
1020 uint64 total = 0;
1021 for (int i = 0; i < m_profilers.size(); i++) {
1022 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1023 total += m_profilers[i]->getTransitionCount(state, event);
1024 }
1025 out << "] " << total << "\\n";
1026 }
1027 }
1028 out << "\\n";
1029 }
1030}
1031''')
1032 code.write(path, "%s_ProfileDumper.cc" % self.ident)
1033
1034 def printProfilerHH(self, path):
1035 code = self.symtab.codeFormatter()
1036 ident = self.ident
1037
1038 code('''
1039// Auto generated C++ code started by $__file__:$__line__
1040// ${ident}: ${{self.short}}
1041
1042#ifndef __${ident}_PROFILER_HH__
1043#define __${ident}_PROFILER_HH__
1044
1045#include <iostream>
1046
1047#include "mem/ruby/common/Global.hh"
1048#include "mem/protocol/${ident}_State.hh"
1049#include "mem/protocol/${ident}_Event.hh"
1050
1051class ${ident}_Profiler
1052{
1053 public:
1054 ${ident}_Profiler();
1055 void setVersion(int version);
1056 void countTransition(${ident}_State state, ${ident}_Event event);
1057 void possibleTransition(${ident}_State state, ${ident}_Event event);
1058 uint64 getEventCount(${ident}_Event event);
1059 bool isPossible(${ident}_State state, ${ident}_Event event);
1060 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1061 void clearStats();
1062
1063 private:
1064 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1065 int m_event_counters[${ident}_Event_NUM];
1066 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1067 int m_version;
1068};
1069
1070#endif // __${ident}_PROFILER_HH__
1071''')
1072 code.write(path, "%s_Profiler.hh" % self.ident)
1073
1074 def printProfilerCC(self, path):
1075 code = self.symtab.codeFormatter()
1076 ident = self.ident
1077
1078 code('''
1079// Auto generated C++ code started by $__file__:$__line__
1080// ${ident}: ${{self.short}}
1081
1082#include "mem/protocol/${ident}_Profiler.hh"
1083
1084${ident}_Profiler::${ident}_Profiler()
1085{
1086 for (int state = 0; state < ${ident}_State_NUM; state++) {
1087 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1088 m_possible[state][event] = false;
1089 m_counters[state][event] = 0;
1090 }
1091 }
1092 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1093 m_event_counters[event] = 0;
1094 }
1095}
1096
1097void
1098${ident}_Profiler::setVersion(int version)
1099{
1100 m_version = version;
1101}
1102
1103void
1104${ident}_Profiler::clearStats()
1105{
1106 for (int state = 0; state < ${ident}_State_NUM; state++) {
1107 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1108 m_counters[state][event] = 0;
1109 }
1110 }
1111
1112 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1113 m_event_counters[event] = 0;
1114 }
1115}
1116void
1117${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1118{
1119 assert(m_possible[state][event]);
1120 m_counters[state][event]++;
1121 m_event_counters[event]++;
1122}
1123void
1124${ident}_Profiler::possibleTransition(${ident}_State state,
1125 ${ident}_Event event)
1126{
1127 m_possible[state][event] = true;
1128}
1129
1130uint64
1131${ident}_Profiler::getEventCount(${ident}_Event event)
1132{
1133 return m_event_counters[event];
1134}
1135
1136bool
1137${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1138{
1139 return m_possible[state][event];
1140}
1141
1142uint64
1143${ident}_Profiler::getTransitionCount(${ident}_State state,
1144 ${ident}_Event event)
1145{
1146 return m_counters[state][event];
1147}
1148
1149''')
1150 code.write(path, "%s_Profiler.cc" % self.ident)
1151
1152 # **************************
1153 # ******* HTML Files *******
1154 # **************************
1155 def frameRef(self, click_href, click_target, over_href, over_num, text):
1156 code = self.symtab.codeFormatter(fix_newlines=False)
1157 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1158 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1159 parent.frames[$over_num].location='$over_href'
1160 }\">
1161 ${{html.formatShorthand(text)}}
1162 </A>""")
1163 return str(code)
1164
1165 def writeHTMLFiles(self, path):
1166 # Create table with no row hilighted
1167 self.printHTMLTransitions(path, None)
1168
1169 # Generate transition tables
1170 for state in self.states.itervalues():
1171 self.printHTMLTransitions(path, state)
1172
1173 # Generate action descriptions
1174 for action in self.actions.itervalues():
1175 name = "%s_action_%s.html" % (self.ident, action.ident)
1176 code = html.createSymbol(action, "Action")
1177 code.write(path, name)
1178
1179 # Generate state descriptions
1180 for state in self.states.itervalues():
1181 name = "%s_State_%s.html" % (self.ident, state.ident)
1182 code = html.createSymbol(state, "State")
1183 code.write(path, name)
1184
1185 # Generate event descriptions
1186 for event in self.events.itervalues():
1187 name = "%s_Event_%s.html" % (self.ident, event.ident)
1188 code = html.createSymbol(event, "Event")
1189 code.write(path, name)
1190
1191 def printHTMLTransitions(self, path, active_state):
1192 code = self.symtab.codeFormatter()
1193
1194 code('''
1195<HTML>
1196<BODY link="blue" vlink="blue">
1197
1198<H1 align="center">${{html.formatShorthand(self.short)}}:
1199''')
1200 code.indent()
1201 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1202 mid = machine.ident
1203 if i != 0:
1204 extra = " - "
1205 else:
1206 extra = ""
1207 if machine == self:
1208 code('$extra$mid')
1209 else:
1210 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1211 code.dedent()
1212
1213 code("""
1214</H1>
1215
1216<TABLE border=1>
1217<TR>
1218 <TH> </TH>
1219""")
1220
1221 for event in self.events.itervalues():
1222 href = "%s_Event_%s.html" % (self.ident, event.ident)
1223 ref = self.frameRef(href, "Status", href, "1", event.short)
1224 code('<TH bgcolor=white>$ref</TH>')
1225
1226 code('</TR>')
1227 # -- Body of table
1228 for state in self.states.itervalues():
1229 # -- Each row
1230 if state == active_state:
1231 color = "yellow"
1232 else:
1233 color = "white"
1234
1235 click = "%s_table_%s.html" % (self.ident, state.ident)
1236 over = "%s_State_%s.html" % (self.ident, state.ident)
1237 text = html.formatShorthand(state.short)
1238 ref = self.frameRef(click, "Table", over, "1", state.short)
1239 code('''
1240<TR>
1241 <TH bgcolor=$color>$ref</TH>
1242''')
1243
1244 # -- One column for each event
1245 for event in self.events.itervalues():
1246 trans = self.table.get((state,event), None)
1247 if trans is None:
1248 # This is the no transition case
1249 if state == active_state:
1250 color = "#C0C000"
1251 else:
1252 color = "lightgrey"
1253
1254 code('<TD bgcolor=$color>&nbsp;</TD>')
1255 continue
1256
1257 next = trans.nextState
1258 stall_action = False
1259
1260 # -- Get the actions
1261 for action in trans.actions:
1262 if action.ident == "z_stall" or \
1263 action.ident == "zz_recycleMandatoryQueue":
1264 stall_action = True
1265
1266 # -- Print out "actions/next-state"
1267 if stall_action:
1268 if state == active_state:
1269 color = "#C0C000"
1270 else:
1271 color = "lightgrey"
1272
1273 elif active_state and next.ident == active_state.ident:
1274 color = "aqua"
1275 elif state == active_state:
1276 color = "yellow"
1277 else:
1278 color = "white"
1279
1280 code('<TD bgcolor=$color>')
1281 for action in trans.actions:
1282 href = "%s_action_%s.html" % (self.ident, action.ident)
1283 ref = self.frameRef(href, "Status", href, "1",
1284 action.short)
1285 code(' $ref')
1286 if next != state:
1287 if trans.actions:
1288 code('/')
1289 click = "%s_table_%s.html" % (self.ident, next.ident)
1290 over = "%s_State_%s.html" % (self.ident, next.ident)
1291 ref = self.frameRef(click, "Table", over, "1", next.short)
1292 code("$ref")
1293 code("</TD>")
1294
1295 # -- Each row
1296 if state == active_state:
1297 color = "yellow"
1298 else:
1299 color = "white"
1300
1301 click = "%s_table_%s.html" % (self.ident, state.ident)
1302 over = "%s_State_%s.html" % (self.ident, state.ident)
1303 ref = self.frameRef(click, "Table", over, "1", state.short)
1304 code('''
1305 <TH bgcolor=$color>$ref</TH>
1306</TR>
1307''')
1308 code('''
1309<!- Column footer->
1310<TR>
1311 <TH> </TH>
1312''')
1313
1314 for event in self.events.itervalues():
1315 href = "%s_Event_%s.html" % (self.ident, event.ident)
1316 ref = self.frameRef(href, "Status", href, "1", event.short)
1317 code('<TH bgcolor=white>$ref</TH>')
1318 code('''
1319</TR>
1320</TABLE>
1321</BODY></HTML>
1322''')
1323
1324
1325 if active_state:
1326 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1327 else:
1328 name = "%s_table.html" % self.ident
1329 code.write(path, name)
1330
1331__all__ = [ "StateMachine" ]
573 code.dedent()
574 code('}')
575
576 has_mandatory_q = False
577 for port in self.in_ports:
578 if port.code.find("mandatoryQueue_ptr") >= 0:
579 has_mandatory_q = True
580
581 if has_mandatory_q:
582 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
583 else:
584 mq_ident = "NULL"
585
586 code('''
587int
588$c_ident::getNumControllers()
589{
590 return m_num_controllers;
591}
592
593MessageBuffer*
594$c_ident::getMandatoryQueue() const
595{
596 return $mq_ident;
597}
598
599const int &
600$c_ident::getVersion() const
601{
602 return m_version;
603}
604
605const string
606$c_ident::toString() const
607{
608 return "$c_ident";
609}
610
611const string
612$c_ident::getName() const
613{
614 return m_name;
615}
616
617const MachineType
618$c_ident::getMachineType() const
619{
620 return MachineType_${ident};
621}
622
623void
624$c_ident::blockOnQueue(Address addr, MessageBuffer* port)
625{
626 m_is_blocking = true;
627 m_block_map[addr] = port;
628}
629
630void
631$c_ident::unblock(Address addr)
632{
633 m_block_map.erase(addr);
634 if (m_block_map.size() == 0) {
635 m_is_blocking = false;
636 }
637}
638
639void
640$c_ident::print(ostream& out) const
641{
642 out << "[$c_ident " << m_version << "]";
643}
644
645void
646$c_ident::printConfig(ostream& out) const
647{
648 out << "$c_ident config: " << m_name << endl;
649 out << " version: " << m_version << endl;
650 map<string, string>::const_iterator it;
651 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
652 out << " " << it->first << ": " << it->second << endl;
653}
654
655void
656$c_ident::printStats(ostream& out) const
657{
658''')
659 #
660 # Cache and Memory Controllers have specific profilers associated with
661 # them. Print out these stats before dumping state transition stats.
662 #
663 for param in self.config_parameters:
664 if param.type_ast.type.ident == "CacheMemory" or \
665 param.type_ast.type.ident == "DirectoryMemory" or \
666 param.type_ast.type.ident == "MemoryControl":
667 assert(param.pointer)
668 code(' m_${{param.ident}}_ptr->printStats(out);')
669
670 code('''
671 if (m_version == 0) {
672 s_profileDumper.dumpStats(out);
673 }
674}
675
676void $c_ident::clearStats() {
677''')
678 #
679 # Cache and Memory Controllers have specific profilers associated with
680 # them. These stats must be cleared too.
681 #
682 for param in self.config_parameters:
683 if param.type_ast.type.ident == "CacheMemory" or \
684 param.type_ast.type.ident == "MemoryControl":
685 assert(param.pointer)
686 code(' m_${{param.ident}}_ptr->clearStats();')
687
688 code('''
689 m_profiler.clearStats();
690}
691
692// Actions
693''')
694
695 for action in self.actions.itervalues():
696 if "c_code" not in action:
697 continue
698
699 code('''
700/** \\brief ${{action.desc}} */
701void
702$c_ident::${{action.ident}}(const Address& addr)
703{
704 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
705 ${{action["c_code"]}}
706}
707
708''')
709 code.write(path, "%s.cc" % c_ident)
710
711 def printCWakeup(self, path):
712 '''Output the wakeup loop for the events'''
713
714 code = self.symtab.codeFormatter()
715 ident = self.ident
716
717 code('''
718// Auto generated C++ code started by $__file__:$__line__
719// ${ident}: ${{self.short}}
720
721#include "base/misc.hh"
722#include "mem/ruby/common/Global.hh"
723#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
724#include "mem/protocol/${ident}_Controller.hh"
725#include "mem/protocol/${ident}_State.hh"
726#include "mem/protocol/${ident}_Event.hh"
727#include "mem/protocol/Types.hh"
728#include "mem/ruby/system/System.hh"
729
730using namespace std;
731
732void
733${ident}_Controller::wakeup()
734{
735 // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this);
736 // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
737
738 int counter = 0;
739 while (true) {
740 // Some cases will put us into an infinite loop without this limit
741 assert(counter <= m_transitions_per_cycle);
742 if (counter == m_transitions_per_cycle) {
743 // Count how often we are fully utilized
744 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
745
746 // Wakeup in another cycle and try again
747 g_eventQueue_ptr->scheduleEvent(this, 1);
748 break;
749 }
750''')
751
752 code.indent()
753 code.indent()
754
755 # InPorts
756 #
757 for port in self.in_ports:
758 code.indent()
759 code('// ${ident}InPort $port')
760 code('${{port["c_code_in_port"]}}')
761 code.dedent()
762
763 code('')
764
765 code.dedent()
766 code.dedent()
767 code('''
768 break; // If we got this far, we have nothing left todo
769 }
770 // g_eventQueue_ptr->scheduleEvent(this, 1);
771 // DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
772}
773''')
774
775 code.write(path, "%s_Wakeup.cc" % self.ident)
776
777 def printCSwitch(self, path):
778 '''Output switch statement for transition table'''
779
780 code = self.symtab.codeFormatter()
781 ident = self.ident
782
783 code('''
784// Auto generated C++ code started by $__file__:$__line__
785// ${ident}: ${{self.short}}
786
787#include "mem/ruby/common/Global.hh"
788#include "mem/protocol/${ident}_Controller.hh"
789#include "mem/protocol/${ident}_State.hh"
790#include "mem/protocol/${ident}_Event.hh"
791#include "mem/protocol/Types.hh"
792#include "mem/ruby/system/System.hh"
793
794#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
795
796#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
797#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
798
799TransitionResult
800${ident}_Controller::doTransition(${ident}_Event event,
801 ${ident}_State state,
802 const Address &addr)
803{
804 ${ident}_State next_state = state;
805
806 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
807 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
808 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
809 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
810 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
811 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
812
813 TransitionResult result =
814 doTransitionWorker(event, state, next_state, addr);
815
816 if (result == TransitionResult_Valid) {
817 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
818 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
819 m_profiler.countTransition(state, event);
820 if (Debug::getProtocolTrace()) {
821 g_system_ptr->getProfiler()->profileTransition("${ident}",
822 m_version, addr,
823 ${ident}_State_to_string(state),
824 ${ident}_Event_to_string(event),
825 ${ident}_State_to_string(next_state),
826 GET_TRANSITION_COMMENT());
827 }
828 CLEAR_TRANSITION_COMMENT();
829 ${ident}_setState(addr, next_state);
830
831 } else if (result == TransitionResult_ResourceStall) {
832 if (Debug::getProtocolTrace()) {
833 g_system_ptr->getProfiler()->profileTransition("${ident}",
834 m_version, addr,
835 ${ident}_State_to_string(state),
836 ${ident}_Event_to_string(event),
837 ${ident}_State_to_string(next_state),
838 "Resource Stall");
839 }
840 } else if (result == TransitionResult_ProtocolStall) {
841 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
842 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
843 if (Debug::getProtocolTrace()) {
844 g_system_ptr->getProfiler()->profileTransition("${ident}",
845 m_version, addr,
846 ${ident}_State_to_string(state),
847 ${ident}_Event_to_string(event),
848 ${ident}_State_to_string(next_state),
849 "Protocol Stall");
850 }
851 }
852
853 return result;
854}
855
856TransitionResult
857${ident}_Controller::doTransitionWorker(${ident}_Event event,
858 ${ident}_State state,
859 ${ident}_State& next_state,
860 const Address& addr)
861{
862 switch(HASH_FUN(state, event)) {
863''')
864
865 # This map will allow suppress generating duplicate code
866 cases = orderdict()
867
868 for trans in self.transitions:
869 case_string = "%s_State_%s, %s_Event_%s" % \
870 (self.ident, trans.state.ident, self.ident, trans.event.ident)
871
872 case = self.symtab.codeFormatter()
873 # Only set next_state if it changes
874 if trans.state != trans.nextState:
875 ns_ident = trans.nextState.ident
876 case('next_state = ${ident}_State_${ns_ident};')
877
878 actions = trans.actions
879
880 # Check for resources
881 case_sorter = []
882 res = trans.resources
883 for key,val in res.iteritems():
884 if key.type.ident != "DNUCAStopTable":
885 val = '''
886if (!%s.areNSlotsAvailable(%s))
887 return TransitionResult_ResourceStall;
888''' % (key.code, val)
889 case_sorter.append(val)
890
891
892 # Emit the code sequences in a sorted order. This makes the
893 # output deterministic (without this the output order can vary
894 # since Map's keys() on a vector of pointers is not deterministic
895 for c in sorted(case_sorter):
896 case("$c")
897
898 # Figure out if we stall
899 stall = False
900 for action in actions:
901 if action.ident == "z_stall":
902 stall = True
903 break
904
905 if stall:
906 case('return TransitionResult_ProtocolStall;')
907 else:
908 for action in actions:
909 case('${{action.ident}}(addr);')
910 case('return TransitionResult_Valid;')
911
912 case = str(case)
913
914 # Look to see if this transition code is unique.
915 if case not in cases:
916 cases[case] = []
917
918 cases[case].append(case_string)
919
920 # Walk through all of the unique code blocks and spit out the
921 # corresponding case statement elements
922 for case,transitions in cases.iteritems():
923 # Iterative over all the multiple transitions that share
924 # the same code
925 for trans in transitions:
926 code(' case HASH_FUN($trans):')
927 code(' $case')
928
929 code('''
930 default:
931 WARN_EXPR(m_version);
932 WARN_EXPR(g_eventQueue_ptr->getTime());
933 WARN_EXPR(addr);
934 WARN_EXPR(event);
935 WARN_EXPR(state);
936 ERROR_MSG(\"Invalid transition\");
937 }
938 return TransitionResult_Valid;
939}
940''')
941 code.write(path, "%s_Transitions.cc" % self.ident)
942
943 def printProfileDumperHH(self, path):
944 code = self.symtab.codeFormatter()
945 ident = self.ident
946
947 code('''
948// Auto generated C++ code started by $__file__:$__line__
949// ${ident}: ${{self.short}}
950
951#ifndef __${ident}_PROFILE_DUMPER_HH__
952#define __${ident}_PROFILE_DUMPER_HH__
953
954#include <iostream>
955#include <vector>
956
957#include "${ident}_Profiler.hh"
958#include "${ident}_Event.hh"
959
960typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
961
962class ${ident}_ProfileDumper
963{
964 public:
965 ${ident}_ProfileDumper();
966 void registerProfiler(${ident}_Profiler* profiler);
967 void dumpStats(std::ostream& out) const;
968
969 private:
970 ${ident}_profilers m_profilers;
971};
972
973#endif // __${ident}_PROFILE_DUMPER_HH__
974''')
975 code.write(path, "%s_ProfileDumper.hh" % self.ident)
976
977 def printProfileDumperCC(self, path):
978 code = self.symtab.codeFormatter()
979 ident = self.ident
980
981 code('''
982// Auto generated C++ code started by $__file__:$__line__
983// ${ident}: ${{self.short}}
984
985#include "mem/protocol/${ident}_ProfileDumper.hh"
986
987${ident}_ProfileDumper::${ident}_ProfileDumper()
988{
989}
990
991void
992${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
993{
994 m_profilers.push_back(profiler);
995}
996
997void
998${ident}_ProfileDumper::dumpStats(std::ostream& out) const
999{
1000 out << " --- ${ident} ---\\n";
1001 out << " - Event Counts -\\n";
1002 for (${ident}_Event event = ${ident}_Event_FIRST;
1003 event < ${ident}_Event_NUM;
1004 ++event) {
1005 out << (${ident}_Event) event << " [";
1006 uint64 total = 0;
1007 for (int i = 0; i < m_profilers.size(); i++) {
1008 out << m_profilers[i]->getEventCount(event) << " ";
1009 total += m_profilers[i]->getEventCount(event);
1010 }
1011 out << "] " << total << "\\n";
1012 }
1013 out << "\\n";
1014 out << " - Transitions -\\n";
1015 for (${ident}_State state = ${ident}_State_FIRST;
1016 state < ${ident}_State_NUM;
1017 ++state) {
1018 for (${ident}_Event event = ${ident}_Event_FIRST;
1019 event < ${ident}_Event_NUM;
1020 ++event) {
1021 if (m_profilers[0]->isPossible(state, event)) {
1022 out << (${ident}_State) state << " "
1023 << (${ident}_Event) event << " [";
1024 uint64 total = 0;
1025 for (int i = 0; i < m_profilers.size(); i++) {
1026 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1027 total += m_profilers[i]->getTransitionCount(state, event);
1028 }
1029 out << "] " << total << "\\n";
1030 }
1031 }
1032 out << "\\n";
1033 }
1034}
1035''')
1036 code.write(path, "%s_ProfileDumper.cc" % self.ident)
1037
1038 def printProfilerHH(self, path):
1039 code = self.symtab.codeFormatter()
1040 ident = self.ident
1041
1042 code('''
1043// Auto generated C++ code started by $__file__:$__line__
1044// ${ident}: ${{self.short}}
1045
1046#ifndef __${ident}_PROFILER_HH__
1047#define __${ident}_PROFILER_HH__
1048
1049#include <iostream>
1050
1051#include "mem/ruby/common/Global.hh"
1052#include "mem/protocol/${ident}_State.hh"
1053#include "mem/protocol/${ident}_Event.hh"
1054
1055class ${ident}_Profiler
1056{
1057 public:
1058 ${ident}_Profiler();
1059 void setVersion(int version);
1060 void countTransition(${ident}_State state, ${ident}_Event event);
1061 void possibleTransition(${ident}_State state, ${ident}_Event event);
1062 uint64 getEventCount(${ident}_Event event);
1063 bool isPossible(${ident}_State state, ${ident}_Event event);
1064 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1065 void clearStats();
1066
1067 private:
1068 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1069 int m_event_counters[${ident}_Event_NUM];
1070 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1071 int m_version;
1072};
1073
1074#endif // __${ident}_PROFILER_HH__
1075''')
1076 code.write(path, "%s_Profiler.hh" % self.ident)
1077
1078 def printProfilerCC(self, path):
1079 code = self.symtab.codeFormatter()
1080 ident = self.ident
1081
1082 code('''
1083// Auto generated C++ code started by $__file__:$__line__
1084// ${ident}: ${{self.short}}
1085
1086#include "mem/protocol/${ident}_Profiler.hh"
1087
1088${ident}_Profiler::${ident}_Profiler()
1089{
1090 for (int state = 0; state < ${ident}_State_NUM; state++) {
1091 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1092 m_possible[state][event] = false;
1093 m_counters[state][event] = 0;
1094 }
1095 }
1096 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1097 m_event_counters[event] = 0;
1098 }
1099}
1100
1101void
1102${ident}_Profiler::setVersion(int version)
1103{
1104 m_version = version;
1105}
1106
1107void
1108${ident}_Profiler::clearStats()
1109{
1110 for (int state = 0; state < ${ident}_State_NUM; state++) {
1111 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1112 m_counters[state][event] = 0;
1113 }
1114 }
1115
1116 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1117 m_event_counters[event] = 0;
1118 }
1119}
1120void
1121${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1122{
1123 assert(m_possible[state][event]);
1124 m_counters[state][event]++;
1125 m_event_counters[event]++;
1126}
1127void
1128${ident}_Profiler::possibleTransition(${ident}_State state,
1129 ${ident}_Event event)
1130{
1131 m_possible[state][event] = true;
1132}
1133
1134uint64
1135${ident}_Profiler::getEventCount(${ident}_Event event)
1136{
1137 return m_event_counters[event];
1138}
1139
1140bool
1141${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1142{
1143 return m_possible[state][event];
1144}
1145
1146uint64
1147${ident}_Profiler::getTransitionCount(${ident}_State state,
1148 ${ident}_Event event)
1149{
1150 return m_counters[state][event];
1151}
1152
1153''')
1154 code.write(path, "%s_Profiler.cc" % self.ident)
1155
1156 # **************************
1157 # ******* HTML Files *******
1158 # **************************
1159 def frameRef(self, click_href, click_target, over_href, over_num, text):
1160 code = self.symtab.codeFormatter(fix_newlines=False)
1161 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1162 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1163 parent.frames[$over_num].location='$over_href'
1164 }\">
1165 ${{html.formatShorthand(text)}}
1166 </A>""")
1167 return str(code)
1168
1169 def writeHTMLFiles(self, path):
1170 # Create table with no row hilighted
1171 self.printHTMLTransitions(path, None)
1172
1173 # Generate transition tables
1174 for state in self.states.itervalues():
1175 self.printHTMLTransitions(path, state)
1176
1177 # Generate action descriptions
1178 for action in self.actions.itervalues():
1179 name = "%s_action_%s.html" % (self.ident, action.ident)
1180 code = html.createSymbol(action, "Action")
1181 code.write(path, name)
1182
1183 # Generate state descriptions
1184 for state in self.states.itervalues():
1185 name = "%s_State_%s.html" % (self.ident, state.ident)
1186 code = html.createSymbol(state, "State")
1187 code.write(path, name)
1188
1189 # Generate event descriptions
1190 for event in self.events.itervalues():
1191 name = "%s_Event_%s.html" % (self.ident, event.ident)
1192 code = html.createSymbol(event, "Event")
1193 code.write(path, name)
1194
1195 def printHTMLTransitions(self, path, active_state):
1196 code = self.symtab.codeFormatter()
1197
1198 code('''
1199<HTML>
1200<BODY link="blue" vlink="blue">
1201
1202<H1 align="center">${{html.formatShorthand(self.short)}}:
1203''')
1204 code.indent()
1205 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
1206 mid = machine.ident
1207 if i != 0:
1208 extra = " - "
1209 else:
1210 extra = ""
1211 if machine == self:
1212 code('$extra$mid')
1213 else:
1214 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1215 code.dedent()
1216
1217 code("""
1218</H1>
1219
1220<TABLE border=1>
1221<TR>
1222 <TH> </TH>
1223""")
1224
1225 for event in self.events.itervalues():
1226 href = "%s_Event_%s.html" % (self.ident, event.ident)
1227 ref = self.frameRef(href, "Status", href, "1", event.short)
1228 code('<TH bgcolor=white>$ref</TH>')
1229
1230 code('</TR>')
1231 # -- Body of table
1232 for state in self.states.itervalues():
1233 # -- Each row
1234 if state == active_state:
1235 color = "yellow"
1236 else:
1237 color = "white"
1238
1239 click = "%s_table_%s.html" % (self.ident, state.ident)
1240 over = "%s_State_%s.html" % (self.ident, state.ident)
1241 text = html.formatShorthand(state.short)
1242 ref = self.frameRef(click, "Table", over, "1", state.short)
1243 code('''
1244<TR>
1245 <TH bgcolor=$color>$ref</TH>
1246''')
1247
1248 # -- One column for each event
1249 for event in self.events.itervalues():
1250 trans = self.table.get((state,event), None)
1251 if trans is None:
1252 # This is the no transition case
1253 if state == active_state:
1254 color = "#C0C000"
1255 else:
1256 color = "lightgrey"
1257
1258 code('<TD bgcolor=$color>&nbsp;</TD>')
1259 continue
1260
1261 next = trans.nextState
1262 stall_action = False
1263
1264 # -- Get the actions
1265 for action in trans.actions:
1266 if action.ident == "z_stall" or \
1267 action.ident == "zz_recycleMandatoryQueue":
1268 stall_action = True
1269
1270 # -- Print out "actions/next-state"
1271 if stall_action:
1272 if state == active_state:
1273 color = "#C0C000"
1274 else:
1275 color = "lightgrey"
1276
1277 elif active_state and next.ident == active_state.ident:
1278 color = "aqua"
1279 elif state == active_state:
1280 color = "yellow"
1281 else:
1282 color = "white"
1283
1284 code('<TD bgcolor=$color>')
1285 for action in trans.actions:
1286 href = "%s_action_%s.html" % (self.ident, action.ident)
1287 ref = self.frameRef(href, "Status", href, "1",
1288 action.short)
1289 code(' $ref')
1290 if next != state:
1291 if trans.actions:
1292 code('/')
1293 click = "%s_table_%s.html" % (self.ident, next.ident)
1294 over = "%s_State_%s.html" % (self.ident, next.ident)
1295 ref = self.frameRef(click, "Table", over, "1", next.short)
1296 code("$ref")
1297 code("</TD>")
1298
1299 # -- Each row
1300 if state == active_state:
1301 color = "yellow"
1302 else:
1303 color = "white"
1304
1305 click = "%s_table_%s.html" % (self.ident, state.ident)
1306 over = "%s_State_%s.html" % (self.ident, state.ident)
1307 ref = self.frameRef(click, "Table", over, "1", state.short)
1308 code('''
1309 <TH bgcolor=$color>$ref</TH>
1310</TR>
1311''')
1312 code('''
1313<!- Column footer->
1314<TR>
1315 <TH> </TH>
1316''')
1317
1318 for event in self.events.itervalues():
1319 href = "%s_Event_%s.html" % (self.ident, event.ident)
1320 ref = self.frameRef(href, "Status", href, "1", event.short)
1321 code('<TH bgcolor=white>$ref</TH>')
1322 code('''
1323</TR>
1324</TABLE>
1325</BODY></HTML>
1326''')
1327
1328
1329 if active_state:
1330 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1331 else:
1332 name = "%s_table.html" % self.ident
1333 code.write(path, name)
1334
1335__all__ = [ "StateMachine" ]