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