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