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