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