1 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2 # Copyright (c) 2009 The Hewlett-Packard Development Company
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.
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.
28 from m5
.util
import orderdict
30 from slicc
.symbols
.Symbol
import Symbol
31 from slicc
.symbols
.Var
import Var
32 import slicc
.generate
.html
as html
37 "uint32_t" : "UInt32",
38 "std::string": "String",
40 "CacheMemory": "RubyCache",
41 "WireBuffer": "RubyWireBuffer",
42 "Sequencer": "RubySequencer",
43 "DirectoryMemory": "RubyDirectoryMemory",
44 "MemoryControl": "MemoryControl",
45 "DMASequencer": "DMASequencer",
46 "Prefetcher":"Prefetcher",
50 class StateMachine(Symbol
):
51 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
52 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
54 self
.config_parameters
= config_parameters
57 for param
in config_parameters
:
59 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
60 "(*m_%s_ptr)" % param
.name
, {}, self
)
62 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
63 "m_%s" % param
.name
, {}, self
)
64 self
.symtab
.registerSym(param
.name
, var
)
65 if str(param
.type_ast
.type) == "Prefetcher":
66 self
.prefetchers
.append(var
)
68 self
.states
= orderdict()
69 self
.events
= orderdict()
70 self
.actions
= orderdict()
71 self
.request_types
= orderdict()
80 return "[StateMachine: %s]" % self
.ident
82 def addState(self
, state
):
83 assert self
.table
is None
84 self
.states
[state
.ident
] = state
86 def addEvent(self
, event
):
87 assert self
.table
is None
88 self
.events
[event
.ident
] = event
90 def addAction(self
, action
):
91 assert self
.table
is None
93 # Check for duplicate action
94 for other
in self
.actions
.itervalues():
95 if action
.ident
== other
.ident
:
96 action
.warning("Duplicate action definition: %s" % action
.ident
)
97 action
.error("Duplicate action definition: %s" % action
.ident
)
98 if action
.short
== other
.short
:
99 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
100 other
.warning(" shorthand = %s" % other
.short
)
101 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
102 action
.error(" shorthand = %s" % action
.short
)
104 self
.actions
[action
.ident
] = action
106 def addRequestType(self
, request_type
):
107 assert self
.table
is None
108 self
.request_types
[request_type
.ident
] = request_type
110 def addTransition(self
, trans
):
111 assert self
.table
is None
112 self
.transitions
.append(trans
)
114 def addInPort(self
, var
):
115 self
.in_ports
.append(var
)
117 def addFunc(self
, func
):
118 # register func in the symbol table
119 self
.symtab
.registerSym(str(func
), func
)
120 self
.functions
.append(func
)
122 def addObject(self
, obj
):
123 self
.objects
.append(obj
)
125 def addType(self
, type):
126 type_ident
= '%s' % type.c_ident
128 if type_ident
== "%s_TBE" %self
.ident
:
129 if self
.TBEType
!= None:
130 self
.error("Multiple Transaction Buffer types in a " \
134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
135 if self
.EntryType
!= None:
136 self
.error("Multiple AbstractCacheEntry types in a " \
138 self
.EntryType
= type
140 # Needs to be called before accessing the table
141 def buildTable(self
):
142 assert self
.table
is None
146 for trans
in self
.transitions
:
147 # Track which actions we touch so we know if we use them
148 # all -- really this should be done for all symbols as
149 # part of the symbol table, then only trigger it for
150 # Actions, States, Events, etc.
152 for action
in trans
.actions
:
155 index
= (trans
.state
, trans
.event
)
157 table
[index
].warning("Duplicate transition: %s" % table
[index
])
158 trans
.error("Duplicate transition: %s" % trans
)
161 # Look at all actions to make sure we used them all
162 for action
in self
.actions
.itervalues():
164 error_msg
= "Unused action: %s" % action
.ident
166 error_msg
+= ", " + action
.desc
167 action
.warning(error_msg
)
170 def writeCodeFiles(self
, path
, includes
):
171 self
.printControllerPython(path
)
172 self
.printControllerHH(path
)
173 self
.printControllerCC(path
, includes
)
174 self
.printCSwitch(path
)
175 self
.printCWakeup(path
, includes
)
177 def printControllerPython(self
, path
):
178 code
= self
.symtab
.codeFormatter()
180 py_ident
= "%s_Controller" % ident
181 c_ident
= "%s_Controller" % self
.ident
183 from m5.params import *
184 from m5.SimObject import SimObject
185 from Controller import RubyController
187 class $py_ident(RubyController):
189 cxx_header = 'mem/protocol/${c_ident}.hh'
192 for param
in self
.config_parameters
:
194 if param
.default
is not None:
195 dflt_str
= str(param
.default
) + ', '
196 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
197 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
198 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
200 self
.error("Unknown c++ to python class conversion for c++ " \
201 "type: '%s'. Please update the python_class_map " \
202 "in StateMachine.py", param
.type_ast
.type.c_ident
)
204 code
.write(path
, '%s.py' % py_ident
)
207 def printControllerHH(self
, path
):
208 '''Output the method declarations for the class declaration'''
209 code
= self
.symtab
.codeFormatter()
211 c_ident
= "%s_Controller" % self
.ident
214 /** \\file $c_ident.hh
216 * Auto generated C++ code started by $__file__:$__line__
217 * Created by slicc definition of Module "${{self.short}}"
220 #ifndef __${ident}_CONTROLLER_HH__
221 #define __${ident}_CONTROLLER_HH__
227 #include "mem/protocol/TransitionResult.hh"
228 #include "mem/protocol/Types.hh"
229 #include "mem/ruby/common/Consumer.hh"
230 #include "mem/ruby/common/Global.hh"
231 #include "mem/ruby/slicc_interface/AbstractController.hh"
232 #include "params/$c_ident.hh"
237 for var
in self
.objects
:
238 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
239 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
240 if "network" in var
and "physical_network" in var
:
242 seen_types
.add(var
.type.ident
)
244 # for adding information to the protocol debug trace
246 extern std::stringstream ${ident}_transitionComment;
248 class $c_ident : public AbstractController
251 typedef ${c_ident}Params Params;
252 $c_ident(const Params *p);
253 static int getNumControllers();
255 MessageBuffer* getMandatoryQueue() const;
256 const std::string toString() const;
258 void print(std::ostream& out) const;
264 void recordCacheTrace(int cntrl, CacheRecorder* tr);
265 Sequencer* getSequencer() const;
267 bool functionalReadBuffers(PacketPtr&);
268 uint32_t functionalWriteBuffers(PacketPtr&);
270 void countTransition(${ident}_State state, ${ident}_Event event);
271 void possibleTransition(${ident}_State state, ${ident}_Event event);
272 uint64 getEventCount(${ident}_Event event);
273 bool isPossible(${ident}_State state, ${ident}_Event event);
274 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
281 for param
in self
.config_parameters
:
283 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
285 code('${{param.type_ast.type}} m_${{param.ident}};')
288 TransitionResult doTransition(${ident}_Event event,
291 if self
.EntryType
!= None:
293 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
295 if self
.TBEType
!= None:
297 ${{self.TBEType.c_ident}}* m_tbe_ptr,
303 TransitionResult doTransitionWorker(${ident}_Event event,
304 ${ident}_State state,
305 ${ident}_State& next_state,
308 if self
.TBEType
!= None:
310 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
312 if self
.EntryType
!= None:
314 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
318 const Address& addr);
320 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
321 int m_event_counters[${ident}_Event_NUM];
322 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
324 static std::vector<Stats::Vector *> eventVec;
325 static std::vector<std::vector<Stats::Vector *> > transVec;
326 static int m_num_controllers;
328 // Internal functions
331 for func
in self
.functions
:
332 proto
= func
.prototype
337 code('void getQueuesFromPeer(AbstractController *);')
338 if self
.EntryType
!= None:
341 // Set and Reset for cache_entry variable
342 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
343 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
346 if self
.TBEType
!= None:
349 // Set and Reset for tbe variable
350 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
351 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
354 # Prototype the actions that the controller can take
359 if self
.TBEType
!= None and self
.EntryType
!= None:
360 for action
in self
.actions
.itervalues():
361 code('/** \\brief ${{action.desc}} */')
362 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
363 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& '
364 'm_cache_entry_ptr, const Address& addr);')
365 elif self
.TBEType
!= None:
366 for action
in self
.actions
.itervalues():
367 code('/** \\brief ${{action.desc}} */')
368 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& '
369 'm_tbe_ptr, const Address& addr);')
370 elif self
.EntryType
!= None:
371 for action
in self
.actions
.itervalues():
372 code('/** \\brief ${{action.desc}} */')
373 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& '
374 'm_cache_entry_ptr, const Address& addr);')
376 for action
in self
.actions
.itervalues():
377 code('/** \\brief ${{action.desc}} */')
378 code('void ${{action.ident}}(const Address& addr);')
380 # the controller internal variables
385 for var
in self
.objects
:
386 th
= var
.get("template", "")
387 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
391 code('#endif // __${ident}_CONTROLLER_H__')
392 code
.write(path
, '%s.hh' % c_ident
)
394 def printControllerCC(self
, path
, includes
):
395 '''Output the actions for performing the actions'''
397 code
= self
.symtab
.codeFormatter()
399 c_ident
= "%s_Controller" % self
.ident
403 /** \\file $c_ident.cc
405 * Auto generated C++ code started by $__file__:$__line__
406 * Created by slicc definition of Module "${{self.short}}"
409 #include <sys/types.h>
416 #include "base/compiler.hh"
417 #include "base/cprintf.hh"
418 #include "debug/RubyGenerated.hh"
419 #include "debug/RubySlicc.hh"
420 #include "mem/protocol/${ident}_Controller.hh"
421 #include "mem/protocol/${ident}_Event.hh"
422 #include "mem/protocol/${ident}_State.hh"
423 #include "mem/protocol/Types.hh"
424 #include "mem/ruby/common/Global.hh"
425 #include "mem/ruby/system/System.hh"
427 for include_path
in includes
:
428 code('#include "${{include_path}}"')
435 # include object classes
437 for var
in self
.objects
:
438 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
439 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
440 seen_types
.add(var
.type.ident
)
442 num_in_ports
= len(self
.in_ports
)
446 ${c_ident}Params::create()
448 return new $c_ident(this);
451 int $c_ident::m_num_controllers = 0;
452 std::vector<Stats::Vector *> $c_ident::eventVec;
453 std::vector<std::vector<Stats::Vector *> > $c_ident::transVec;
455 // for adding information to the protocol debug trace
456 stringstream ${ident}_transitionComment;
459 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
461 #define APPEND_TRANSITION_COMMENT(str) do {} while (0)
464 /** \\brief constructor */
465 $c_ident::$c_ident(const Params *p)
466 : AbstractController(p)
468 m_machineID.type = MachineType_${ident};
469 m_machineID.num = m_version;
472 m_in_ports = $num_in_ports;
477 # After initializing the universal machine parameters, initialize the
478 # this machines config parameters. Also if these configuration params
479 # include a sequencer, connect the it to the controller.
481 for param
in self
.config_parameters
:
483 code('m_${{param.name}}_ptr = p->${{param.name}};')
485 code('m_${{param.name}} = p->${{param.name}};')
486 if re
.compile("sequencer").search(param
.name
):
487 code('m_${{param.name}}_ptr->setController(this);')
489 for var
in self
.objects
:
490 if var
.ident
.find("mandatoryQueue") >= 0:
492 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
493 m_${{var.c_ident}}_ptr->setReceiver(this);
496 if "network" in var
and "physical_network" in var
and \
497 var
["network"] == "To":
500 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
501 peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
502 m_${{var.c_ident}}_ptr->setSender(this);
507 connectWithPeer(p->peer);
509 for (int state = 0; state < ${ident}_State_NUM; state++) {
510 for (int event = 0; event < ${ident}_Event_NUM; event++) {
511 m_possible[state][event] = false;
512 m_counters[state][event] = 0;
515 for (int event = 0; event < ${ident}_Event_NUM; event++) {
516 m_event_counters[event] = 0;
526 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
527 int base M5_VAR_USED = MachineType_base_number(machine_type);
529 // initialize objects
534 for var
in self
.objects
:
536 vid
= "m_%s_ptr" % var
.c_ident
537 if "network" not in var
:
538 # Not a network port object
539 if "primitive" in vtype
:
540 code('$vid = new ${{vtype.c_ident}};')
542 code('(*$vid) = ${{var["default"]}};')
545 if var
.ident
.find("mandatoryQueue") < 0:
546 th
= var
.get("template", "")
547 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
549 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
550 args
= var
.get("constructor", "")
551 code('$expr($args);')
553 code('assert($vid != NULL);')
556 code('*$vid = ${{var["default"]}}; // Object default')
557 elif "default" in vtype
:
558 comment
= "Type %s default" % vtype
.ident
559 code('*$vid = ${{vtype["default"]}}; // $comment')
564 code('$vid->setOrdering(${{var["ordered"]}});')
569 code('$vid->setRandomization(${{var["random"]}});')
572 if vtype
.isBuffer
and "rank" in var
:
573 code('$vid->setPriority(${{var["rank"]}});')
575 # Set sender and receiver for trigger queue
576 if var
.ident
.find("triggerQueue") >= 0:
577 code('$vid->setSender(this);')
578 code('$vid->setReceiver(this);')
579 elif vtype
.c_ident
== "TimerTable":
580 code('$vid->setClockObj(this);')
581 elif var
.ident
.find("optionalQueue") >= 0:
582 code('$vid->setSender(this);')
583 code('$vid->setReceiver(this);')
586 # Network port object
587 network
= var
["network"]
588 ordered
= var
["ordered"]
590 if "virtual_network" in var
:
591 vnet
= var
["virtual_network"]
592 vnet_type
= var
["vnet_type"]
594 assert var
.machine
is not None
596 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
597 assert($vid != NULL);
602 code('$vid->setSender(this);')
604 code('$vid->setReceiver(this);')
609 code('$vid->setOrdering(${{var["ordered"]}});')
614 code('$vid->setRandomization(${{var["random"]}});')
618 code('$vid->setPriority(${{var["rank"]}})')
623 if (m_buffer_size > 0) {
624 $vid->resize(m_buffer_size);
628 # set description (may be overriden later by port def)
630 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
635 if "recycle_latency" in var
:
636 code('$vid->setRecycleLatency( ' \
637 'Cycles(${{var["recycle_latency"]}}));')
639 code('$vid->setRecycleLatency(m_recycle_latency);')
641 # Set the prefetchers
643 for prefetcher
in self
.prefetchers
:
644 code('${{prefetcher.code}}.setController(this);')
647 for port
in self
.in_ports
:
648 # Set the queue consumers
649 code('${{port.code}}.setConsumer(this);')
650 # Set the queue descriptions
651 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
653 # Initialize the transition profiling
655 for trans
in self
.transitions
:
656 # Figure out if we stall
658 for action
in trans
.actions
:
659 if action
.ident
== "z_stall":
662 # Only possible if it is not a 'z' case
664 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
665 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
666 code('possibleTransition($state, $event);')
670 AbstractController::init();
676 for port
in self
.in_ports
:
677 if port
.code
.find("mandatoryQueue_ptr") >= 0:
678 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
681 for param
in self
.config_parameters
:
682 if param
.name
== "sequencer":
683 assert(param
.pointer
)
684 seq_ident
= "m_%s_ptr" % param
.name
691 AbstractController::regStats();
693 if (m_version == 0) {
694 for (${ident}_Event event = ${ident}_Event_FIRST;
695 event < ${ident}_Event_NUM; ++event) {
696 Stats::Vector *t = new Stats::Vector();
697 t->init(m_num_controllers);
698 t->name(g_system_ptr->name() + ".${c_ident}." +
699 ${ident}_Event_to_string(event));
700 t->flags(Stats::pdf | Stats::total | Stats::oneline |
703 eventVec.push_back(t);
706 for (${ident}_State state = ${ident}_State_FIRST;
707 state < ${ident}_State_NUM; ++state) {
709 transVec.push_back(std::vector<Stats::Vector *>());
711 for (${ident}_Event event = ${ident}_Event_FIRST;
712 event < ${ident}_Event_NUM; ++event) {
714 Stats::Vector *t = new Stats::Vector();
715 t->init(m_num_controllers);
716 t->name(g_system_ptr->name() + ".${c_ident}." +
717 ${ident}_State_to_string(state) +
718 "." + ${ident}_Event_to_string(event));
720 t->flags(Stats::pdf | Stats::total | Stats::oneline |
722 transVec[state].push_back(t);
729 $c_ident::collateStats()
731 for (${ident}_Event event = ${ident}_Event_FIRST;
732 event < ${ident}_Event_NUM; ++event) {
733 for (unsigned int i = 0; i < m_num_controllers; ++i) {
734 std::map<uint32_t, AbstractController *>::iterator it =
735 g_abs_controls[MachineType_${ident}].find(i);
736 assert(it != g_abs_controls[MachineType_${ident}].end());
737 (*eventVec[event])[i] =
738 (($c_ident *)(*it).second)->getEventCount(event);
742 for (${ident}_State state = ${ident}_State_FIRST;
743 state < ${ident}_State_NUM; ++state) {
745 for (${ident}_Event event = ${ident}_Event_FIRST;
746 event < ${ident}_Event_NUM; ++event) {
748 for (unsigned int i = 0; i < m_num_controllers; ++i) {
749 std::map<uint32_t, AbstractController *>::iterator it =
750 g_abs_controls[MachineType_${ident}].find(i);
751 assert(it != g_abs_controls[MachineType_${ident}].end());
752 (*transVec[state][event])[i] =
753 (($c_ident *)(*it).second)->getTransitionCount(state, event);
760 $c_ident::countTransition(${ident}_State state, ${ident}_Event event)
762 assert(m_possible[state][event]);
763 m_counters[state][event]++;
764 m_event_counters[event]++;
767 $c_ident::possibleTransition(${ident}_State state,
768 ${ident}_Event event)
770 m_possible[state][event] = true;
774 $c_ident::getEventCount(${ident}_Event event)
776 return m_event_counters[event];
780 $c_ident::isPossible(${ident}_State state, ${ident}_Event event)
782 return m_possible[state][event];
786 $c_ident::getTransitionCount(${ident}_State state,
787 ${ident}_Event event)
789 return m_counters[state][event];
793 $c_ident::getNumControllers()
795 return m_num_controllers;
799 $c_ident::getMandatoryQueue() const
805 $c_ident::getSequencer() const
811 $c_ident::toString() const
817 $c_ident::print(ostream& out) const
819 out << "[$c_ident " << m_version << "]";
822 void $c_ident::resetStats()
824 for (int state = 0; state < ${ident}_State_NUM; state++) {
825 for (int event = 0; event < ${ident}_Event_NUM; event++) {
826 m_counters[state][event] = 0;
830 for (int event = 0; event < ${ident}_Event_NUM; event++) {
831 m_event_counters[event] = 0;
834 AbstractController::resetStats();
838 if self
.EntryType
!= None:
841 // Set and Reset for cache_entry variable
843 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
845 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
849 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
851 m_cache_entry_ptr = 0;
855 if self
.TBEType
!= None:
858 // Set and Reset for tbe variable
860 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
862 m_tbe_ptr = m_new_tbe;
866 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
875 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
879 # Record cache contents for all associated caches.
882 for param
in self
.config_parameters
:
883 if param
.type_ast
.type.ident
== "CacheMemory":
884 assert(param
.pointer
)
885 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
893 if self
.TBEType
!= None and self
.EntryType
!= None:
894 for action
in self
.actions
.itervalues():
895 if "c_code" not in action
:
899 /** \\brief ${{action.desc}} */
901 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
903 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
904 ${{action["c_code"]}}
908 elif self
.TBEType
!= None:
909 for action
in self
.actions
.itervalues():
910 if "c_code" not in action
:
914 /** \\brief ${{action.desc}} */
916 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
918 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
919 ${{action["c_code"]}}
923 elif self
.EntryType
!= None:
924 for action
in self
.actions
.itervalues():
925 if "c_code" not in action
:
929 /** \\brief ${{action.desc}} */
931 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
933 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
934 ${{action["c_code"]}}
939 for action
in self
.actions
.itervalues():
940 if "c_code" not in action
:
944 /** \\brief ${{action.desc}} */
946 $c_ident::${{action.ident}}(const Address& addr)
948 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
949 ${{action["c_code"]}}
953 for func
in self
.functions
:
954 code(func
.generateCode())
956 # Function for functional reads from messages buffered in the controller
959 $c_ident::functionalReadBuffers(PacketPtr& pkt)
962 for var
in self
.objects
:
965 vid
= "m_%s_ptr" % var
.c_ident
966 code('if ($vid->functionalRead(pkt)) { return true; }')
972 # Function for functional writes to messages buffered in the controller
975 $c_ident::functionalWriteBuffers(PacketPtr& pkt)
977 uint32_t num_functional_writes = 0;
979 for var
in self
.objects
:
982 vid
= "m_%s_ptr" % var
.c_ident
983 code('num_functional_writes += $vid->functionalWrite(pkt);')
985 return num_functional_writes;
989 # Check if this controller has a peer, if yes then write the
990 # function for connecting to the peer.
995 $c_ident::getQueuesFromPeer(AbstractController *peer)
998 for var
in self
.objects
:
999 if "network" in var
and "physical_network" in var
and \
1000 var
["network"] == "From":
1002 m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1003 assert(m_${{var.c_ident}}_ptr != NULL);
1004 m_${{var.c_ident}}_ptr->setReceiver(this);
1009 code
.write(path
, "%s.cc" % c_ident
)
1011 def printCWakeup(self
, path
, includes
):
1012 '''Output the wakeup loop for the events'''
1014 code
= self
.symtab
.codeFormatter()
1017 outputRequest_types
= True
1018 if len(self
.request_types
) == 0:
1019 outputRequest_types
= False
1022 // Auto generated C++ code started by $__file__:$__line__
1023 // ${ident}: ${{self.short}}
1025 #include <sys/types.h>
1030 #include "base/misc.hh"
1031 #include "debug/RubySlicc.hh"
1032 #include "mem/protocol/${ident}_Controller.hh"
1033 #include "mem/protocol/${ident}_Event.hh"
1034 #include "mem/protocol/${ident}_State.hh"
1037 if outputRequest_types
:
1038 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1041 #include "mem/protocol/Types.hh"
1042 #include "mem/ruby/common/Global.hh"
1043 #include "mem/ruby/system/System.hh"
1047 for include_path
in includes
:
1048 code('#include "${{include_path}}"')
1052 using namespace std;
1055 ${ident}_Controller::wakeup()
1059 // Some cases will put us into an infinite loop without this limit
1060 assert(counter <= m_transitions_per_cycle);
1061 if (counter == m_transitions_per_cycle) {
1062 // Count how often we are fully utilized
1063 m_fully_busy_cycles++;
1065 // Wakeup in another cycle and try again
1066 scheduleEvent(Cycles(1));
1076 for port
in self
.in_ports
:
1078 code('// ${ident}InPort $port')
1079 if port
.pairs
.has_key("rank"):
1080 code('m_cur_in_port = ${{port.pairs["rank"]}};')
1082 code('m_cur_in_port = 0;')
1083 code('${{port["c_code_in_port"]}}')
1091 break; // If we got this far, we have nothing left todo
1096 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1098 def printCSwitch(self
, path
):
1099 '''Output switch statement for transition table'''
1101 code
= self
.symtab
.codeFormatter()
1105 // Auto generated C++ code started by $__file__:$__line__
1106 // ${ident}: ${{self.short}}
1110 #include "base/misc.hh"
1111 #include "base/trace.hh"
1112 #include "debug/ProtocolTrace.hh"
1113 #include "debug/RubyGenerated.hh"
1114 #include "mem/protocol/${ident}_Controller.hh"
1115 #include "mem/protocol/${ident}_Event.hh"
1116 #include "mem/protocol/${ident}_State.hh"
1117 #include "mem/protocol/Types.hh"
1118 #include "mem/ruby/common/Global.hh"
1119 #include "mem/ruby/system/System.hh"
1121 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1123 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1124 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1127 ${ident}_Controller::doTransition(${ident}_Event event,
1129 if self
.EntryType
!= None:
1131 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1133 if self
.TBEType
!= None:
1135 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1141 if self
.TBEType
!= None and self
.EntryType
!= None:
1142 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1143 elif self
.TBEType
!= None:
1144 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1145 elif self
.EntryType
!= None:
1146 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1148 code('${ident}_State state = getState(addr);')
1151 ${ident}_State next_state = state;
1153 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1154 *this, curCycle(), ${ident}_State_to_string(state),
1155 ${ident}_Event_to_string(event), addr);
1157 TransitionResult result =
1159 if self
.TBEType
!= None and self
.EntryType
!= None:
1160 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1161 elif self
.TBEType
!= None:
1162 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1163 elif self
.EntryType
!= None:
1164 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1166 code('doTransitionWorker(event, state, next_state, addr);')
1169 if (result == TransitionResult_Valid) {
1170 DPRINTF(RubyGenerated, "next_state: %s\\n",
1171 ${ident}_State_to_string(next_state));
1172 countTransition(state, event);
1173 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1174 curTick(), m_version, "${ident}",
1175 ${ident}_Event_to_string(event),
1176 ${ident}_State_to_string(state),
1177 ${ident}_State_to_string(next_state),
1178 addr, GET_TRANSITION_COMMENT());
1180 CLEAR_TRANSITION_COMMENT();
1182 if self
.TBEType
!= None and self
.EntryType
!= None:
1183 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1184 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1185 elif self
.TBEType
!= None:
1186 code('setState(m_tbe_ptr, addr, next_state);')
1187 code('setAccessPermission(addr, next_state);')
1188 elif self
.EntryType
!= None:
1189 code('setState(m_cache_entry_ptr, addr, next_state);')
1190 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1192 code('setState(addr, next_state);')
1193 code('setAccessPermission(addr, next_state);')
1196 } else if (result == TransitionResult_ResourceStall) {
1197 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1198 curTick(), m_version, "${ident}",
1199 ${ident}_Event_to_string(event),
1200 ${ident}_State_to_string(state),
1201 ${ident}_State_to_string(next_state),
1202 addr, "Resource Stall");
1203 } else if (result == TransitionResult_ProtocolStall) {
1204 DPRINTF(RubyGenerated, "stalling\\n");
1205 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1206 curTick(), m_version, "${ident}",
1207 ${ident}_Event_to_string(event),
1208 ${ident}_State_to_string(state),
1209 ${ident}_State_to_string(next_state),
1210 addr, "Protocol Stall");
1217 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1218 ${ident}_State state,
1219 ${ident}_State& next_state,
1222 if self
.TBEType
!= None:
1224 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1226 if self
.EntryType
!= None:
1228 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1231 const Address& addr)
1233 switch(HASH_FUN(state, event)) {
1236 # This map will allow suppress generating duplicate code
1239 for trans
in self
.transitions
:
1240 case_string
= "%s_State_%s, %s_Event_%s" % \
1241 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1243 case
= self
.symtab
.codeFormatter()
1244 # Only set next_state if it changes
1245 if trans
.state
!= trans
.nextState
:
1246 ns_ident
= trans
.nextState
.ident
1247 case('next_state = ${ident}_State_${ns_ident};')
1249 actions
= trans
.actions
1250 request_types
= trans
.request_types
1252 # Check for resources
1254 res
= trans
.resources
1255 for key
,val
in res
.iteritems():
1257 if (!%s.areNSlotsAvailable(%s))
1258 return TransitionResult_ResourceStall;
1259 ''' % (key
.code
, val
)
1260 case_sorter
.append(val
)
1262 # Check all of the request_types for resource constraints
1263 for request_type
in request_types
:
1265 if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1266 return TransitionResult_ResourceStall;
1268 ''' % (self
.ident
, request_type
.ident
)
1269 case_sorter
.append(val
)
1271 # Emit the code sequences in a sorted order. This makes the
1272 # output deterministic (without this the output order can vary
1273 # since Map's keys() on a vector of pointers is not deterministic
1274 for c
in sorted(case_sorter
):
1277 # Record access types for this transition
1278 for request_type
in request_types
:
1279 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1281 # Figure out if we stall
1283 for action
in actions
:
1284 if action
.ident
== "z_stall":
1289 case('return TransitionResult_ProtocolStall;')
1291 if self
.TBEType
!= None and self
.EntryType
!= None:
1292 for action
in actions
:
1293 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1294 elif self
.TBEType
!= None:
1295 for action
in actions
:
1296 case('${{action.ident}}(m_tbe_ptr, addr);')
1297 elif self
.EntryType
!= None:
1298 for action
in actions
:
1299 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1301 for action
in actions
:
1302 case('${{action.ident}}(addr);')
1303 case('return TransitionResult_Valid;')
1307 # Look to see if this transition code is unique.
1308 if case
not in cases
:
1311 cases
[case
].append(case_string
)
1313 # Walk through all of the unique code blocks and spit out the
1314 # corresponding case statement elements
1315 for case
,transitions
in cases
.iteritems():
1316 # Iterative over all the multiple transitions that share
1318 for trans
in transitions
:
1319 code(' case HASH_FUN($trans):')
1324 fatal("Invalid transition\\n"
1325 "%s time: %d addr: %s event: %s state: %s\\n",
1326 name(), curCycle(), addr, event, state);
1328 return TransitionResult_Valid;
1331 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1334 # **************************
1335 # ******* HTML Files *******
1336 # **************************
1337 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1338 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1339 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1340 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1341 parent.frames[$over_num].location='$over_href'
1343 ${{html.formatShorthand(text)}}
1347 def writeHTMLFiles(self
, path
):
1348 # Create table with no row hilighted
1349 self
.printHTMLTransitions(path
, None)
1351 # Generate transition tables
1352 for state
in self
.states
.itervalues():
1353 self
.printHTMLTransitions(path
, state
)
1355 # Generate action descriptions
1356 for action
in self
.actions
.itervalues():
1357 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1358 code
= html
.createSymbol(action
, "Action")
1359 code
.write(path
, name
)
1361 # Generate state descriptions
1362 for state
in self
.states
.itervalues():
1363 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1364 code
= html
.createSymbol(state
, "State")
1365 code
.write(path
, name
)
1367 # Generate event descriptions
1368 for event
in self
.events
.itervalues():
1369 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1370 code
= html
.createSymbol(event
, "Event")
1371 code
.write(path
, name
)
1373 def printHTMLTransitions(self
, path
, active_state
):
1374 code
= self
.symtab
.codeFormatter()
1378 <BODY link="blue" vlink="blue">
1380 <H1 align="center">${{html.formatShorthand(self.short)}}:
1383 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1392 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1403 for event
in self
.events
.itervalues():
1404 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1405 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1406 code('<TH bgcolor=white>$ref</TH>')
1410 for state
in self
.states
.itervalues():
1412 if state
== active_state
:
1417 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1418 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1419 text
= html
.formatShorthand(state
.short
)
1420 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1423 <TH bgcolor=$color>$ref</TH>
1426 # -- One column for each event
1427 for event
in self
.events
.itervalues():
1428 trans
= self
.table
.get((state
,event
), None)
1430 # This is the no transition case
1431 if state
== active_state
:
1436 code('<TD bgcolor=$color> </TD>')
1439 next
= trans
.nextState
1440 stall_action
= False
1442 # -- Get the actions
1443 for action
in trans
.actions
:
1444 if action
.ident
== "z_stall" or \
1445 action
.ident
== "zz_recycleMandatoryQueue":
1448 # -- Print out "actions/next-state"
1450 if state
== active_state
:
1455 elif active_state
and next
.ident
== active_state
.ident
:
1457 elif state
== active_state
:
1462 code('<TD bgcolor=$color>')
1463 for action
in trans
.actions
:
1464 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1465 ref
= self
.frameRef(href
, "Status", href
, "1",
1471 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1472 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1473 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1478 if state
== active_state
:
1483 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1484 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1485 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1487 <TH bgcolor=$color>$ref</TH>
1496 for event
in self
.events
.itervalues():
1497 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1498 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1499 code('<TH bgcolor=white>$ref</TH>')
1508 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1510 name
= "%s_table.html" % self
.ident
1511 code
.write(path
, name
)
1513 __all__
= [ "StateMachine" ]