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);
358 if self
.TBEType
!= None and self
.EntryType
!= None:
359 for action
in self
.actions
.itervalues():
360 code('/** \\brief ${{action.desc}} */')
361 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
362 elif self
.TBEType
!= None:
363 for action
in self
.actions
.itervalues():
364 code('/** \\brief ${{action.desc}} */')
365 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
366 elif self
.EntryType
!= None:
367 for action
in self
.actions
.itervalues():
368 code('/** \\brief ${{action.desc}} */')
369 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
371 for action
in self
.actions
.itervalues():
372 code('/** \\brief ${{action.desc}} */')
373 code('void ${{action.ident}}(const Address& addr);')
375 # the controller internal variables
380 for var
in self
.objects
:
381 th
= var
.get("template", "")
382 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
386 code('#endif // __${ident}_CONTROLLER_H__')
387 code
.write(path
, '%s.hh' % c_ident
)
389 def printControllerCC(self
, path
, includes
):
390 '''Output the actions for performing the actions'''
392 code
= self
.symtab
.codeFormatter()
394 c_ident
= "%s_Controller" % self
.ident
398 /** \\file $c_ident.cc
400 * Auto generated C++ code started by $__file__:$__line__
401 * Created by slicc definition of Module "${{self.short}}"
404 #include <sys/types.h>
411 #include "base/compiler.hh"
412 #include "base/cprintf.hh"
413 #include "debug/RubyGenerated.hh"
414 #include "debug/RubySlicc.hh"
415 #include "mem/protocol/${ident}_Controller.hh"
416 #include "mem/protocol/${ident}_Event.hh"
417 #include "mem/protocol/${ident}_State.hh"
418 #include "mem/protocol/Types.hh"
419 #include "mem/ruby/common/Global.hh"
420 #include "mem/ruby/system/System.hh"
422 for include_path
in includes
:
423 code('#include "${{include_path}}"')
430 # include object classes
432 for var
in self
.objects
:
433 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
434 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
435 seen_types
.add(var
.type.ident
)
439 ${c_ident}Params::create()
441 return new $c_ident(this);
444 int $c_ident::m_num_controllers = 0;
445 std::vector<Stats::Vector *> $c_ident::eventVec;
446 std::vector<std::vector<Stats::Vector *> > $c_ident::transVec;
448 // for adding information to the protocol debug trace
449 stringstream ${ident}_transitionComment;
452 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
454 #define APPEND_TRANSITION_COMMENT(str) do {} while (0)
457 /** \\brief constructor */
458 $c_ident::$c_ident(const Params *p)
459 : AbstractController(p)
461 m_machineID.type = MachineType_${ident};
462 m_machineID.num = m_version;
464 num_in_ports
= len(self
.in_ports
)
465 code(' m_in_ports = $num_in_ports;')
469 # After initializing the universal machine parameters, initialize the
470 # this machines config parameters. Also detemine if these configuration
471 # params include a sequencer. This information will be used later for
472 # contecting the sequencer back to the L1 cache controller.
474 contains_dma_sequencer
= False
476 for param
in self
.config_parameters
:
477 if param
.name
== "dma_sequencer":
478 contains_dma_sequencer
= True
479 elif re
.compile("sequencer").search(param
.name
):
480 sequencers
.append(param
.name
)
482 code('m_${{param.name}}_ptr = p->${{param.name}};')
484 code('m_${{param.name}} = p->${{param.name}};')
487 # For the l1 cache controller, add the special atomic support which
488 # includes passing the sequencer a pointer to the controller.
490 for seq
in sequencers
:
492 m_${{seq}}_ptr->setController(this);
496 # For the DMA controller, pass the sequencer a pointer to the
499 if self
.ident
== "DMA":
500 if not contains_dma_sequencer
:
501 self
.error("The DMA controller must include the sequencer " \
502 "configuration parameter")
505 m_dma_sequencer_ptr->setController(this);
508 code('m_num_controllers++;')
509 for var
in self
.objects
:
510 if var
.ident
.find("mandatoryQueue") >= 0:
512 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
513 m_${{var.c_ident}}_ptr->setReceiver(this);
516 if "network" in var
and "physical_network" in var
and \
517 var
["network"] == "To":
520 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
521 peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
522 m_${{var.c_ident}}_ptr->setSender(this);
527 connectWithPeer(p->peer);
529 for (int state = 0; state < ${ident}_State_NUM; state++) {
530 for (int event = 0; event < ${ident}_Event_NUM; event++) {
531 m_possible[state][event] = false;
532 m_counters[state][event] = 0;
535 for (int event = 0; event < ${ident}_Event_NUM; event++) {
536 m_event_counters[event] = 0;
546 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
547 int base M5_VAR_USED = MachineType_base_number(machine_type);
549 // initialize objects
554 for var
in self
.objects
:
556 vid
= "m_%s_ptr" % var
.c_ident
557 if "network" not in var
:
558 # Not a network port object
559 if "primitive" in vtype
:
560 code('$vid = new ${{vtype.c_ident}};')
562 code('(*$vid) = ${{var["default"]}};')
565 if var
.ident
.find("mandatoryQueue") < 0:
566 th
= var
.get("template", "")
567 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
569 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
570 args
= var
.get("constructor", "")
571 code('$expr($args);')
573 code('assert($vid != NULL);')
576 code('*$vid = ${{var["default"]}}; // Object default')
577 elif "default" in vtype
:
578 comment
= "Type %s default" % vtype
.ident
579 code('*$vid = ${{vtype["default"]}}; // $comment')
584 code('$vid->setOrdering(${{var["ordered"]}});')
589 code('$vid->setRandomization(${{var["random"]}});')
592 if vtype
.isBuffer
and "rank" in var
:
593 code('$vid->setPriority(${{var["rank"]}});')
595 # Set sender and receiver for trigger queue
596 if var
.ident
.find("triggerQueue") >= 0:
597 code('$vid->setSender(this);')
598 code('$vid->setReceiver(this);')
599 elif vtype
.c_ident
== "TimerTable":
600 code('$vid->setClockObj(this);')
601 elif var
.ident
.find("optionalQueue") >= 0:
602 code('$vid->setSender(this);')
603 code('$vid->setReceiver(this);')
606 # Network port object
607 network
= var
["network"]
608 ordered
= var
["ordered"]
610 if "virtual_network" in var
:
611 vnet
= var
["virtual_network"]
612 vnet_type
= var
["vnet_type"]
614 assert var
.machine
is not None
616 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
617 assert($vid != NULL);
622 code('$vid->setSender(this);')
624 code('$vid->setReceiver(this);')
629 code('$vid->setOrdering(${{var["ordered"]}});')
634 code('$vid->setRandomization(${{var["random"]}});')
638 code('$vid->setPriority(${{var["rank"]}})')
643 if (m_buffer_size > 0) {
644 $vid->resize(m_buffer_size);
648 # set description (may be overriden later by port def)
650 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
655 if "recycle_latency" in var
:
656 code('$vid->setRecycleLatency( ' \
657 'Cycles(${{var["recycle_latency"]}}));')
659 code('$vid->setRecycleLatency(m_recycle_latency);')
661 # Set the prefetchers
663 for prefetcher
in self
.prefetchers
:
664 code('${{prefetcher.code}}.setController(this);')
667 for port
in self
.in_ports
:
668 # Set the queue consumers
669 code('${{port.code}}.setConsumer(this);')
670 # Set the queue descriptions
671 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
673 # Initialize the transition profiling
675 for trans
in self
.transitions
:
676 # Figure out if we stall
678 for action
in trans
.actions
:
679 if action
.ident
== "z_stall":
682 # Only possible if it is not a 'z' case
684 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
685 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
686 code('possibleTransition($state, $event);')
690 AbstractController::init();
695 has_mandatory_q
= False
696 for port
in self
.in_ports
:
697 if port
.code
.find("mandatoryQueue_ptr") >= 0:
698 has_mandatory_q
= True
701 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
706 for param
in self
.config_parameters
:
707 if param
.name
== "sequencer":
708 assert(param
.pointer
)
709 seq_ident
= "m_%s_ptr" % param
.name
716 AbstractController::regStats();
718 if (m_version == 0) {
719 for (${ident}_Event event = ${ident}_Event_FIRST;
720 event < ${ident}_Event_NUM; ++event) {
721 Stats::Vector *t = new Stats::Vector();
722 t->init(m_num_controllers);
723 t->name(g_system_ptr->name() + ".${c_ident}." +
724 ${ident}_Event_to_string(event));
725 t->flags(Stats::pdf | Stats::total | Stats::oneline |
728 eventVec.push_back(t);
731 for (${ident}_State state = ${ident}_State_FIRST;
732 state < ${ident}_State_NUM; ++state) {
734 transVec.push_back(std::vector<Stats::Vector *>());
736 for (${ident}_Event event = ${ident}_Event_FIRST;
737 event < ${ident}_Event_NUM; ++event) {
739 Stats::Vector *t = new Stats::Vector();
740 t->init(m_num_controllers);
741 t->name(g_system_ptr->name() + ".${c_ident}." +
742 ${ident}_State_to_string(state) +
743 "." + ${ident}_Event_to_string(event));
745 t->flags(Stats::pdf | Stats::total | Stats::oneline |
747 transVec[state].push_back(t);
754 $c_ident::collateStats()
756 for (${ident}_Event event = ${ident}_Event_FIRST;
757 event < ${ident}_Event_NUM; ++event) {
758 for (unsigned int i = 0; i < m_num_controllers; ++i) {
759 std::map<uint32_t, AbstractController *>::iterator it =
760 g_abs_controls[MachineType_${ident}].find(i);
761 assert(it != g_abs_controls[MachineType_${ident}].end());
762 (*eventVec[event])[i] =
763 (($c_ident *)(*it).second)->getEventCount(event);
767 for (${ident}_State state = ${ident}_State_FIRST;
768 state < ${ident}_State_NUM; ++state) {
770 for (${ident}_Event event = ${ident}_Event_FIRST;
771 event < ${ident}_Event_NUM; ++event) {
773 for (unsigned int i = 0; i < m_num_controllers; ++i) {
774 std::map<uint32_t, AbstractController *>::iterator it =
775 g_abs_controls[MachineType_${ident}].find(i);
776 assert(it != g_abs_controls[MachineType_${ident}].end());
777 (*transVec[state][event])[i] =
778 (($c_ident *)(*it).second)->getTransitionCount(state, event);
785 $c_ident::countTransition(${ident}_State state, ${ident}_Event event)
787 assert(m_possible[state][event]);
788 m_counters[state][event]++;
789 m_event_counters[event]++;
792 $c_ident::possibleTransition(${ident}_State state,
793 ${ident}_Event event)
795 m_possible[state][event] = true;
799 $c_ident::getEventCount(${ident}_Event event)
801 return m_event_counters[event];
805 $c_ident::isPossible(${ident}_State state, ${ident}_Event event)
807 return m_possible[state][event];
811 $c_ident::getTransitionCount(${ident}_State state,
812 ${ident}_Event event)
814 return m_counters[state][event];
818 $c_ident::getNumControllers()
820 return m_num_controllers;
824 $c_ident::getMandatoryQueue() const
830 $c_ident::getSequencer() const
836 $c_ident::toString() const
842 $c_ident::print(ostream& out) const
844 out << "[$c_ident " << m_version << "]";
847 void $c_ident::resetStats()
849 for (int state = 0; state < ${ident}_State_NUM; state++) {
850 for (int event = 0; event < ${ident}_Event_NUM; event++) {
851 m_counters[state][event] = 0;
855 for (int event = 0; event < ${ident}_Event_NUM; event++) {
856 m_event_counters[event] = 0;
859 AbstractController::resetStats();
863 if self
.EntryType
!= None:
866 // Set and Reset for cache_entry variable
868 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
870 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
874 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
876 m_cache_entry_ptr = 0;
880 if self
.TBEType
!= None:
883 // Set and Reset for tbe variable
885 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
887 m_tbe_ptr = m_new_tbe;
891 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
900 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
904 # Record cache contents for all associated caches.
907 for param
in self
.config_parameters
:
908 if param
.type_ast
.type.ident
== "CacheMemory":
909 assert(param
.pointer
)
910 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
918 if self
.TBEType
!= None and self
.EntryType
!= None:
919 for action
in self
.actions
.itervalues():
920 if "c_code" not in action
:
924 /** \\brief ${{action.desc}} */
926 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
929 ${{action["c_code"]}}
933 elif self
.TBEType
!= None:
934 for action
in self
.actions
.itervalues():
935 if "c_code" not in action
:
939 /** \\brief ${{action.desc}} */
941 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
944 ${{action["c_code"]}}
948 elif self
.EntryType
!= None:
949 for action
in self
.actions
.itervalues():
950 if "c_code" not in action
:
954 /** \\brief ${{action.desc}} */
956 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
958 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
959 ${{action["c_code"]}}
964 for action
in self
.actions
.itervalues():
965 if "c_code" not in action
:
969 /** \\brief ${{action.desc}} */
971 $c_ident::${{action.ident}}(const Address& addr)
973 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
974 ${{action["c_code"]}}
978 for func
in self
.functions
:
979 code(func
.generateCode())
981 # Function for functional reads from messages buffered in the controller
984 $c_ident::functionalReadBuffers(PacketPtr& pkt)
987 for var
in self
.objects
:
990 vid
= "m_%s_ptr" % var
.c_ident
991 code('if ($vid->functionalRead(pkt)) { return true; }')
997 # Function for functional writes to messages buffered in the controller
1000 $c_ident::functionalWriteBuffers(PacketPtr& pkt)
1002 uint32_t num_functional_writes = 0;
1004 for var
in self
.objects
:
1007 vid
= "m_%s_ptr" % var
.c_ident
1008 code('num_functional_writes += $vid->functionalWrite(pkt);')
1010 return num_functional_writes;
1014 # Check if this controller has a peer, if yes then write the
1015 # function for connecting to the peer.
1020 $c_ident::getQueuesFromPeer(AbstractController *peer)
1023 for var
in self
.objects
:
1024 if "network" in var
and "physical_network" in var
and \
1025 var
["network"] == "From":
1027 m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1028 assert(m_${{var.c_ident}}_ptr != NULL);
1029 m_${{var.c_ident}}_ptr->setReceiver(this);
1034 code
.write(path
, "%s.cc" % c_ident
)
1036 def printCWakeup(self
, path
, includes
):
1037 '''Output the wakeup loop for the events'''
1039 code
= self
.symtab
.codeFormatter()
1042 outputRequest_types
= True
1043 if len(self
.request_types
) == 0:
1044 outputRequest_types
= False
1047 // Auto generated C++ code started by $__file__:$__line__
1048 // ${ident}: ${{self.short}}
1050 #include <sys/types.h>
1055 #include "base/misc.hh"
1056 #include "debug/RubySlicc.hh"
1057 #include "mem/protocol/${ident}_Controller.hh"
1058 #include "mem/protocol/${ident}_Event.hh"
1059 #include "mem/protocol/${ident}_State.hh"
1062 if outputRequest_types
:
1063 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1066 #include "mem/protocol/Types.hh"
1067 #include "mem/ruby/common/Global.hh"
1068 #include "mem/ruby/system/System.hh"
1072 for include_path
in includes
:
1073 code('#include "${{include_path}}"')
1077 using namespace std;
1080 ${ident}_Controller::wakeup()
1084 // Some cases will put us into an infinite loop without this limit
1085 assert(counter <= m_transitions_per_cycle);
1086 if (counter == m_transitions_per_cycle) {
1087 // Count how often we are fully utilized
1088 m_fully_busy_cycles++;
1090 // Wakeup in another cycle and try again
1091 scheduleEvent(Cycles(1));
1101 for port
in self
.in_ports
:
1103 code('// ${ident}InPort $port')
1104 if port
.pairs
.has_key("rank"):
1105 code('m_cur_in_port = ${{port.pairs["rank"]}};')
1107 code('m_cur_in_port = 0;')
1108 code('${{port["c_code_in_port"]}}')
1116 break; // If we got this far, we have nothing left todo
1121 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1123 def printCSwitch(self
, path
):
1124 '''Output switch statement for transition table'''
1126 code
= self
.symtab
.codeFormatter()
1130 // Auto generated C++ code started by $__file__:$__line__
1131 // ${ident}: ${{self.short}}
1135 #include "base/misc.hh"
1136 #include "base/trace.hh"
1137 #include "debug/ProtocolTrace.hh"
1138 #include "debug/RubyGenerated.hh"
1139 #include "mem/protocol/${ident}_Controller.hh"
1140 #include "mem/protocol/${ident}_Event.hh"
1141 #include "mem/protocol/${ident}_State.hh"
1142 #include "mem/protocol/Types.hh"
1143 #include "mem/ruby/common/Global.hh"
1144 #include "mem/ruby/system/System.hh"
1146 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1148 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1149 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1152 ${ident}_Controller::doTransition(${ident}_Event event,
1154 if self
.EntryType
!= None:
1156 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1158 if self
.TBEType
!= None:
1160 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1166 if self
.TBEType
!= None and self
.EntryType
!= None:
1167 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1168 elif self
.TBEType
!= None:
1169 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1170 elif self
.EntryType
!= None:
1171 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1173 code('${ident}_State state = getState(addr);')
1176 ${ident}_State next_state = state;
1178 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1179 *this, curCycle(), ${ident}_State_to_string(state),
1180 ${ident}_Event_to_string(event), addr);
1182 TransitionResult result =
1184 if self
.TBEType
!= None and self
.EntryType
!= None:
1185 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1186 elif self
.TBEType
!= None:
1187 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1188 elif self
.EntryType
!= None:
1189 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1191 code('doTransitionWorker(event, state, next_state, addr);')
1194 if (result == TransitionResult_Valid) {
1195 DPRINTF(RubyGenerated, "next_state: %s\\n",
1196 ${ident}_State_to_string(next_state));
1197 countTransition(state, event);
1198 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1199 curTick(), m_version, "${ident}",
1200 ${ident}_Event_to_string(event),
1201 ${ident}_State_to_string(state),
1202 ${ident}_State_to_string(next_state),
1203 addr, GET_TRANSITION_COMMENT());
1205 CLEAR_TRANSITION_COMMENT();
1207 if self
.TBEType
!= None and self
.EntryType
!= None:
1208 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1209 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1210 elif self
.TBEType
!= None:
1211 code('setState(m_tbe_ptr, addr, next_state);')
1212 code('setAccessPermission(addr, next_state);')
1213 elif self
.EntryType
!= None:
1214 code('setState(m_cache_entry_ptr, addr, next_state);')
1215 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1217 code('setState(addr, next_state);')
1218 code('setAccessPermission(addr, next_state);')
1221 } else if (result == TransitionResult_ResourceStall) {
1222 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1223 curTick(), m_version, "${ident}",
1224 ${ident}_Event_to_string(event),
1225 ${ident}_State_to_string(state),
1226 ${ident}_State_to_string(next_state),
1227 addr, "Resource Stall");
1228 } else if (result == TransitionResult_ProtocolStall) {
1229 DPRINTF(RubyGenerated, "stalling\\n");
1230 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1231 curTick(), m_version, "${ident}",
1232 ${ident}_Event_to_string(event),
1233 ${ident}_State_to_string(state),
1234 ${ident}_State_to_string(next_state),
1235 addr, "Protocol Stall");
1242 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1243 ${ident}_State state,
1244 ${ident}_State& next_state,
1247 if self
.TBEType
!= None:
1249 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1251 if self
.EntryType
!= None:
1253 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1256 const Address& addr)
1258 switch(HASH_FUN(state, event)) {
1261 # This map will allow suppress generating duplicate code
1264 for trans
in self
.transitions
:
1265 case_string
= "%s_State_%s, %s_Event_%s" % \
1266 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1268 case
= self
.symtab
.codeFormatter()
1269 # Only set next_state if it changes
1270 if trans
.state
!= trans
.nextState
:
1271 ns_ident
= trans
.nextState
.ident
1272 case('next_state = ${ident}_State_${ns_ident};')
1274 actions
= trans
.actions
1275 request_types
= trans
.request_types
1277 # Check for resources
1279 res
= trans
.resources
1280 for key
,val
in res
.iteritems():
1281 if key
.type.ident
!= "DNUCAStopTable":
1283 if (!%s.areNSlotsAvailable(%s))
1284 return TransitionResult_ResourceStall;
1285 ''' % (key
.code
, val
)
1286 case_sorter
.append(val
)
1288 # Check all of the request_types for resource constraints
1289 for request_type
in request_types
:
1291 if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1292 return TransitionResult_ResourceStall;
1294 ''' % (self
.ident
, request_type
.ident
)
1295 case_sorter
.append(val
)
1297 # Emit the code sequences in a sorted order. This makes the
1298 # output deterministic (without this the output order can vary
1299 # since Map's keys() on a vector of pointers is not deterministic
1300 for c
in sorted(case_sorter
):
1303 # Record access types for this transition
1304 for request_type
in request_types
:
1305 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1307 # Figure out if we stall
1309 for action
in actions
:
1310 if action
.ident
== "z_stall":
1315 case('return TransitionResult_ProtocolStall;')
1317 if self
.TBEType
!= None and self
.EntryType
!= None:
1318 for action
in actions
:
1319 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1320 elif self
.TBEType
!= None:
1321 for action
in actions
:
1322 case('${{action.ident}}(m_tbe_ptr, addr);')
1323 elif self
.EntryType
!= None:
1324 for action
in actions
:
1325 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1327 for action
in actions
:
1328 case('${{action.ident}}(addr);')
1329 case('return TransitionResult_Valid;')
1333 # Look to see if this transition code is unique.
1334 if case
not in cases
:
1337 cases
[case
].append(case_string
)
1339 # Walk through all of the unique code blocks and spit out the
1340 # corresponding case statement elements
1341 for case
,transitions
in cases
.iteritems():
1342 # Iterative over all the multiple transitions that share
1344 for trans
in transitions
:
1345 code(' case HASH_FUN($trans):')
1350 fatal("Invalid transition\\n"
1351 "%s time: %d addr: %s event: %s state: %s\\n",
1352 name(), curCycle(), addr, event, state);
1354 return TransitionResult_Valid;
1357 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1360 # **************************
1361 # ******* HTML Files *******
1362 # **************************
1363 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1364 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1365 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1366 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1367 parent.frames[$over_num].location='$over_href'
1369 ${{html.formatShorthand(text)}}
1373 def writeHTMLFiles(self
, path
):
1374 # Create table with no row hilighted
1375 self
.printHTMLTransitions(path
, None)
1377 # Generate transition tables
1378 for state
in self
.states
.itervalues():
1379 self
.printHTMLTransitions(path
, state
)
1381 # Generate action descriptions
1382 for action
in self
.actions
.itervalues():
1383 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1384 code
= html
.createSymbol(action
, "Action")
1385 code
.write(path
, name
)
1387 # Generate state descriptions
1388 for state
in self
.states
.itervalues():
1389 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1390 code
= html
.createSymbol(state
, "State")
1391 code
.write(path
, name
)
1393 # Generate event descriptions
1394 for event
in self
.events
.itervalues():
1395 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1396 code
= html
.createSymbol(event
, "Event")
1397 code
.write(path
, name
)
1399 def printHTMLTransitions(self
, path
, active_state
):
1400 code
= self
.symtab
.codeFormatter()
1404 <BODY link="blue" vlink="blue">
1406 <H1 align="center">${{html.formatShorthand(self.short)}}:
1409 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1418 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1429 for event
in self
.events
.itervalues():
1430 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1431 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1432 code('<TH bgcolor=white>$ref</TH>')
1436 for state
in self
.states
.itervalues():
1438 if state
== active_state
:
1443 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1444 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1445 text
= html
.formatShorthand(state
.short
)
1446 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1449 <TH bgcolor=$color>$ref</TH>
1452 # -- One column for each event
1453 for event
in self
.events
.itervalues():
1454 trans
= self
.table
.get((state
,event
), None)
1456 # This is the no transition case
1457 if state
== active_state
:
1462 code('<TD bgcolor=$color> </TD>')
1465 next
= trans
.nextState
1466 stall_action
= False
1468 # -- Get the actions
1469 for action
in trans
.actions
:
1470 if action
.ident
== "z_stall" or \
1471 action
.ident
== "zz_recycleMandatoryQueue":
1474 # -- Print out "actions/next-state"
1476 if state
== active_state
:
1481 elif active_state
and next
.ident
== active_state
.ident
:
1483 elif state
== active_state
:
1488 code('<TD bgcolor=$color>')
1489 for action
in trans
.actions
:
1490 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1491 ref
= self
.frameRef(href
, "Status", href
, "1",
1497 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1498 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1499 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1504 if state
== active_state
:
1509 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1510 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1511 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1513 <TH bgcolor=$color>$ref</TH>
1522 for event
in self
.events
.itervalues():
1523 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1524 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1525 code('<TH bgcolor=white>$ref</TH>')
1534 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1536 name
= "%s_table.html" % self
.ident
1537 code
.write(path
, name
)
1539 __all__
= [ "StateMachine" ]