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