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