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