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