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