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