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