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