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