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