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