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