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