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