StateMachine.py (6863:21fbf0412e0d) StateMachine.py (6877:2a1a3d916ca8)
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 code_formatter, orderdict
29
30from slicc.symbols.Symbol import Symbol
31from slicc.symbols.Var import Var
32import slicc.generate.html as html
33
34class StateMachine(Symbol):
35 def __init__(self, symtab, ident, location, pairs, config_parameters):
36 super(StateMachine, self).__init__(symtab, ident, location, pairs)
37 self.table = None
38 self.config_parameters = config_parameters
39 for param in config_parameters:
40 var = Var(symtab, param.name, location, param.type_ast.type,
41 "m_%s" % param.name, {}, self)
42 self.symtab.registerSym(param.name, var)
43
44 self.states = orderdict()
45 self.events = orderdict()
46 self.actions = orderdict()
47 self.transitions = []
48 self.in_ports = []
49 self.functions = []
50 self.objects = []
51
52 self.message_buffer_names = []
53
54 def __repr__(self):
55 return "[StateMachine: %s]" % self.ident
56
57 def addState(self, state):
58 assert self.table is None
59 self.states[state.ident] = state
60
61 def addEvent(self, event):
62 assert self.table is None
63 self.events[event.ident] = event
64
65 def addAction(self, action):
66 assert self.table is None
67
68 # Check for duplicate action
69 for other in self.actions.itervalues():
70 if action.ident == other.ident:
71 action.warning("Duplicate action definition: %s" % action.ident)
72 action.error("Duplicate action definition: %s" % action.ident)
73 if action.short == other.short:
74 other.warning("Duplicate action shorthand: %s" % other.ident)
75 other.warning(" shorthand = %s" % other.short)
76 action.warning("Duplicate action shorthand: %s" % action.ident)
77 action.error(" shorthand = %s" % action.short)
78
79 self.actions[action.ident] = action
80
81 def addTransition(self, trans):
82 assert self.table is None
83 self.transitions.append(trans)
84
85 def addInPort(self, var):
86 self.in_ports.append(var)
87
88 def addFunc(self, func):
89 # register func in the symbol table
90 self.symtab.registerSym(str(func), func)
91 self.functions.append(func)
92
93 def addObject(self, obj):
94 self.objects.append(obj)
95
96 # Needs to be called before accessing the table
97 def buildTable(self):
98 assert self.table is None
99
100 table = {}
101
102 for trans in self.transitions:
103 # Track which actions we touch so we know if we use them
104 # all -- really this should be done for all symbols as
105 # part of the symbol table, then only trigger it for
106 # Actions, States, Events, etc.
107
108 for action in trans.actions:
109 action.used = True
110
111 index = (trans.state, trans.event)
112 if index in table:
113 table[index].warning("Duplicate transition: %s" % table[index])
114 trans.error("Duplicate transition: %s" % trans)
115 table[index] = trans
116
117 # Look at all actions to make sure we used them all
118 for action in self.actions.itervalues():
119 if not action.used:
120 error_msg = "Unused action: %s" % action.ident
121 if "desc" in action:
122 error_msg += ", " + action.desc
123 action.warning(error_msg)
124 self.table = table
125
126 def writeCodeFiles(self, path):
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 code_formatter, orderdict
29
30from slicc.symbols.Symbol import Symbol
31from slicc.symbols.Var import Var
32import slicc.generate.html as html
33
34class StateMachine(Symbol):
35 def __init__(self, symtab, ident, location, pairs, config_parameters):
36 super(StateMachine, self).__init__(symtab, ident, location, pairs)
37 self.table = None
38 self.config_parameters = config_parameters
39 for param in config_parameters:
40 var = Var(symtab, param.name, location, param.type_ast.type,
41 "m_%s" % param.name, {}, self)
42 self.symtab.registerSym(param.name, var)
43
44 self.states = orderdict()
45 self.events = orderdict()
46 self.actions = orderdict()
47 self.transitions = []
48 self.in_ports = []
49 self.functions = []
50 self.objects = []
51
52 self.message_buffer_names = []
53
54 def __repr__(self):
55 return "[StateMachine: %s]" % self.ident
56
57 def addState(self, state):
58 assert self.table is None
59 self.states[state.ident] = state
60
61 def addEvent(self, event):
62 assert self.table is None
63 self.events[event.ident] = event
64
65 def addAction(self, action):
66 assert self.table is None
67
68 # Check for duplicate action
69 for other in self.actions.itervalues():
70 if action.ident == other.ident:
71 action.warning("Duplicate action definition: %s" % action.ident)
72 action.error("Duplicate action definition: %s" % action.ident)
73 if action.short == other.short:
74 other.warning("Duplicate action shorthand: %s" % other.ident)
75 other.warning(" shorthand = %s" % other.short)
76 action.warning("Duplicate action shorthand: %s" % action.ident)
77 action.error(" shorthand = %s" % action.short)
78
79 self.actions[action.ident] = action
80
81 def addTransition(self, trans):
82 assert self.table is None
83 self.transitions.append(trans)
84
85 def addInPort(self, var):
86 self.in_ports.append(var)
87
88 def addFunc(self, func):
89 # register func in the symbol table
90 self.symtab.registerSym(str(func), func)
91 self.functions.append(func)
92
93 def addObject(self, obj):
94 self.objects.append(obj)
95
96 # Needs to be called before accessing the table
97 def buildTable(self):
98 assert self.table is None
99
100 table = {}
101
102 for trans in self.transitions:
103 # Track which actions we touch so we know if we use them
104 # all -- really this should be done for all symbols as
105 # part of the symbol table, then only trigger it for
106 # Actions, States, Events, etc.
107
108 for action in trans.actions:
109 action.used = True
110
111 index = (trans.state, trans.event)
112 if index in table:
113 table[index].warning("Duplicate transition: %s" % table[index])
114 trans.error("Duplicate transition: %s" % trans)
115 table[index] = trans
116
117 # Look at all actions to make sure we used them all
118 for action in self.actions.itervalues():
119 if not action.used:
120 error_msg = "Unused action: %s" % action.ident
121 if "desc" in action:
122 error_msg += ", " + action.desc
123 action.warning(error_msg)
124 self.table = table
125
126 def writeCodeFiles(self, path):
127 self.printControllerPython(path)
127 self.printControllerHH(path)
128 self.printControllerCC(path)
129 self.printCSwitch(path)
130 self.printCWakeup(path)
131 self.printProfilerCC(path)
132 self.printProfilerHH(path)
133
134 for func in self.functions:
135 func.writeCodeFiles(path)
136
128 self.printControllerHH(path)
129 self.printControllerCC(path)
130 self.printCSwitch(path)
131 self.printCWakeup(path)
132 self.printProfilerCC(path)
133 self.printProfilerHH(path)
134
135 for func in self.functions:
136 func.writeCodeFiles(path)
137
138 def printControllerPython(self, path):
139 code = code_formatter()
140 ident = self.ident
141 py_ident = "%s_Controller" % ident
142 c_ident = "%s_Controller" % self.ident
143 code('''
144from m5.params import *
145from m5.SimObject import SimObject
146from Controller import RubyController
147
148class $py_ident(RubyController):
149 type = '$py_ident'
150''')
151 code.indent()
152 for param in self.config_parameters:
153 dflt_str = ''
154 if param.default is not None:
155 dflt_str = str(param.default) + ', '
156 code('${{param.name}} = Param.Int(${dflt_str}"")')
157 code.dedent()
158 code.write(path, '%s.py' % py_ident)
159
160
137 def printControllerHH(self, path):
138 '''Output the method declarations for the class declaration'''
139 code = code_formatter()
140 ident = self.ident
141 c_ident = "%s_Controller" % self.ident
142
143 self.message_buffer_names = []
144
145 code('''
146/** \\file $ident.hh
147 *
148 * Auto generated C++ code started by $__file__:$__line__
149 * Created by slicc definition of Module "${{self.short}}"
150 */
151
152#ifndef ${ident}_CONTROLLER_H
153#define ${ident}_CONTROLLER_H
154
161 def printControllerHH(self, path):
162 '''Output the method declarations for the class declaration'''
163 code = code_formatter()
164 ident = self.ident
165 c_ident = "%s_Controller" % self.ident
166
167 self.message_buffer_names = []
168
169 code('''
170/** \\file $ident.hh
171 *
172 * Auto generated C++ code started by $__file__:$__line__
173 * Created by slicc definition of Module "${{self.short}}"
174 */
175
176#ifndef ${ident}_CONTROLLER_H
177#define ${ident}_CONTROLLER_H
178
179#include "params/$c_ident.hh"
180
155#include "mem/ruby/common/Global.hh"
156#include "mem/ruby/common/Consumer.hh"
157#include "mem/ruby/slicc_interface/AbstractController.hh"
158#include "mem/protocol/TransitionResult.hh"
159#include "mem/protocol/Types.hh"
160#include "mem/protocol/${ident}_Profiler.hh"
161''')
162
163 seen_types = set()
164 for var in self.objects:
165 if var.type.ident not in seen_types and not var.type.isPrimitive:
166 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
167 seen_types.add(var.type.ident)
168
169 # for adding information to the protocol debug trace
170 code('''
171extern stringstream ${ident}_transitionComment;
172
173class $c_ident : public AbstractController {
174#ifdef CHECK_COHERENCE
175#endif /* CHECK_COHERENCE */
176public:
181#include "mem/ruby/common/Global.hh"
182#include "mem/ruby/common/Consumer.hh"
183#include "mem/ruby/slicc_interface/AbstractController.hh"
184#include "mem/protocol/TransitionResult.hh"
185#include "mem/protocol/Types.hh"
186#include "mem/protocol/${ident}_Profiler.hh"
187''')
188
189 seen_types = set()
190 for var in self.objects:
191 if var.type.ident not in seen_types and not var.type.isPrimitive:
192 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
193 seen_types.add(var.type.ident)
194
195 # for adding information to the protocol debug trace
196 code('''
197extern stringstream ${ident}_transitionComment;
198
199class $c_ident : public AbstractController {
200#ifdef CHECK_COHERENCE
201#endif /* CHECK_COHERENCE */
202public:
177 $c_ident(const string & name);
203 typedef ${c_ident}Params Params;
204 $c_ident(const Params *p);
178 static int getNumControllers();
205 static int getNumControllers();
179 void init(Network* net_ptr, const vector<string> & argv);
206 void init();
180 MessageBuffer* getMandatoryQueue() const;
181 const int & getVersion() const;
182 const string toString() const;
183 const string getName() const;
184 const MachineType getMachineType() const;
185 void print(ostream& out) const;
186 void printConfig(ostream& out) const;
187 void wakeup();
188 void printStats(ostream& out) const { s_profiler.dumpStats(out); }
189 void clearStats() { s_profiler.clearStats(); }
190 void blockOnQueue(Address addr, MessageBuffer* port);
191 void unblock(Address addr);
192private:
193''')
194
195 code.indent()
196 # added by SS
197 for param in self.config_parameters:
198 code('int m_${{param.ident}};')
199
200 code('''
201int m_number_of_TBEs;
202
203TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc
204TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc
205string m_name;
206int m_transitions_per_cycle;
207int m_buffer_size;
208int m_recycle_latency;
209map< string, string > m_cfg;
210NodeID m_version;
211Network* m_net_ptr;
212MachineID m_machineID;
213bool m_is_blocking;
214map< Address, MessageBuffer* > m_block_map;
215${ident}_Profiler s_profiler;
216static int m_num_controllers;
217// Internal functions
218''')
219
220 for func in self.functions:
221 proto = func.prototype
222 if proto:
223 code('$proto')
224
225 code('''
226
227// Actions
228''')
229 for action in self.actions.itervalues():
230 code('/** \\brief ${{action.desc}} */')
231 code('void ${{action.ident}}(const Address& addr);')
232
233 # the controller internal variables
234 code('''
235
236// Object
237''')
238 for var in self.objects:
239 th = var.get("template_hack", "")
240 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
241
242 if var.type.ident == "MessageBuffer":
243 self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
244
245 code.dedent()
246 code('};')
247 code('#endif // ${ident}_CONTROLLER_H')
248 code.write(path, '%s.hh' % c_ident)
249
250 def printControllerCC(self, path):
251 '''Output the actions for performing the actions'''
252
253 code = code_formatter()
254 ident = self.ident
255 c_ident = "%s_Controller" % self.ident
256
257 code('''
258/** \\file $ident.cc
259 *
260 * Auto generated C++ code started by $__file__:$__line__
261 * Created by slicc definition of Module "${{self.short}}"
262 */
263
264#include "mem/ruby/common/Global.hh"
265#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
266#include "mem/protocol/${ident}_Controller.hh"
267#include "mem/protocol/${ident}_State.hh"
268#include "mem/protocol/${ident}_Event.hh"
269#include "mem/protocol/Types.hh"
270#include "mem/ruby/system/System.hh"
271''')
272
273 # include object classes
274 seen_types = set()
275 for var in self.objects:
276 if var.type.ident not in seen_types and not var.type.isPrimitive:
277 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
278 seen_types.add(var.type.ident)
279
280 code('''
207 MessageBuffer* getMandatoryQueue() const;
208 const int & getVersion() const;
209 const string toString() const;
210 const string getName() const;
211 const MachineType getMachineType() const;
212 void print(ostream& out) const;
213 void printConfig(ostream& out) const;
214 void wakeup();
215 void printStats(ostream& out) const { s_profiler.dumpStats(out); }
216 void clearStats() { s_profiler.clearStats(); }
217 void blockOnQueue(Address addr, MessageBuffer* port);
218 void unblock(Address addr);
219private:
220''')
221
222 code.indent()
223 # added by SS
224 for param in self.config_parameters:
225 code('int m_${{param.ident}};')
226
227 code('''
228int m_number_of_TBEs;
229
230TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc
231TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc
232string m_name;
233int m_transitions_per_cycle;
234int m_buffer_size;
235int m_recycle_latency;
236map< string, string > m_cfg;
237NodeID m_version;
238Network* m_net_ptr;
239MachineID m_machineID;
240bool m_is_blocking;
241map< Address, MessageBuffer* > m_block_map;
242${ident}_Profiler s_profiler;
243static int m_num_controllers;
244// Internal functions
245''')
246
247 for func in self.functions:
248 proto = func.prototype
249 if proto:
250 code('$proto')
251
252 code('''
253
254// Actions
255''')
256 for action in self.actions.itervalues():
257 code('/** \\brief ${{action.desc}} */')
258 code('void ${{action.ident}}(const Address& addr);')
259
260 # the controller internal variables
261 code('''
262
263// Object
264''')
265 for var in self.objects:
266 th = var.get("template_hack", "")
267 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
268
269 if var.type.ident == "MessageBuffer":
270 self.message_buffer_names.append("m_%s_ptr" % var.c_ident)
271
272 code.dedent()
273 code('};')
274 code('#endif // ${ident}_CONTROLLER_H')
275 code.write(path, '%s.hh' % c_ident)
276
277 def printControllerCC(self, path):
278 '''Output the actions for performing the actions'''
279
280 code = code_formatter()
281 ident = self.ident
282 c_ident = "%s_Controller" % self.ident
283
284 code('''
285/** \\file $ident.cc
286 *
287 * Auto generated C++ code started by $__file__:$__line__
288 * Created by slicc definition of Module "${{self.short}}"
289 */
290
291#include "mem/ruby/common/Global.hh"
292#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
293#include "mem/protocol/${ident}_Controller.hh"
294#include "mem/protocol/${ident}_State.hh"
295#include "mem/protocol/${ident}_Event.hh"
296#include "mem/protocol/Types.hh"
297#include "mem/ruby/system/System.hh"
298''')
299
300 # include object classes
301 seen_types = set()
302 for var in self.objects:
303 if var.type.ident not in seen_types and not var.type.isPrimitive:
304 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
305 seen_types.add(var.type.ident)
306
307 code('''
308$c_ident *
309${c_ident}Params::create()
310{
311 return new $c_ident(this);
312}
313
314
281int $c_ident::m_num_controllers = 0;
282
283stringstream ${ident}_transitionComment;
284#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
285/** \\brief constructor */
315int $c_ident::m_num_controllers = 0;
316
317stringstream ${ident}_transitionComment;
318#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
319/** \\brief constructor */
286$c_ident::$c_ident(const string &name)
287 : m_name(name)
320$c_ident::$c_ident(const Params *p)
321 : AbstractController(p)
288{
322{
323 m_version = p->version;
324 m_transitions_per_cycle = p->transitions_per_cycle;
325 m_buffer_size = p->buffer_size;
326 m_recycle_latency = p->recycle_latency;
327 m_number_of_TBEs = p->number_of_TBEs;
289''')
290 code.indent()
328''')
329 code.indent()
330 for param in self.config_parameters:
331 code('m_${{param.name}} = p->${{param.name}};')
291
292 code('m_num_controllers++;')
293 for var in self.objects:
294 if var.ident.find("mandatoryQueue") >= 0:
295 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
296
297 code.dedent()
298 code('''
299}
300
332
333 code('m_num_controllers++;')
334 for var in self.objects:
335 if var.ident.find("mandatoryQueue") >= 0:
336 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
337
338 code.dedent()
339 code('''
340}
341
301void $c_ident::init(Network *net_ptr, const vector<string> &argv)
342void $c_ident::init()
302{
343{
303 for (size_t i = 0; i < argv.size(); i += 2) {
304 if (argv[i] == "version")
305 m_version = atoi(argv[i+1].c_str());
306 else if (argv[i] == "transitions_per_cycle")
307 m_transitions_per_cycle = atoi(argv[i+1].c_str());
308 else if (argv[i] == "buffer_size")
309 m_buffer_size = atoi(argv[i+1].c_str());
310 else if (argv[i] == "recycle_latency")
311 m_recycle_latency = atoi(argv[i+1].c_str());
312 else if (argv[i] == "number_of_TBEs")
313 m_number_of_TBEs = atoi(argv[i+1].c_str());
314''')
315
316 code.indent()
317 code.indent()
318 for param in self.config_parameters:
319 code('else if (argv[i] == "${{param.name}}")')
320 if param.type_ast.type.ident == "int":
321 code(' m_${{param.name}} = atoi(argv[i+1].c_str());')
322 elif param.type_ast.type.ident == "bool":
323 code(' m_${{param.name}} = string_to_bool(argv[i+1]);')
324 else:
325 self.error("only int and bool parameters are "\
326 "currently supported")
327 code.dedent()
328 code.dedent()
329 code('''
330 }
331
332 m_net_ptr = net_ptr;
333 m_machineID.type = MachineType_${ident};
334 m_machineID.num = m_version;
344 m_machineID.type = MachineType_${ident};
345 m_machineID.num = m_version;
335 for (size_t i = 0; i < argv.size(); i += 2) {
336 if (argv[i] != "version")
337 m_cfg[argv[i]] = argv[i+1];
338 }
339
340 // Objects
341 s_profiler.setVersion(m_version);
342''')
343
344 code.indent()
345 for var in self.objects:
346 vtype = var.type
347 vid = "m_%s_ptr" % var.c_ident
348 if "network" not in var:
349 # Not a network port object
350 if "primitive" in vtype:
351 code('$vid = new ${{vtype.c_ident}};')
352 if "default" in var:
353 code('(*$vid) = ${{var["default"]}};')
354 else:
355 # Normal Object
356 # added by SS
357 if "factory" in var:
358 code('$vid = ${{var["factory"]}};')
359 elif var.ident.find("mandatoryQueue") < 0:
360 th = var.get("template_hack", "")
361 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
362
363 args = ""
364 if "non_obj" not in vtype and not vtype.isEnumeration:
365 if expr.find("TBETable") >= 0:
366 args = "m_number_of_TBEs"
367 else:
368 args = var.get("constructor_hack", "")
369 args = "(%s)" % args
370
371 code('$expr$args;')
372 else:
373 code(';')
374
375 code('assert($vid != NULL);')
376
377 if "default" in var:
378 code('(*$vid) = ${{var["default"]}}; // Object default')
379 elif "default" in vtype:
380 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default')
381
382 # Set ordering
383 if "ordered" in var and "trigger_queue" not in var:
384 # A buffer
385 code('$vid->setOrdering(${{var["ordered"]}});')
386
387 # Set randomization
388 if "random" in var:
389 # A buffer
390 code('$vid->setRandomization(${{var["random"]}});')
391
392 # Set Priority
393 if vtype.isBuffer and \
394 "rank" in var and "trigger_queue" not in var:
395 code('$vid->setPriority(${{var["rank"]}});')
396 else:
397 # Network port object
398 network = var["network"]
399 ordered = var["ordered"]
400 vnet = var["virtual_network"]
401
402 assert var.machine is not None
403 code('''
404$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet);
405''')
406
407 code('assert($vid != NULL);')
408
409 # Set ordering
410 if "ordered" in var:
411 # A buffer
412 code('$vid->setOrdering(${{var["ordered"]}});')
413
414 # Set randomization
415 if "random" in var:
416 # A buffer
417 code('$vid->setRandomization(${{var["random"]}})')
418
419 # Set Priority
420 if "rank" in var:
421 code('$vid->setPriority(${{var["rank"]}})')
422
423 # Set buffer size
424 if vtype.isBuffer:
425 code('''
426if (m_buffer_size > 0) {
427 $vid->setSize(m_buffer_size);
428}
429''')
430
431 # set description (may be overriden later by port def)
432 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");')
433
434 # Set the queue consumers
435 code.insert_newline()
436 for port in self.in_ports:
437 code('${{port.code}}.setConsumer(this);')
438
439 # Set the queue descriptions
440 code.insert_newline()
441 for port in self.in_ports:
442 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");')
443
444 # Initialize the transition profiling
445 code.insert_newline()
446 for trans in self.transitions:
447 # Figure out if we stall
448 stall = False
449 for action in trans.actions:
450 if action.ident == "z_stall":
451 stall = True
452
453 # Only possible if it is not a 'z' case
454 if not stall:
455 state = "%s_State_%s" % (self.ident, trans.state.ident)
456 event = "%s_Event_%s" % (self.ident, trans.event.ident)
457 code('s_profiler.possibleTransition($state, $event);')
458
459 # added by SS to initialize recycle_latency of message buffers
460 for buf in self.message_buffer_names:
461 code("$buf->setRecycleLatency(m_recycle_latency);")
462
463 code.dedent()
464 code('}')
465
466 has_mandatory_q = False
467 for port in self.in_ports:
468 if port.code.find("mandatoryQueue_ptr") >= 0:
469 has_mandatory_q = True
470
471 if has_mandatory_q:
472 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
473 else:
474 mq_ident = "NULL"
475
476 code('''
477int $c_ident::getNumControllers() {
478 return m_num_controllers;
479}
480
481MessageBuffer* $c_ident::getMandatoryQueue() const {
482 return $mq_ident;
483}
484
485const int & $c_ident::getVersion() const{
486 return m_version;
487}
488
489const string $c_ident::toString() const{
490 return "$c_ident";
491}
492
493const string $c_ident::getName() const{
494 return m_name;
495}
496const MachineType $c_ident::getMachineType() const{
497 return MachineType_${ident};
498}
499
500void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) {
501 m_is_blocking = true;
502 m_block_map[addr] = port;
503}
504void $c_ident::unblock(Address addr) {
505 m_block_map.erase(addr);
506 if (m_block_map.size() == 0) {
507 m_is_blocking = false;
508 }
509}
510
511void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; }
512
513void $c_ident::printConfig(ostream& out) const {
514 out << "$c_ident config: " << m_name << endl;
515 out << " version: " << m_version << endl;
516 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) {
517 out << " " << (*it).first << ": " << (*it).second << endl;
518 }
519}
520
521// Actions
522''')
523
524 for action in self.actions.itervalues():
525 if "c_code" not in action:
526 continue
527
528 code('''
529/** \\brief ${{action.desc}} */
530void $c_ident::${{action.ident}}(const Address& addr)
531{
532 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
533 ${{action["c_code"]}}
534}
535
536''')
537 code.write(path, "%s.cc" % c_ident)
538
539 def printCWakeup(self, path):
540 '''Output the wakeup loop for the events'''
541
542 code = code_formatter()
543 ident = self.ident
544
545 code('''
546// Auto generated C++ code started by $__file__:$__line__
547// ${ident}: ${{self.short}}
548
549#include "mem/ruby/common/Global.hh"
550#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
551#include "mem/protocol/${ident}_Controller.hh"
552#include "mem/protocol/${ident}_State.hh"
553#include "mem/protocol/${ident}_Event.hh"
554#include "mem/protocol/Types.hh"
555#include "mem/ruby/system/System.hh"
556
557void ${ident}_Controller::wakeup()
558{
559
560 int counter = 0;
561 while (true) {
562 // Some cases will put us into an infinite loop without this limit
563 assert(counter <= m_transitions_per_cycle);
564 if (counter == m_transitions_per_cycle) {
565 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized
566 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again
567 break;
568 }
569''')
570
571 code.indent()
572 code.indent()
573
574 # InPorts
575 #
576 for port in self.in_ports:
577 code.indent()
578 code('// ${ident}InPort $port')
579 code('${{port["c_code_in_port"]}}')
580 code.dedent()
581
582 code('')
583
584 code.dedent()
585 code.dedent()
586 code('''
587 break; // If we got this far, we have nothing left todo
588 }
589}
590''')
591
592 code.write(path, "%s_Wakeup.cc" % self.ident)
593
594 def printCSwitch(self, path):
595 '''Output switch statement for transition table'''
596
597 code = code_formatter()
598 ident = self.ident
599
600 code('''
601// Auto generated C++ code started by $__file__:$__line__
602// ${ident}: ${{self.short}}
603
604#include "mem/ruby/common/Global.hh"
605#include "mem/protocol/${ident}_Controller.hh"
606#include "mem/protocol/${ident}_State.hh"
607#include "mem/protocol/${ident}_Event.hh"
608#include "mem/protocol/Types.hh"
609#include "mem/ruby/system/System.hh"
610
611#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
612
613#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
614#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
615
616TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr
617)
618{
619 ${ident}_State next_state = state;
620
621 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
622 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
623 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
624 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
625 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
626 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
627
628 TransitionResult result = doTransitionWorker(event, state, next_state, addr);
629
630 if (result == TransitionResult_Valid) {
631 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
632 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
633 s_profiler.countTransition(state, event);
634 if (Debug::getProtocolTrace()) {
635 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
636 ${ident}_State_to_string(state),
637 ${ident}_Event_to_string(event),
638 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT());
639 }
640 CLEAR_TRANSITION_COMMENT();
641 ${ident}_setState(addr, next_state);
642
643 } else if (result == TransitionResult_ResourceStall) {
644 if (Debug::getProtocolTrace()) {
645 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
646 ${ident}_State_to_string(state),
647 ${ident}_Event_to_string(event),
648 ${ident}_State_to_string(next_state),
649 "Resource Stall");
650 }
651 } else if (result == TransitionResult_ProtocolStall) {
652 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
653 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
654 if (Debug::getProtocolTrace()) {
655 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
656 ${ident}_State_to_string(state),
657 ${ident}_Event_to_string(event),
658 ${ident}_State_to_string(next_state),
659 "Protocol Stall");
660 }
661 }
662
663 return result;
664}
665
666TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr
667)
668{
669 switch(HASH_FUN(state, event)) {
670''')
671
672 # This map will allow suppress generating duplicate code
673 cases = orderdict()
674
675 for trans in self.transitions:
676 case_string = "%s_State_%s, %s_Event_%s" % \
677 (self.ident, trans.state.ident, self.ident, trans.event.ident)
678
679 case = code_formatter()
680 # Only set next_state if it changes
681 if trans.state != trans.nextState:
682 ns_ident = trans.nextState.ident
683 case('next_state = ${ident}_State_${ns_ident};')
684
685 actions = trans.actions
686
687 # Check for resources
688 case_sorter = []
689 res = trans.resources
690 for key,val in res.iteritems():
691 if key.type.ident != "DNUCAStopTable":
692 val = '''
693if (!%s.areNSlotsAvailable(%s)) {
694 return TransitionResult_ResourceStall;
695}
696''' % (key.code, val)
697 case_sorter.append(val)
698
699
700 # Emit the code sequences in a sorted order. This makes the
701 # output deterministic (without this the output order can vary
702 # since Map's keys() on a vector of pointers is not deterministic
703 for c in sorted(case_sorter):
704 case("$c")
705
706 # Figure out if we stall
707 stall = False
708 for action in actions:
709 if action.ident == "z_stall":
710 stall = True
711 break
712
713 if stall:
714 case('return TransitionResult_ProtocolStall;')
715 else:
716 for action in actions:
717 case('${{action.ident}}(addr);')
718 case('return TransitionResult_Valid;')
719
720 case = str(case)
721
722 # Look to see if this transition code is unique.
723 if case not in cases:
724 cases[case] = []
725
726 cases[case].append(case_string)
727
728 # Walk through all of the unique code blocks and spit out the
729 # corresponding case statement elements
730 for case,transitions in cases.iteritems():
731 # Iterative over all the multiple transitions that share
732 # the same code
733 for trans in transitions:
734 code(' case HASH_FUN($trans):')
735 code(' {')
736 code(' $case')
737 code(' }')
738
739 code('''
740 default:
741 WARN_EXPR(m_version);
742 WARN_EXPR(g_eventQueue_ptr->getTime());
743 WARN_EXPR(addr);
744 WARN_EXPR(event);
745 WARN_EXPR(state);
746 ERROR_MSG(\"Invalid transition\");
747 }
748 return TransitionResult_Valid;
749}
750''')
751 code.write(path, "%s_Transitions.cc" % self.ident)
752
753 def printProfilerHH(self, path):
754 code = code_formatter()
755 ident = self.ident
756
757 code('''
758// Auto generated C++ code started by $__file__:$__line__
759// ${ident}: ${{self.short}}
760
761#ifndef ${ident}_PROFILER_H
762#define ${ident}_PROFILER_H
763
764#include "mem/ruby/common/Global.hh"
765#include "mem/protocol/${ident}_State.hh"
766#include "mem/protocol/${ident}_Event.hh"
767
768class ${ident}_Profiler {
769 public:
770 ${ident}_Profiler();
771 void setVersion(int version);
772 void countTransition(${ident}_State state, ${ident}_Event event);
773 void possibleTransition(${ident}_State state, ${ident}_Event event);
774 void dumpStats(ostream& out) const;
775 void clearStats();
776
777 private:
778 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
779 int m_event_counters[${ident}_Event_NUM];
780 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
781 int m_version;
782};
783
784#endif // ${ident}_PROFILER_H
785''')
786 code.write(path, "%s_Profiler.hh" % self.ident)
787
788 def printProfilerCC(self, path):
789 code = code_formatter()
790 ident = self.ident
791
792 code('''
793// Auto generated C++ code started by $__file__:$__line__
794// ${ident}: ${{self.short}}
795
796#include "mem/protocol/${ident}_Profiler.hh"
797
798${ident}_Profiler::${ident}_Profiler()
799{
800 for (int state = 0; state < ${ident}_State_NUM; state++) {
801 for (int event = 0; event < ${ident}_Event_NUM; event++) {
802 m_possible[state][event] = false;
803 m_counters[state][event] = 0;
804 }
805 }
806 for (int event = 0; event < ${ident}_Event_NUM; event++) {
807 m_event_counters[event] = 0;
808 }
809}
810void ${ident}_Profiler::setVersion(int version)
811{
812 m_version = version;
813}
814void ${ident}_Profiler::clearStats()
815{
816 for (int state = 0; state < ${ident}_State_NUM; state++) {
817 for (int event = 0; event < ${ident}_Event_NUM; event++) {
818 m_counters[state][event] = 0;
819 }
820 }
821
822 for (int event = 0; event < ${ident}_Event_NUM; event++) {
823 m_event_counters[event] = 0;
824 }
825}
826void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
827{
828 assert(m_possible[state][event]);
829 m_counters[state][event]++;
830 m_event_counters[event]++;
831}
832void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event)
833{
834 m_possible[state][event] = true;
835}
836void ${ident}_Profiler::dumpStats(ostream& out) const
837{
838 out << " --- ${ident} " << m_version << " ---" << endl;
839 out << " - Event Counts -" << endl;
840 for (int event = 0; event < ${ident}_Event_NUM; event++) {
841 int count = m_event_counters[event];
842 out << (${ident}_Event) event << " " << count << endl;
843 }
844 out << endl;
845 out << " - Transitions -" << endl;
846 for (int state = 0; state < ${ident}_State_NUM; state++) {
847 for (int event = 0; event < ${ident}_Event_NUM; event++) {
848 if (m_possible[state][event]) {
849 int count = m_counters[state][event];
850 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count;
851 if (count == 0) {
852 out << " <-- ";
853 }
854 out << endl;
855 }
856 }
857 out << endl;
858 }
859}
860''')
861 code.write(path, "%s_Profiler.cc" % self.ident)
862
863 # **************************
864 # ******* HTML Files *******
865 # **************************
866 def frameRef(self, click_href, click_target, over_href, over_target_num,
867 text):
868 code = code_formatter(fix_newlines=False)
869 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""")
870 return str(code)
871
872 def writeHTMLFiles(self, path):
873 # Create table with no row hilighted
874 self.printHTMLTransitions(path, None)
875
876 # Generate transition tables
877 for state in self.states.itervalues():
878 self.printHTMLTransitions(path, state)
879
880 # Generate action descriptions
881 for action in self.actions.itervalues():
882 name = "%s_action_%s.html" % (self.ident, action.ident)
883 code = html.createSymbol(action, "Action")
884 code.write(path, name)
885
886 # Generate state descriptions
887 for state in self.states.itervalues():
888 name = "%s_State_%s.html" % (self.ident, state.ident)
889 code = html.createSymbol(state, "State")
890 code.write(path, name)
891
892 # Generate event descriptions
893 for event in self.events.itervalues():
894 name = "%s_Event_%s.html" % (self.ident, event.ident)
895 code = html.createSymbol(event, "Event")
896 code.write(path, name)
897
898 def printHTMLTransitions(self, path, active_state):
899 code = code_formatter()
900
901 code('''
902<HTML><BODY link="blue" vlink="blue">
903
904<H1 align="center">${{html.formatShorthand(self.short)}}:
905''')
906 code.indent()
907 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
908 mid = machine.ident
909 if i != 0:
910 extra = " - "
911 else:
912 extra = ""
913 if machine == self:
914 code('$extra$mid')
915 else:
916 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
917 code.dedent()
918
919 code("""
920</H1>
921
922<TABLE border=1>
923<TR>
924 <TH> </TH>
925""")
926
927 for event in self.events.itervalues():
928 href = "%s_Event_%s.html" % (self.ident, event.ident)
929 ref = self.frameRef(href, "Status", href, "1", event.short)
930 code('<TH bgcolor=white>$ref</TH>')
931
932 code('</TR>')
933 # -- Body of table
934 for state in self.states.itervalues():
935 # -- Each row
936 if state == active_state:
937 color = "yellow"
938 else:
939 color = "white"
940
941 click = "%s_table_%s.html" % (self.ident, state.ident)
942 over = "%s_State_%s.html" % (self.ident, state.ident)
943 text = html.formatShorthand(state.short)
944 ref = self.frameRef(click, "Table", over, "1", state.short)
945 code('''
946<TR>
947 <TH bgcolor=$color>$ref</TH>
948''')
949
950 # -- One column for each event
951 for event in self.events.itervalues():
952 trans = self.table.get((state,event), None)
953 if trans is None:
954 # This is the no transition case
955 if state == active_state:
956 color = "#C0C000"
957 else:
958 color = "lightgrey"
959
960 code('<TD bgcolor=$color>&nbsp;</TD>')
961 continue
962
963 next = trans.nextState
964 stall_action = False
965
966 # -- Get the actions
967 for action in trans.actions:
968 if action.ident == "z_stall" or \
969 action.ident == "zz_recycleMandatoryQueue":
970 stall_action = True
971
972 # -- Print out "actions/next-state"
973 if stall_action:
974 if state == active_state:
975 color = "#C0C000"
976 else:
977 color = "lightgrey"
978
979 elif active_state and next.ident == active_state.ident:
980 color = "aqua"
981 elif state == active_state:
982 color = "yellow"
983 else:
984 color = "white"
985
986 fix = code.nofix()
987 code('<TD bgcolor=$color>')
988 for action in trans.actions:
989 href = "%s_action_%s.html" % (self.ident, action.ident)
990 ref = self.frameRef(href, "Status", href, "1",
991 action.short)
992 code(' $ref\n')
993 if next != state:
994 if trans.actions:
995 code('/')
996 click = "%s_table_%s.html" % (self.ident, next.ident)
997 over = "%s_State_%s.html" % (self.ident, next.ident)
998 ref = self.frameRef(click, "Table", over, "1", next.short)
999 code("$ref")
1000 code("</TD>\n")
1001 code.fix(fix)
1002
1003 # -- Each row
1004 if state == active_state:
1005 color = "yellow"
1006 else:
1007 color = "white"
1008
1009 click = "%s_table_%s.html" % (self.ident, state.ident)
1010 over = "%s_State_%s.html" % (self.ident, state.ident)
1011 ref = self.frameRef(click, "Table", over, "1", state.short)
1012 code('''
1013 <TH bgcolor=$color>$ref</TH>
1014</TR>
1015''')
1016 code('''
1017<TR>
1018 <TH> </TH>
1019''')
1020
1021 for event in self.events.itervalues():
1022 href = "%s_Event_%s.html" % (self.ident, event.ident)
1023 ref = self.frameRef(href, "Status", href, "1", event.short)
1024 code('<TH bgcolor=white>$ref</TH>')
1025 code('''
1026</TR>
1027</TABLE>
1028</BODY></HTML>
1029''')
1030
1031
1032 if active_state:
1033 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1034 else:
1035 name = "%s_table.html" % self.ident
1036 code.write(path, name)
1037
1038__all__ = [ "StateMachine" ]
346
347 // Objects
348 s_profiler.setVersion(m_version);
349''')
350
351 code.indent()
352 for var in self.objects:
353 vtype = var.type
354 vid = "m_%s_ptr" % var.c_ident
355 if "network" not in var:
356 # Not a network port object
357 if "primitive" in vtype:
358 code('$vid = new ${{vtype.c_ident}};')
359 if "default" in var:
360 code('(*$vid) = ${{var["default"]}};')
361 else:
362 # Normal Object
363 # added by SS
364 if "factory" in var:
365 code('$vid = ${{var["factory"]}};')
366 elif var.ident.find("mandatoryQueue") < 0:
367 th = var.get("template_hack", "")
368 expr = "%s = new %s%s" % (vid, vtype.c_ident, th)
369
370 args = ""
371 if "non_obj" not in vtype and not vtype.isEnumeration:
372 if expr.find("TBETable") >= 0:
373 args = "m_number_of_TBEs"
374 else:
375 args = var.get("constructor_hack", "")
376 args = "(%s)" % args
377
378 code('$expr$args;')
379 else:
380 code(';')
381
382 code('assert($vid != NULL);')
383
384 if "default" in var:
385 code('(*$vid) = ${{var["default"]}}; // Object default')
386 elif "default" in vtype:
387 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default')
388
389 # Set ordering
390 if "ordered" in var and "trigger_queue" not in var:
391 # A buffer
392 code('$vid->setOrdering(${{var["ordered"]}});')
393
394 # Set randomization
395 if "random" in var:
396 # A buffer
397 code('$vid->setRandomization(${{var["random"]}});')
398
399 # Set Priority
400 if vtype.isBuffer and \
401 "rank" in var and "trigger_queue" not in var:
402 code('$vid->setPriority(${{var["rank"]}});')
403 else:
404 # Network port object
405 network = var["network"]
406 ordered = var["ordered"]
407 vnet = var["virtual_network"]
408
409 assert var.machine is not None
410 code('''
411$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet);
412''')
413
414 code('assert($vid != NULL);')
415
416 # Set ordering
417 if "ordered" in var:
418 # A buffer
419 code('$vid->setOrdering(${{var["ordered"]}});')
420
421 # Set randomization
422 if "random" in var:
423 # A buffer
424 code('$vid->setRandomization(${{var["random"]}})')
425
426 # Set Priority
427 if "rank" in var:
428 code('$vid->setPriority(${{var["rank"]}})')
429
430 # Set buffer size
431 if vtype.isBuffer:
432 code('''
433if (m_buffer_size > 0) {
434 $vid->setSize(m_buffer_size);
435}
436''')
437
438 # set description (may be overriden later by port def)
439 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");')
440
441 # Set the queue consumers
442 code.insert_newline()
443 for port in self.in_ports:
444 code('${{port.code}}.setConsumer(this);')
445
446 # Set the queue descriptions
447 code.insert_newline()
448 for port in self.in_ports:
449 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");')
450
451 # Initialize the transition profiling
452 code.insert_newline()
453 for trans in self.transitions:
454 # Figure out if we stall
455 stall = False
456 for action in trans.actions:
457 if action.ident == "z_stall":
458 stall = True
459
460 # Only possible if it is not a 'z' case
461 if not stall:
462 state = "%s_State_%s" % (self.ident, trans.state.ident)
463 event = "%s_Event_%s" % (self.ident, trans.event.ident)
464 code('s_profiler.possibleTransition($state, $event);')
465
466 # added by SS to initialize recycle_latency of message buffers
467 for buf in self.message_buffer_names:
468 code("$buf->setRecycleLatency(m_recycle_latency);")
469
470 code.dedent()
471 code('}')
472
473 has_mandatory_q = False
474 for port in self.in_ports:
475 if port.code.find("mandatoryQueue_ptr") >= 0:
476 has_mandatory_q = True
477
478 if has_mandatory_q:
479 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident
480 else:
481 mq_ident = "NULL"
482
483 code('''
484int $c_ident::getNumControllers() {
485 return m_num_controllers;
486}
487
488MessageBuffer* $c_ident::getMandatoryQueue() const {
489 return $mq_ident;
490}
491
492const int & $c_ident::getVersion() const{
493 return m_version;
494}
495
496const string $c_ident::toString() const{
497 return "$c_ident";
498}
499
500const string $c_ident::getName() const{
501 return m_name;
502}
503const MachineType $c_ident::getMachineType() const{
504 return MachineType_${ident};
505}
506
507void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) {
508 m_is_blocking = true;
509 m_block_map[addr] = port;
510}
511void $c_ident::unblock(Address addr) {
512 m_block_map.erase(addr);
513 if (m_block_map.size() == 0) {
514 m_is_blocking = false;
515 }
516}
517
518void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; }
519
520void $c_ident::printConfig(ostream& out) const {
521 out << "$c_ident config: " << m_name << endl;
522 out << " version: " << m_version << endl;
523 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) {
524 out << " " << (*it).first << ": " << (*it).second << endl;
525 }
526}
527
528// Actions
529''')
530
531 for action in self.actions.itervalues():
532 if "c_code" not in action:
533 continue
534
535 code('''
536/** \\brief ${{action.desc}} */
537void $c_ident::${{action.ident}}(const Address& addr)
538{
539 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
540 ${{action["c_code"]}}
541}
542
543''')
544 code.write(path, "%s.cc" % c_ident)
545
546 def printCWakeup(self, path):
547 '''Output the wakeup loop for the events'''
548
549 code = code_formatter()
550 ident = self.ident
551
552 code('''
553// Auto generated C++ code started by $__file__:$__line__
554// ${ident}: ${{self.short}}
555
556#include "mem/ruby/common/Global.hh"
557#include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
558#include "mem/protocol/${ident}_Controller.hh"
559#include "mem/protocol/${ident}_State.hh"
560#include "mem/protocol/${ident}_Event.hh"
561#include "mem/protocol/Types.hh"
562#include "mem/ruby/system/System.hh"
563
564void ${ident}_Controller::wakeup()
565{
566
567 int counter = 0;
568 while (true) {
569 // Some cases will put us into an infinite loop without this limit
570 assert(counter <= m_transitions_per_cycle);
571 if (counter == m_transitions_per_cycle) {
572 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized
573 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again
574 break;
575 }
576''')
577
578 code.indent()
579 code.indent()
580
581 # InPorts
582 #
583 for port in self.in_ports:
584 code.indent()
585 code('// ${ident}InPort $port')
586 code('${{port["c_code_in_port"]}}')
587 code.dedent()
588
589 code('')
590
591 code.dedent()
592 code.dedent()
593 code('''
594 break; // If we got this far, we have nothing left todo
595 }
596}
597''')
598
599 code.write(path, "%s_Wakeup.cc" % self.ident)
600
601 def printCSwitch(self, path):
602 '''Output switch statement for transition table'''
603
604 code = code_formatter()
605 ident = self.ident
606
607 code('''
608// Auto generated C++ code started by $__file__:$__line__
609// ${ident}: ${{self.short}}
610
611#include "mem/ruby/common/Global.hh"
612#include "mem/protocol/${ident}_Controller.hh"
613#include "mem/protocol/${ident}_State.hh"
614#include "mem/protocol/${ident}_Event.hh"
615#include "mem/protocol/Types.hh"
616#include "mem/ruby/system/System.hh"
617
618#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
619
620#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
621#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
622
623TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr
624)
625{
626 ${ident}_State next_state = state;
627
628 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
629 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
630 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
631 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
632 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
633 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
634
635 TransitionResult result = doTransitionWorker(event, state, next_state, addr);
636
637 if (result == TransitionResult_Valid) {
638 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
639 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
640 s_profiler.countTransition(state, event);
641 if (Debug::getProtocolTrace()) {
642 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
643 ${ident}_State_to_string(state),
644 ${ident}_Event_to_string(event),
645 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT());
646 }
647 CLEAR_TRANSITION_COMMENT();
648 ${ident}_setState(addr, next_state);
649
650 } else if (result == TransitionResult_ResourceStall) {
651 if (Debug::getProtocolTrace()) {
652 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
653 ${ident}_State_to_string(state),
654 ${ident}_Event_to_string(event),
655 ${ident}_State_to_string(next_state),
656 "Resource Stall");
657 }
658 } else if (result == TransitionResult_ProtocolStall) {
659 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
660 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
661 if (Debug::getProtocolTrace()) {
662 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
663 ${ident}_State_to_string(state),
664 ${ident}_Event_to_string(event),
665 ${ident}_State_to_string(next_state),
666 "Protocol Stall");
667 }
668 }
669
670 return result;
671}
672
673TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr
674)
675{
676 switch(HASH_FUN(state, event)) {
677''')
678
679 # This map will allow suppress generating duplicate code
680 cases = orderdict()
681
682 for trans in self.transitions:
683 case_string = "%s_State_%s, %s_Event_%s" % \
684 (self.ident, trans.state.ident, self.ident, trans.event.ident)
685
686 case = code_formatter()
687 # Only set next_state if it changes
688 if trans.state != trans.nextState:
689 ns_ident = trans.nextState.ident
690 case('next_state = ${ident}_State_${ns_ident};')
691
692 actions = trans.actions
693
694 # Check for resources
695 case_sorter = []
696 res = trans.resources
697 for key,val in res.iteritems():
698 if key.type.ident != "DNUCAStopTable":
699 val = '''
700if (!%s.areNSlotsAvailable(%s)) {
701 return TransitionResult_ResourceStall;
702}
703''' % (key.code, val)
704 case_sorter.append(val)
705
706
707 # Emit the code sequences in a sorted order. This makes the
708 # output deterministic (without this the output order can vary
709 # since Map's keys() on a vector of pointers is not deterministic
710 for c in sorted(case_sorter):
711 case("$c")
712
713 # Figure out if we stall
714 stall = False
715 for action in actions:
716 if action.ident == "z_stall":
717 stall = True
718 break
719
720 if stall:
721 case('return TransitionResult_ProtocolStall;')
722 else:
723 for action in actions:
724 case('${{action.ident}}(addr);')
725 case('return TransitionResult_Valid;')
726
727 case = str(case)
728
729 # Look to see if this transition code is unique.
730 if case not in cases:
731 cases[case] = []
732
733 cases[case].append(case_string)
734
735 # Walk through all of the unique code blocks and spit out the
736 # corresponding case statement elements
737 for case,transitions in cases.iteritems():
738 # Iterative over all the multiple transitions that share
739 # the same code
740 for trans in transitions:
741 code(' case HASH_FUN($trans):')
742 code(' {')
743 code(' $case')
744 code(' }')
745
746 code('''
747 default:
748 WARN_EXPR(m_version);
749 WARN_EXPR(g_eventQueue_ptr->getTime());
750 WARN_EXPR(addr);
751 WARN_EXPR(event);
752 WARN_EXPR(state);
753 ERROR_MSG(\"Invalid transition\");
754 }
755 return TransitionResult_Valid;
756}
757''')
758 code.write(path, "%s_Transitions.cc" % self.ident)
759
760 def printProfilerHH(self, path):
761 code = code_formatter()
762 ident = self.ident
763
764 code('''
765// Auto generated C++ code started by $__file__:$__line__
766// ${ident}: ${{self.short}}
767
768#ifndef ${ident}_PROFILER_H
769#define ${ident}_PROFILER_H
770
771#include "mem/ruby/common/Global.hh"
772#include "mem/protocol/${ident}_State.hh"
773#include "mem/protocol/${ident}_Event.hh"
774
775class ${ident}_Profiler {
776 public:
777 ${ident}_Profiler();
778 void setVersion(int version);
779 void countTransition(${ident}_State state, ${ident}_Event event);
780 void possibleTransition(${ident}_State state, ${ident}_Event event);
781 void dumpStats(ostream& out) const;
782 void clearStats();
783
784 private:
785 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
786 int m_event_counters[${ident}_Event_NUM];
787 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
788 int m_version;
789};
790
791#endif // ${ident}_PROFILER_H
792''')
793 code.write(path, "%s_Profiler.hh" % self.ident)
794
795 def printProfilerCC(self, path):
796 code = code_formatter()
797 ident = self.ident
798
799 code('''
800// Auto generated C++ code started by $__file__:$__line__
801// ${ident}: ${{self.short}}
802
803#include "mem/protocol/${ident}_Profiler.hh"
804
805${ident}_Profiler::${ident}_Profiler()
806{
807 for (int state = 0; state < ${ident}_State_NUM; state++) {
808 for (int event = 0; event < ${ident}_Event_NUM; event++) {
809 m_possible[state][event] = false;
810 m_counters[state][event] = 0;
811 }
812 }
813 for (int event = 0; event < ${ident}_Event_NUM; event++) {
814 m_event_counters[event] = 0;
815 }
816}
817void ${ident}_Profiler::setVersion(int version)
818{
819 m_version = version;
820}
821void ${ident}_Profiler::clearStats()
822{
823 for (int state = 0; state < ${ident}_State_NUM; state++) {
824 for (int event = 0; event < ${ident}_Event_NUM; event++) {
825 m_counters[state][event] = 0;
826 }
827 }
828
829 for (int event = 0; event < ${ident}_Event_NUM; event++) {
830 m_event_counters[event] = 0;
831 }
832}
833void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
834{
835 assert(m_possible[state][event]);
836 m_counters[state][event]++;
837 m_event_counters[event]++;
838}
839void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event)
840{
841 m_possible[state][event] = true;
842}
843void ${ident}_Profiler::dumpStats(ostream& out) const
844{
845 out << " --- ${ident} " << m_version << " ---" << endl;
846 out << " - Event Counts -" << endl;
847 for (int event = 0; event < ${ident}_Event_NUM; event++) {
848 int count = m_event_counters[event];
849 out << (${ident}_Event) event << " " << count << endl;
850 }
851 out << endl;
852 out << " - Transitions -" << endl;
853 for (int state = 0; state < ${ident}_State_NUM; state++) {
854 for (int event = 0; event < ${ident}_Event_NUM; event++) {
855 if (m_possible[state][event]) {
856 int count = m_counters[state][event];
857 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count;
858 if (count == 0) {
859 out << " <-- ";
860 }
861 out << endl;
862 }
863 }
864 out << endl;
865 }
866}
867''')
868 code.write(path, "%s_Profiler.cc" % self.ident)
869
870 # **************************
871 # ******* HTML Files *******
872 # **************************
873 def frameRef(self, click_href, click_target, over_href, over_target_num,
874 text):
875 code = code_formatter(fix_newlines=False)
876 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""")
877 return str(code)
878
879 def writeHTMLFiles(self, path):
880 # Create table with no row hilighted
881 self.printHTMLTransitions(path, None)
882
883 # Generate transition tables
884 for state in self.states.itervalues():
885 self.printHTMLTransitions(path, state)
886
887 # Generate action descriptions
888 for action in self.actions.itervalues():
889 name = "%s_action_%s.html" % (self.ident, action.ident)
890 code = html.createSymbol(action, "Action")
891 code.write(path, name)
892
893 # Generate state descriptions
894 for state in self.states.itervalues():
895 name = "%s_State_%s.html" % (self.ident, state.ident)
896 code = html.createSymbol(state, "State")
897 code.write(path, name)
898
899 # Generate event descriptions
900 for event in self.events.itervalues():
901 name = "%s_Event_%s.html" % (self.ident, event.ident)
902 code = html.createSymbol(event, "Event")
903 code.write(path, name)
904
905 def printHTMLTransitions(self, path, active_state):
906 code = code_formatter()
907
908 code('''
909<HTML><BODY link="blue" vlink="blue">
910
911<H1 align="center">${{html.formatShorthand(self.short)}}:
912''')
913 code.indent()
914 for i,machine in enumerate(self.symtab.getAllType(StateMachine)):
915 mid = machine.ident
916 if i != 0:
917 extra = " - "
918 else:
919 extra = ""
920 if machine == self:
921 code('$extra$mid')
922 else:
923 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
924 code.dedent()
925
926 code("""
927</H1>
928
929<TABLE border=1>
930<TR>
931 <TH> </TH>
932""")
933
934 for event in self.events.itervalues():
935 href = "%s_Event_%s.html" % (self.ident, event.ident)
936 ref = self.frameRef(href, "Status", href, "1", event.short)
937 code('<TH bgcolor=white>$ref</TH>')
938
939 code('</TR>')
940 # -- Body of table
941 for state in self.states.itervalues():
942 # -- Each row
943 if state == active_state:
944 color = "yellow"
945 else:
946 color = "white"
947
948 click = "%s_table_%s.html" % (self.ident, state.ident)
949 over = "%s_State_%s.html" % (self.ident, state.ident)
950 text = html.formatShorthand(state.short)
951 ref = self.frameRef(click, "Table", over, "1", state.short)
952 code('''
953<TR>
954 <TH bgcolor=$color>$ref</TH>
955''')
956
957 # -- One column for each event
958 for event in self.events.itervalues():
959 trans = self.table.get((state,event), None)
960 if trans is None:
961 # This is the no transition case
962 if state == active_state:
963 color = "#C0C000"
964 else:
965 color = "lightgrey"
966
967 code('<TD bgcolor=$color>&nbsp;</TD>')
968 continue
969
970 next = trans.nextState
971 stall_action = False
972
973 # -- Get the actions
974 for action in trans.actions:
975 if action.ident == "z_stall" or \
976 action.ident == "zz_recycleMandatoryQueue":
977 stall_action = True
978
979 # -- Print out "actions/next-state"
980 if stall_action:
981 if state == active_state:
982 color = "#C0C000"
983 else:
984 color = "lightgrey"
985
986 elif active_state and next.ident == active_state.ident:
987 color = "aqua"
988 elif state == active_state:
989 color = "yellow"
990 else:
991 color = "white"
992
993 fix = code.nofix()
994 code('<TD bgcolor=$color>')
995 for action in trans.actions:
996 href = "%s_action_%s.html" % (self.ident, action.ident)
997 ref = self.frameRef(href, "Status", href, "1",
998 action.short)
999 code(' $ref\n')
1000 if next != state:
1001 if trans.actions:
1002 code('/')
1003 click = "%s_table_%s.html" % (self.ident, next.ident)
1004 over = "%s_State_%s.html" % (self.ident, next.ident)
1005 ref = self.frameRef(click, "Table", over, "1", next.short)
1006 code("$ref")
1007 code("</TD>\n")
1008 code.fix(fix)
1009
1010 # -- Each row
1011 if state == active_state:
1012 color = "yellow"
1013 else:
1014 color = "white"
1015
1016 click = "%s_table_%s.html" % (self.ident, state.ident)
1017 over = "%s_State_%s.html" % (self.ident, state.ident)
1018 ref = self.frameRef(click, "Table", over, "1", state.short)
1019 code('''
1020 <TH bgcolor=$color>$ref</TH>
1021</TR>
1022''')
1023 code('''
1024<TR>
1025 <TH> </TH>
1026''')
1027
1028 for event in self.events.itervalues():
1029 href = "%s_Event_%s.html" % (self.ident, event.ident)
1030 ref = self.frameRef(href, "Status", href, "1", event.short)
1031 code('<TH bgcolor=white>$ref</TH>')
1032 code('''
1033</TR>
1034</TABLE>
1035</BODY></HTML>
1036''')
1037
1038
1039 if active_state:
1040 name = "%s_table_%s.html" % (self.ident, active_state.ident)
1041 else:
1042 name = "%s_table.html" % self.ident
1043 code.write(path, name)
1044
1045__all__ = [ "StateMachine" ]