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