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,
301 const Address& addr);
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)
464 # max_port_rank is used to size vectors and thus should be one plus the
467 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
468 code(' m_max_in_port_rank = $max_port_rank;')
472 # After initializing the universal machine parameters, initialize the
473 # this machines config parameters. Also detemine if these configuration
474 # params include a sequencer. This information will be used later for
475 # contecting the sequencer back to the L1 cache controller.
477 contains_dma_sequencer
= False
479 for param
in self
.config_parameters
:
480 if param
.name
== "dma_sequencer":
481 contains_dma_sequencer
= True
482 elif re
.compile("sequencer").search(param
.name
):
483 sequencers
.append(param
.name
)
485 code('m_${{param.name}}_ptr = p->${{param.name}};')
487 code('m_${{param.name}} = p->${{param.name}};')
490 # For the l1 cache controller, add the special atomic support which
491 # includes passing the sequencer a pointer to the controller.
493 for seq
in sequencers
:
495 m_${{seq}}_ptr->setController(this);
499 # For the DMA controller, pass the sequencer a pointer to the
502 if self
.ident
== "DMA":
503 if not contains_dma_sequencer
:
504 self
.error("The DMA controller must include the sequencer " \
505 "configuration parameter")
508 m_dma_sequencer_ptr->setController(this);
511 code('m_num_controllers++;')
512 for var
in self
.objects
:
513 if var
.ident
.find("mandatoryQueue") >= 0:
515 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
516 m_${{var.c_ident}}_ptr->setReceiver(this);
519 if "network" in var
and "physical_network" in var
and \
520 var
["network"] == "To":
523 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
524 peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
525 m_${{var.c_ident}}_ptr->setSender(this);
530 connectWithPeer(p->peer);
532 for (int state = 0; state < ${ident}_State_NUM; state++) {
533 for (int event = 0; event < ${ident}_Event_NUM; event++) {
534 m_possible[state][event] = false;
535 m_counters[state][event] = 0;
538 for (int event = 0; event < ${ident}_Event_NUM; event++) {
539 m_event_counters[event] = 0;
549 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}");
550 int base = MachineType_base_number(machine_type);
552 m_machineID.type = MachineType_${ident};
553 m_machineID.num = m_version;
555 // initialize objects
560 for var
in self
.objects
:
562 vid
= "m_%s_ptr" % var
.c_ident
563 if "network" not in var
:
564 # Not a network port object
565 if "primitive" in vtype
:
566 code('$vid = new ${{vtype.c_ident}};')
568 code('(*$vid) = ${{var["default"]}};')
571 if var
.ident
.find("mandatoryQueue") < 0:
572 th
= var
.get("template", "")
573 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
575 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
576 args
= var
.get("constructor", "")
577 code('$expr($args);')
579 code('assert($vid != NULL);')
582 code('*$vid = ${{var["default"]}}; // Object default')
583 elif "default" in vtype
:
584 comment
= "Type %s default" % vtype
.ident
585 code('*$vid = ${{vtype["default"]}}; // $comment')
590 code('$vid->setOrdering(${{var["ordered"]}});')
595 code('$vid->setRandomization(${{var["random"]}});')
598 if vtype
.isBuffer
and "rank" in var
:
599 code('$vid->setPriority(${{var["rank"]}});')
601 # Set sender and receiver for trigger queue
602 if var
.ident
.find("triggerQueue") >= 0:
603 code('$vid->setSender(this);')
604 code('$vid->setReceiver(this);')
605 elif vtype
.c_ident
== "TimerTable":
606 code('$vid->setClockObj(this);')
607 elif var
.ident
.find("optionalQueue") >= 0:
608 code('$vid->setSender(this);')
609 code('$vid->setReceiver(this);')
612 # Network port object
613 network
= var
["network"]
614 ordered
= var
["ordered"]
616 if "virtual_network" in var
:
617 vnet
= var
["virtual_network"]
618 vnet_type
= var
["vnet_type"]
620 assert var
.machine
is not None
622 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
623 assert($vid != NULL);
628 code('$vid->setSender(this);')
630 code('$vid->setReceiver(this);')
635 code('$vid->setOrdering(${{var["ordered"]}});')
640 code('$vid->setRandomization(${{var["random"]}});')
644 code('$vid->setPriority(${{var["rank"]}})')
649 if (m_buffer_size > 0) {
650 $vid->resize(m_buffer_size);
654 # set description (may be overriden later by port def)
656 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
661 if "recycle_latency" in var
:
662 code('$vid->setRecycleLatency( ' \
663 'Cycles(${{var["recycle_latency"]}}));')
665 code('$vid->setRecycleLatency(m_recycle_latency);')
667 # Set the prefetchers
669 for prefetcher
in self
.prefetchers
:
670 code('${{prefetcher.code}}.setController(this);')
673 for port
in self
.in_ports
:
674 # Set the queue consumers
675 code('${{port.code}}.setConsumer(this);')
676 # Set the queue descriptions
677 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
679 # Initialize the transition profiling
681 for trans
in self
.transitions
:
682 # Figure out if we stall
684 for action
in trans
.actions
:
685 if action
.ident
== "z_stall":
688 # Only possible if it is not a 'z' case
690 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
691 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
692 code('possibleTransition($state, $event);')
696 AbstractController::init();
701 has_mandatory_q
= False
702 for port
in self
.in_ports
:
703 if port
.code
.find("mandatoryQueue_ptr") >= 0:
704 has_mandatory_q
= True
707 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
712 for param
in self
.config_parameters
:
713 if param
.name
== "sequencer":
714 assert(param
.pointer
)
715 seq_ident
= "m_%s_ptr" % param
.name
722 if (m_version == 0) {
723 for (${ident}_Event event = ${ident}_Event_FIRST;
724 event < ${ident}_Event_NUM; ++event) {
725 Stats::Vector *t = new Stats::Vector();
726 t->init(m_num_controllers);
727 t->name(name() + "." + ${ident}_Event_to_string(event));
728 t->flags(Stats::pdf | Stats::total | Stats::oneline |
731 eventVec.push_back(t);
734 for (${ident}_State state = ${ident}_State_FIRST;
735 state < ${ident}_State_NUM; ++state) {
737 transVec.push_back(std::vector<Stats::Vector *>());
739 for (${ident}_Event event = ${ident}_Event_FIRST;
740 event < ${ident}_Event_NUM; ++event) {
742 Stats::Vector *t = new Stats::Vector();
743 t->init(m_num_controllers);
744 t->name(name() + "." + ${ident}_State_to_string(state) +
745 "." + ${ident}_Event_to_string(event));
747 t->flags(Stats::pdf | Stats::total | Stats::oneline |
749 transVec[state].push_back(t);
756 $c_ident::collateStats()
758 for (${ident}_Event event = ${ident}_Event_FIRST;
759 event < ${ident}_Event_NUM; ++event) {
760 for (unsigned int i = 0; i < m_num_controllers; ++i) {
761 std::map<uint32_t, AbstractController *>::iterator it =
762 g_abs_controls[MachineType_${ident}].find(i);
763 assert(it != g_abs_controls[MachineType_${ident}].end());
764 (*eventVec[event])[i] =
765 (($c_ident *)(*it).second)->getEventCount(event);
769 for (${ident}_State state = ${ident}_State_FIRST;
770 state < ${ident}_State_NUM; ++state) {
772 for (${ident}_Event event = ${ident}_Event_FIRST;
773 event < ${ident}_Event_NUM; ++event) {
775 for (unsigned int i = 0; i < m_num_controllers; ++i) {
776 std::map<uint32_t, AbstractController *>::iterator it =
777 g_abs_controls[MachineType_${ident}].find(i);
778 assert(it != g_abs_controls[MachineType_${ident}].end());
779 (*transVec[state][event])[i] =
780 (($c_ident *)(*it).second)->getTransitionCount(state, event);
787 $c_ident::countTransition(${ident}_State state, ${ident}_Event event)
789 assert(m_possible[state][event]);
790 m_counters[state][event]++;
791 m_event_counters[event]++;
794 $c_ident::possibleTransition(${ident}_State state,
795 ${ident}_Event event)
797 m_possible[state][event] = true;
801 $c_ident::getEventCount(${ident}_Event event)
803 return m_event_counters[event];
807 $c_ident::isPossible(${ident}_State state, ${ident}_Event event)
809 return m_possible[state][event];
813 $c_ident::getTransitionCount(${ident}_State state,
814 ${ident}_Event event)
816 return m_counters[state][event];
820 $c_ident::getNumControllers()
822 return m_num_controllers;
826 $c_ident::getMandatoryQueue() const
832 $c_ident::getSequencer() const
838 $c_ident::toString() const
844 $c_ident::print(ostream& out) const
846 out << "[$c_ident " << m_version << "]";
849 void $c_ident::clearStats()
851 for (int state = 0; state < ${ident}_State_NUM; state++) {
852 for (int event = 0; event < ${ident}_Event_NUM; event++) {
853 m_counters[state][event] = 0;
857 for (int event = 0; event < ${ident}_Event_NUM; event++) {
858 m_event_counters[event] = 0;
861 AbstractController::clearStats();
865 if self
.EntryType
!= None:
868 // Set and Reset for cache_entry variable
870 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
872 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
876 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
878 m_cache_entry_ptr = 0;
882 if self
.TBEType
!= None:
885 // Set and Reset for tbe variable
887 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
889 m_tbe_ptr = m_new_tbe;
893 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
902 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
906 # Record cache contents for all associated caches.
909 for param
in self
.config_parameters
:
910 if param
.type_ast
.type.ident
== "CacheMemory":
911 assert(param
.pointer
)
912 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
920 if self
.TBEType
!= None and self
.EntryType
!= None:
921 for action
in self
.actions
.itervalues():
922 if "c_code" not in action
:
926 /** \\brief ${{action.desc}} */
928 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
930 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
931 ${{action["c_code"]}}
935 elif self
.TBEType
!= None:
936 for action
in self
.actions
.itervalues():
937 if "c_code" not in action
:
941 /** \\brief ${{action.desc}} */
943 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
945 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
946 ${{action["c_code"]}}
950 elif self
.EntryType
!= None:
951 for action
in self
.actions
.itervalues():
952 if "c_code" not in action
:
956 /** \\brief ${{action.desc}} */
958 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
960 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
961 ${{action["c_code"]}}
966 for action
in self
.actions
.itervalues():
967 if "c_code" not in action
:
971 /** \\brief ${{action.desc}} */
973 $c_ident::${{action.ident}}(const Address& addr)
975 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
976 ${{action["c_code"]}}
980 for func
in self
.functions
:
981 code(func
.generateCode())
983 # Function for functional reads from messages buffered in the controller
986 $c_ident::functionalReadBuffers(PacketPtr& pkt)
989 for var
in self
.objects
:
992 vid
= "m_%s_ptr" % var
.c_ident
993 code('if ($vid->functionalRead(pkt)) { return true; }')
999 # Function for functional writes to messages buffered in the controller
1002 $c_ident::functionalWriteBuffers(PacketPtr& pkt)
1004 uint32_t num_functional_writes = 0;
1006 for var
in self
.objects
:
1009 vid
= "m_%s_ptr" % var
.c_ident
1010 code('num_functional_writes += $vid->functionalWrite(pkt);')
1012 return num_functional_writes;
1016 # Check if this controller has a peer, if yes then write the
1017 # function for connecting to the peer.
1022 $c_ident::getQueuesFromPeer(AbstractController *peer)
1025 for var
in self
.objects
:
1026 if "network" in var
and "physical_network" in var
and \
1027 var
["network"] == "From":
1029 m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
1030 assert(m_${{var.c_ident}}_ptr != NULL);
1031 m_${{var.c_ident}}_ptr->setReceiver(this);
1036 code
.write(path
, "%s.cc" % c_ident
)
1038 def printCWakeup(self
, path
, includes
):
1039 '''Output the wakeup loop for the events'''
1041 code
= self
.symtab
.codeFormatter()
1044 outputRequest_types
= True
1045 if len(self
.request_types
) == 0:
1046 outputRequest_types
= False
1049 // Auto generated C++ code started by $__file__:$__line__
1050 // ${ident}: ${{self.short}}
1052 #include <sys/types.h>
1057 #include "base/misc.hh"
1058 #include "debug/RubySlicc.hh"
1059 #include "mem/protocol/${ident}_Controller.hh"
1060 #include "mem/protocol/${ident}_Event.hh"
1061 #include "mem/protocol/${ident}_State.hh"
1064 if outputRequest_types
:
1065 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1068 #include "mem/protocol/Types.hh"
1069 #include "mem/ruby/common/Global.hh"
1070 #include "mem/ruby/system/System.hh"
1074 for include_path
in includes
:
1075 code('#include "${{include_path}}"')
1079 using namespace std;
1082 ${ident}_Controller::wakeup()
1086 // Some cases will put us into an infinite loop without this limit
1087 assert(counter <= m_transitions_per_cycle);
1088 if (counter == m_transitions_per_cycle) {
1089 // Count how often we are fully utilized
1090 m_fully_busy_cycles++;
1092 // Wakeup in another cycle and try again
1093 scheduleEvent(Cycles(1));
1103 for port
in self
.in_ports
:
1105 code('// ${ident}InPort $port')
1106 if port
.pairs
.has_key("rank"):
1107 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1109 code('m_cur_in_port_rank = 0;')
1110 code('${{port["c_code_in_port"]}}')
1118 break; // If we got this far, we have nothing left todo
1123 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1125 def printCSwitch(self
, path
):
1126 '''Output switch statement for transition table'''
1128 code
= self
.symtab
.codeFormatter()
1132 // Auto generated C++ code started by $__file__:$__line__
1133 // ${ident}: ${{self.short}}
1137 #include "base/misc.hh"
1138 #include "base/trace.hh"
1139 #include "debug/ProtocolTrace.hh"
1140 #include "debug/RubyGenerated.hh"
1141 #include "mem/protocol/${ident}_Controller.hh"
1142 #include "mem/protocol/${ident}_Event.hh"
1143 #include "mem/protocol/${ident}_State.hh"
1144 #include "mem/protocol/Types.hh"
1145 #include "mem/ruby/common/Global.hh"
1146 #include "mem/ruby/system/System.hh"
1148 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1150 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1151 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1154 ${ident}_Controller::doTransition(${ident}_Event event,
1156 if self
.EntryType
!= None:
1158 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1160 if self
.TBEType
!= None:
1162 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1165 const Address &addr)
1168 if self
.TBEType
!= None and self
.EntryType
!= None:
1169 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1170 elif self
.TBEType
!= None:
1171 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1172 elif self
.EntryType
!= None:
1173 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1175 code('${ident}_State state = getState(addr);')
1178 ${ident}_State next_state = state;
1180 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1181 *this, curCycle(), ${ident}_State_to_string(state),
1182 ${ident}_Event_to_string(event), addr);
1184 TransitionResult result =
1186 if self
.TBEType
!= None and self
.EntryType
!= None:
1187 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1188 elif self
.TBEType
!= None:
1189 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1190 elif self
.EntryType
!= None:
1191 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1193 code('doTransitionWorker(event, state, next_state, addr);')
1196 if (result == TransitionResult_Valid) {
1197 DPRINTF(RubyGenerated, "next_state: %s\\n",
1198 ${ident}_State_to_string(next_state));
1199 countTransition(state, event);
1200 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1201 curTick(), m_version, "${ident}",
1202 ${ident}_Event_to_string(event),
1203 ${ident}_State_to_string(state),
1204 ${ident}_State_to_string(next_state),
1205 addr, GET_TRANSITION_COMMENT());
1207 CLEAR_TRANSITION_COMMENT();
1209 if self
.TBEType
!= None and self
.EntryType
!= None:
1210 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1211 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1212 elif self
.TBEType
!= None:
1213 code('setState(m_tbe_ptr, addr, next_state);')
1214 code('setAccessPermission(addr, next_state);')
1215 elif self
.EntryType
!= None:
1216 code('setState(m_cache_entry_ptr, addr, next_state);')
1217 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1219 code('setState(addr, next_state);')
1220 code('setAccessPermission(addr, next_state);')
1223 } else if (result == TransitionResult_ResourceStall) {
1224 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1225 curTick(), m_version, "${ident}",
1226 ${ident}_Event_to_string(event),
1227 ${ident}_State_to_string(state),
1228 ${ident}_State_to_string(next_state),
1229 addr, "Resource Stall");
1230 } else if (result == TransitionResult_ProtocolStall) {
1231 DPRINTF(RubyGenerated, "stalling\\n");
1232 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1233 curTick(), m_version, "${ident}",
1234 ${ident}_Event_to_string(event),
1235 ${ident}_State_to_string(state),
1236 ${ident}_State_to_string(next_state),
1237 addr, "Protocol Stall");
1244 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1245 ${ident}_State state,
1246 ${ident}_State& next_state,
1249 if self
.TBEType
!= None:
1251 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1253 if self
.EntryType
!= None:
1255 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1258 const Address& addr)
1260 switch(HASH_FUN(state, event)) {
1263 # This map will allow suppress generating duplicate code
1266 for trans
in self
.transitions
:
1267 case_string
= "%s_State_%s, %s_Event_%s" % \
1268 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1270 case
= self
.symtab
.codeFormatter()
1271 # Only set next_state if it changes
1272 if trans
.state
!= trans
.nextState
:
1273 ns_ident
= trans
.nextState
.ident
1274 case('next_state = ${ident}_State_${ns_ident};')
1276 actions
= trans
.actions
1277 request_types
= trans
.request_types
1279 # Check for resources
1281 res
= trans
.resources
1282 for key
,val
in res
.iteritems():
1283 if key
.type.ident
!= "DNUCAStopTable":
1285 if (!%s.areNSlotsAvailable(%s))
1286 return TransitionResult_ResourceStall;
1287 ''' % (key
.code
, val
)
1288 case_sorter
.append(val
)
1290 # Check all of the request_types for resource constraints
1291 for request_type
in request_types
:
1293 if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1294 return TransitionResult_ResourceStall;
1296 ''' % (self
.ident
, request_type
.ident
)
1297 case_sorter
.append(val
)
1299 # Emit the code sequences in a sorted order. This makes the
1300 # output deterministic (without this the output order can vary
1301 # since Map's keys() on a vector of pointers is not deterministic
1302 for c
in sorted(case_sorter
):
1305 # Record access types for this transition
1306 for request_type
in request_types
:
1307 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1309 # Figure out if we stall
1311 for action
in actions
:
1312 if action
.ident
== "z_stall":
1317 case('return TransitionResult_ProtocolStall;')
1319 if self
.TBEType
!= None and self
.EntryType
!= None:
1320 for action
in actions
:
1321 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1322 elif self
.TBEType
!= None:
1323 for action
in actions
:
1324 case('${{action.ident}}(m_tbe_ptr, addr);')
1325 elif self
.EntryType
!= None:
1326 for action
in actions
:
1327 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1329 for action
in actions
:
1330 case('${{action.ident}}(addr);')
1331 case('return TransitionResult_Valid;')
1335 # Look to see if this transition code is unique.
1336 if case
not in cases
:
1339 cases
[case
].append(case_string
)
1341 # Walk through all of the unique code blocks and spit out the
1342 # corresponding case statement elements
1343 for case
,transitions
in cases
.iteritems():
1344 # Iterative over all the multiple transitions that share
1346 for trans
in transitions
:
1347 code(' case HASH_FUN($trans):')
1352 fatal("Invalid transition\\n"
1353 "%s time: %d addr: %s event: %s state: %s\\n",
1354 name(), curCycle(), addr, event, state);
1356 return TransitionResult_Valid;
1359 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1362 # **************************
1363 # ******* HTML Files *******
1364 # **************************
1365 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1366 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1367 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1368 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1369 parent.frames[$over_num].location='$over_href'
1371 ${{html.formatShorthand(text)}}
1375 def writeHTMLFiles(self
, path
):
1376 # Create table with no row hilighted
1377 self
.printHTMLTransitions(path
, None)
1379 # Generate transition tables
1380 for state
in self
.states
.itervalues():
1381 self
.printHTMLTransitions(path
, state
)
1383 # Generate action descriptions
1384 for action
in self
.actions
.itervalues():
1385 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1386 code
= html
.createSymbol(action
, "Action")
1387 code
.write(path
, name
)
1389 # Generate state descriptions
1390 for state
in self
.states
.itervalues():
1391 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1392 code
= html
.createSymbol(state
, "State")
1393 code
.write(path
, name
)
1395 # Generate event descriptions
1396 for event
in self
.events
.itervalues():
1397 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1398 code
= html
.createSymbol(event
, "Event")
1399 code
.write(path
, name
)
1401 def printHTMLTransitions(self
, path
, active_state
):
1402 code
= self
.symtab
.codeFormatter()
1406 <BODY link="blue" vlink="blue">
1408 <H1 align="center">${{html.formatShorthand(self.short)}}:
1411 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1420 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1431 for event
in self
.events
.itervalues():
1432 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1433 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1434 code('<TH bgcolor=white>$ref</TH>')
1438 for state
in self
.states
.itervalues():
1440 if state
== active_state
:
1445 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1446 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1447 text
= html
.formatShorthand(state
.short
)
1448 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1451 <TH bgcolor=$color>$ref</TH>
1454 # -- One column for each event
1455 for event
in self
.events
.itervalues():
1456 trans
= self
.table
.get((state
,event
), None)
1458 # This is the no transition case
1459 if state
== active_state
:
1464 code('<TD bgcolor=$color> </TD>')
1467 next
= trans
.nextState
1468 stall_action
= False
1470 # -- Get the actions
1471 for action
in trans
.actions
:
1472 if action
.ident
== "z_stall" or \
1473 action
.ident
== "zz_recycleMandatoryQueue":
1476 # -- Print out "actions/next-state"
1478 if state
== active_state
:
1483 elif active_state
and next
.ident
== active_state
.ident
:
1485 elif state
== active_state
:
1490 code('<TD bgcolor=$color>')
1491 for action
in trans
.actions
:
1492 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1493 ref
= self
.frameRef(href
, "Status", href
, "1",
1499 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1500 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1501 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1506 if state
== active_state
:
1511 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1512 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1513 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1515 <TH bgcolor=$color>$ref</TH>
1524 for event
in self
.events
.itervalues():
1525 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1526 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1527 code('<TH bgcolor=white>$ref</TH>')
1536 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1538 name
= "%s_table.html" % self
.ident
1539 code
.write(path
, name
)
1541 __all__
= [ "StateMachine" ]