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