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