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