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