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