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