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