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
35 python_class_map
= {"int": "Int",
36 "std::string": "String",
38 "CacheMemory": "RubyCache",
39 "WireBuffer": "RubyWireBuffer",
40 "Sequencer": "RubySequencer",
41 "DirectoryMemory": "RubyDirectoryMemory",
42 "MemoryControl": "RubyMemoryControl",
43 "DMASequencer": "DMASequencer"
46 class StateMachine(Symbol
):
47 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
48 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
50 self
.config_parameters
= config_parameters
52 for param
in config_parameters
:
54 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
55 "(*m_%s_ptr)" % param
.name
, {}, self
)
57 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
58 "m_%s" % param
.name
, {}, self
)
59 self
.symtab
.registerSym(param
.name
, var
)
61 self
.states
= orderdict()
62 self
.events
= orderdict()
63 self
.actions
= orderdict()
71 self
.message_buffer_names
= []
74 return "[StateMachine: %s]" % self
.ident
76 def addState(self
, state
):
77 assert self
.table
is None
78 self
.states
[state
.ident
] = state
80 def addEvent(self
, event
):
81 assert self
.table
is None
82 self
.events
[event
.ident
] = event
84 def addAction(self
, action
):
85 assert self
.table
is None
87 # Check for duplicate action
88 for other
in self
.actions
.itervalues():
89 if action
.ident
== other
.ident
:
90 action
.warning("Duplicate action definition: %s" % action
.ident
)
91 action
.error("Duplicate action definition: %s" % action
.ident
)
92 if action
.short
== other
.short
:
93 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
94 other
.warning(" shorthand = %s" % other
.short
)
95 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
96 action
.error(" shorthand = %s" % action
.short
)
98 self
.actions
[action
.ident
] = action
100 def addTransition(self
, trans
):
101 assert self
.table
is None
102 self
.transitions
.append(trans
)
104 def addInPort(self
, var
):
105 self
.in_ports
.append(var
)
107 def addFunc(self
, func
):
108 # register func in the symbol table
109 self
.symtab
.registerSym(str(func
), func
)
110 self
.functions
.append(func
)
112 def addObject(self
, obj
):
113 self
.objects
.append(obj
)
115 def addType(self
, type):
116 type_ident
= '%s' % type.c_ident
118 if type_ident
== "%s_TBE" %self
.ident
:
119 if self
.TBEType
!= None:
120 self
.error("Multiple Transaction Buffer types in a " \
124 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
125 if self
.EntryType
!= None:
126 self
.error("Multiple AbstractCacheEntry types in a " \
128 self
.EntryType
= type
130 # Needs to be called before accessing the table
131 def buildTable(self
):
132 assert self
.table
is None
136 for trans
in self
.transitions
:
137 # Track which actions we touch so we know if we use them
138 # all -- really this should be done for all symbols as
139 # part of the symbol table, then only trigger it for
140 # Actions, States, Events, etc.
142 for action
in trans
.actions
:
145 index
= (trans
.state
, trans
.event
)
147 table
[index
].warning("Duplicate transition: %s" % table
[index
])
148 trans
.error("Duplicate transition: %s" % trans
)
151 # Look at all actions to make sure we used them all
152 for action
in self
.actions
.itervalues():
154 error_msg
= "Unused action: %s" % action
.ident
156 error_msg
+= ", " + action
.desc
157 action
.warning(error_msg
)
160 def writeCodeFiles(self
, path
):
161 self
.printControllerPython(path
)
162 self
.printControllerHH(path
)
163 self
.printControllerCC(path
)
164 self
.printCSwitch(path
)
165 self
.printCWakeup(path
)
166 self
.printProfilerCC(path
)
167 self
.printProfilerHH(path
)
168 self
.printProfileDumperCC(path
)
169 self
.printProfileDumperHH(path
)
171 def printControllerPython(self
, path
):
172 code
= self
.symtab
.codeFormatter()
174 py_ident
= "%s_Controller" % ident
175 c_ident
= "%s_Controller" % self
.ident
177 from m5.params import *
178 from m5.SimObject import SimObject
179 from Controller import RubyController
181 class $py_ident(RubyController):
185 for param
in self
.config_parameters
:
187 if param
.default
is not None:
188 dflt_str
= str(param
.default
) + ', '
189 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
190 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
191 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
193 self
.error("Unknown c++ to python class conversion for c++ " \
194 "type: '%s'. Please update the python_class_map " \
195 "in StateMachine.py", param
.type_ast
.type.c_ident
)
197 code
.write(path
, '%s.py' % py_ident
)
200 def printControllerHH(self
, path
):
201 '''Output the method declarations for the class declaration'''
202 code
= self
.symtab
.codeFormatter()
204 c_ident
= "%s_Controller" % self
.ident
206 self
.message_buffer_names
= []
209 /** \\file $c_ident.hh
211 * Auto generated C++ code started by $__file__:$__line__
212 * Created by slicc definition of Module "${{self.short}}"
215 #ifndef __${ident}_CONTROLLER_HH__
216 #define __${ident}_CONTROLLER_HH__
222 #include "mem/protocol/${ident}_ProfileDumper.hh"
223 #include "mem/protocol/${ident}_Profiler.hh"
224 #include "mem/protocol/TransitionResult.hh"
225 #include "mem/protocol/Types.hh"
226 #include "mem/ruby/common/Consumer.hh"
227 #include "mem/ruby/common/Global.hh"
228 #include "mem/ruby/slicc_interface/AbstractController.hh"
229 #include "params/$c_ident.hh"
233 for var
in self
.objects
:
234 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
235 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
236 seen_types
.add(var
.type.ident
)
238 # for adding information to the protocol debug trace
240 extern std::stringstream ${ident}_transitionComment;
242 class $c_ident : public AbstractController
244 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
245 // making the Chip a friend class is an easy way to do this for now
248 typedef ${c_ident}Params Params;
249 $c_ident(const Params *p);
250 static int getNumControllers();
252 MessageBuffer* getMandatoryQueue() const;
253 const int & getVersion() const;
254 const std::string toString() const;
255 const std::string getName() const;
256 const MachineType getMachineType() const;
257 void stallBuffer(MessageBuffer* buf, Address addr);
258 void wakeUpBuffers(Address addr);
259 void wakeUpAllBuffers();
260 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
261 void print(std::ostream& out) const;
262 void printConfig(std::ostream& out) const;
264 void printStats(std::ostream& out) const;
266 void blockOnQueue(Address addr, MessageBuffer* port);
267 void unblock(Address addr);
274 for param
in self
.config_parameters
:
276 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
278 code('${{param.type_ast.type}} m_${{param.ident}};')
281 int m_number_of_TBEs;
283 TransitionResult doTransition(${ident}_Event event,
286 if self
.EntryType
!= None:
288 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
290 if self
.TBEType
!= None:
292 ${{self.TBEType.c_ident}}* m_tbe_ptr,
296 const Address& addr);
298 TransitionResult doTransitionWorker(${ident}_Event event,
299 ${ident}_State state,
300 ${ident}_State& next_state,
303 if self
.TBEType
!= None:
305 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
307 if self
.EntryType
!= None:
309 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
313 const Address& addr);
316 int m_transitions_per_cycle;
318 int m_recycle_latency;
319 std::map<std::string, std::string> m_cfg;
322 MachineID m_machineID;
324 std::map<Address, MessageBuffer*> m_block_map;
325 typedef std::vector<MessageBuffer*> MsgVecType;
326 typedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
327 WaitingBufType m_waiting_buffers;
328 int m_max_in_port_rank;
329 int m_cur_in_port_rank;
330 static ${ident}_ProfileDumper s_profileDumper;
331 ${ident}_Profiler m_profiler;
332 static int m_num_controllers;
334 // Internal functions
337 for func
in self
.functions
:
338 proto
= func
.prototype
342 if self
.EntryType
!= None:
345 // Set and Reset for cache_entry variable
346 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
347 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
350 if self
.TBEType
!= None:
353 // Set and Reset for tbe variable
354 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
355 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
362 if self
.TBEType
!= None and self
.EntryType
!= 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, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
366 elif self
.TBEType
!= None:
367 for action
in self
.actions
.itervalues():
368 code('/** \\brief ${{action.desc}} */')
369 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& 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}}*& m_cache_entry_ptr, const Address& addr);')
375 for action
in self
.actions
.itervalues():
376 code('/** \\brief ${{action.desc}} */')
377 code('void ${{action.ident}}(const Address& addr);')
379 # the controller internal variables
384 for var
in self
.objects
:
385 th
= var
.get("template_hack", "")
386 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
388 if var
.type.ident
== "MessageBuffer":
389 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
393 code('#endif // __${ident}_CONTROLLER_H__')
394 code
.write(path
, '%s.hh' % c_ident
)
396 def printControllerCC(self
, path
):
397 '''Output the actions for performing the actions'''
399 code
= self
.symtab
.codeFormatter()
401 c_ident
= "%s_Controller" % self
.ident
404 /** \\file $c_ident.cc
406 * Auto generated C++ code started by $__file__:$__line__
407 * Created by slicc definition of Module "${{self.short}}"
414 #include "base/cprintf.hh"
415 #include "debug/RubyGenerated.hh"
416 #include "debug/RubySlicc.hh"
417 #include "mem/protocol/${ident}_Controller.hh"
418 #include "mem/protocol/${ident}_Event.hh"
419 #include "mem/protocol/${ident}_State.hh"
420 #include "mem/protocol/Types.hh"
421 #include "mem/ruby/common/Global.hh"
422 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
423 #include "mem/ruby/system/System.hh"
428 # include object classes
430 for var
in self
.objects
:
431 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
432 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
433 seen_types
.add(var
.type.ident
)
437 ${c_ident}Params::create()
439 return new $c_ident(this);
442 int $c_ident::m_num_controllers = 0;
443 ${ident}_ProfileDumper $c_ident::s_profileDumper;
445 // for adding information to the protocol debug trace
446 stringstream ${ident}_transitionComment;
447 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
449 /** \\brief constructor */
450 $c_ident::$c_ident(const Params *p)
451 : AbstractController(p)
453 m_version = p->version;
454 m_transitions_per_cycle = p->transitions_per_cycle;
455 m_buffer_size = p->buffer_size;
456 m_recycle_latency = p->recycle_latency;
457 m_number_of_TBEs = p->number_of_TBEs;
458 m_is_blocking = false;
462 # max_port_rank is used to size vectors and thus should be one plus the
465 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
466 code(' m_max_in_port_rank = $max_port_rank;')
470 # After initializing the universal machine parameters, initialize the
471 # this machines config parameters. Also detemine if these configuration
472 # params include a sequencer. This information will be used later for
473 # contecting the sequencer back to the L1 cache controller.
475 contains_dma_sequencer
= False
477 for param
in self
.config_parameters
:
478 if param
.name
== "dma_sequencer":
479 contains_dma_sequencer
= True
480 elif re
.compile("sequencer").search(param
.name
):
481 sequencers
.append(param
.name
)
483 code('m_${{param.name}}_ptr = p->${{param.name}};')
485 code('m_${{param.name}} = p->${{param.name}};')
488 # For the l1 cache controller, add the special atomic support which
489 # includes passing the sequencer a pointer to the controller.
491 if self
.ident
== "L1Cache":
493 self
.error("The L1Cache controller must include the sequencer " \
494 "configuration parameter")
496 for seq
in sequencers
:
498 m_${{seq}}_ptr->setController(this);
501 # For the DMA controller, pass the sequencer a pointer to the
504 if self
.ident
== "DMA":
505 if not contains_dma_sequencer
:
506 self
.error("The DMA controller must include the sequencer " \
507 "configuration parameter")
510 m_dma_sequencer_ptr->setController(this);
513 code('m_num_controllers++;')
514 for var
in self
.objects
:
515 if var
.ident
.find("mandatoryQueue") >= 0:
516 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
525 MachineType machine_type;
528 m_machineID.type = MachineType_${ident};
529 m_machineID.num = m_version;
531 // initialize objects
532 m_profiler.setVersion(m_version);
533 s_profileDumper.registerProfiler(&m_profiler);
538 for var
in self
.objects
:
540 vid
= "m_%s_ptr" % var
.c_ident
541 if "network" not in var
:
542 # Not a network port object
543 if "primitive" in vtype
:
544 code('$vid = new ${{vtype.c_ident}};')
546 code('(*$vid) = ${{var["default"]}};')
551 code('$vid = ${{var["factory"]}};')
552 elif var
.ident
.find("mandatoryQueue") < 0:
553 th
= var
.get("template_hack", "")
554 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
557 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
558 if expr
.find("TBETable") >= 0:
559 args
= "m_number_of_TBEs"
561 args
= var
.get("constructor_hack", "")
563 code('$expr($args);')
565 code('assert($vid != NULL);')
568 code('*$vid = ${{var["default"]}}; // Object default')
569 elif "default" in vtype
:
570 comment
= "Type %s default" % vtype
.ident
571 code('*$vid = ${{vtype["default"]}}; // $comment')
574 if "ordered" in var
and "trigger_queue" not in var
:
576 code('$vid->setOrdering(${{var["ordered"]}});')
581 code('$vid->setRandomization(${{var["random"]}});')
584 if vtype
.isBuffer
and \
585 "rank" in var
and "trigger_queue" not in var
:
586 code('$vid->setPriority(${{var["rank"]}});')
589 # Network port object
590 network
= var
["network"]
591 ordered
= var
["ordered"]
592 vnet
= var
["virtual_network"]
593 vnet_type
= var
["vnet_type"]
595 assert var
.machine
is not None
597 machine_type = string_to_MachineType("${{var.machine.ident}}");
598 base = MachineType_base_number(machine_type);
599 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
602 code('assert($vid != NULL);')
607 code('$vid->setOrdering(${{var["ordered"]}});')
612 code('$vid->setRandomization(${{var["random"]}});')
616 code('$vid->setPriority(${{var["rank"]}})')
621 if (m_buffer_size > 0) {
622 $vid->resize(m_buffer_size);
626 # set description (may be overriden later by port def)
628 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
633 if "recycle_latency" in var
:
634 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
636 code('$vid->setRecycleLatency(m_recycle_latency);')
639 # Set the queue consumers
641 for port
in self
.in_ports
:
642 code('${{port.code}}.setConsumer(this);')
644 # Set the queue descriptions
646 for port
in self
.in_ports
:
647 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
649 # Initialize the transition profiling
651 for trans
in self
.transitions
:
652 # Figure out if we stall
654 for action
in trans
.actions
:
655 if action
.ident
== "z_stall":
658 # Only possible if it is not a 'z' case
660 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
661 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
662 code('m_profiler.possibleTransition($state, $event);')
667 has_mandatory_q
= False
668 for port
in self
.in_ports
:
669 if port
.code
.find("mandatoryQueue_ptr") >= 0:
670 has_mandatory_q
= True
673 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
679 $c_ident::getNumControllers()
681 return m_num_controllers;
685 $c_ident::getMandatoryQueue() const
691 $c_ident::getVersion() const
697 $c_ident::toString() const
703 $c_ident::getName() const
709 $c_ident::getMachineType() const
711 return MachineType_${ident};
715 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
717 if (m_waiting_buffers.count(addr) == 0) {
718 MsgVecType* msgVec = new MsgVecType;
719 msgVec->resize(m_max_in_port_rank, NULL);
720 m_waiting_buffers[addr] = msgVec;
722 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
726 $c_ident::wakeUpBuffers(Address addr)
728 if (m_waiting_buffers.count(addr) > 0) {
730 // Wake up all possible lower rank (i.e. lower priority) buffers that could
731 // be waiting on this message.
733 for (int in_port_rank = m_cur_in_port_rank - 1;
736 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
737 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
740 delete m_waiting_buffers[addr];
741 m_waiting_buffers.erase(addr);
746 $c_ident::wakeUpAllBuffers()
749 // Wake up all possible buffers that could be waiting on any message.
752 std::vector<MsgVecType*> wokeUpMsgVecs;
754 if(m_waiting_buffers.size() > 0) {
755 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
756 buf_iter != m_waiting_buffers.end();
758 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
759 vec_iter != buf_iter->second->end();
761 if (*vec_iter != NULL) {
762 (*vec_iter)->reanalyzeAllMessages();
765 wokeUpMsgVecs.push_back(buf_iter->second);
768 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
769 wb_iter != wokeUpMsgVecs.end();
774 m_waiting_buffers.clear();
779 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
781 m_is_blocking = true;
782 m_block_map[addr] = port;
786 $c_ident::unblock(Address addr)
788 m_block_map.erase(addr);
789 if (m_block_map.size() == 0) {
790 m_is_blocking = false;
795 $c_ident::print(ostream& out) const
797 out << "[$c_ident " << m_version << "]";
801 $c_ident::printConfig(ostream& out) const
803 out << "$c_ident config: " << m_name << endl;
804 out << " version: " << m_version << endl;
805 map<string, string>::const_iterator it;
806 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
807 out << " " << it->first << ": " << it->second << endl;
811 $c_ident::printStats(ostream& out) const
815 # Cache and Memory Controllers have specific profilers associated with
816 # them. Print out these stats before dumping state transition stats.
818 for param
in self
.config_parameters
:
819 if param
.type_ast
.type.ident
== "CacheMemory" or \
820 param
.type_ast
.type.ident
== "DirectoryMemory" or \
821 param
.type_ast
.type.ident
== "MemoryControl":
822 assert(param
.pointer
)
823 code(' m_${{param.ident}}_ptr->printStats(out);')
826 if (m_version == 0) {
827 s_profileDumper.dumpStats(out);
831 void $c_ident::clearStats() {
834 # Cache and Memory Controllers have specific profilers associated with
835 # them. These stats must be cleared too.
837 for param
in self
.config_parameters
:
838 if param
.type_ast
.type.ident
== "CacheMemory" or \
839 param
.type_ast
.type.ident
== "MemoryControl":
840 assert(param
.pointer
)
841 code(' m_${{param.ident}}_ptr->clearStats();')
844 m_profiler.clearStats();
848 if self
.EntryType
!= None:
851 // Set and Reset for cache_entry variable
853 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
855 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
859 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
861 m_cache_entry_ptr = 0;
865 if self
.TBEType
!= None:
868 // Set and Reset for tbe variable
870 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
872 m_tbe_ptr = m_new_tbe;
876 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
886 if self
.TBEType
!= None and self
.EntryType
!= None:
887 for action
in self
.actions
.itervalues():
888 if "c_code" not in action
:
892 /** \\brief ${{action.desc}} */
894 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
896 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
897 ${{action["c_code"]}}
901 elif self
.TBEType
!= None:
902 for action
in self
.actions
.itervalues():
903 if "c_code" not in action
:
907 /** \\brief ${{action.desc}} */
909 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
911 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
912 ${{action["c_code"]}}
916 elif self
.EntryType
!= None:
917 for action
in self
.actions
.itervalues():
918 if "c_code" not in action
:
922 /** \\brief ${{action.desc}} */
924 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
926 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
927 ${{action["c_code"]}}
932 for action
in self
.actions
.itervalues():
933 if "c_code" not in action
:
937 /** \\brief ${{action.desc}} */
939 $c_ident::${{action.ident}}(const Address& addr)
941 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
942 ${{action["c_code"]}}
946 for func
in self
.functions
:
947 code(func
.generateCode())
949 code
.write(path
, "%s.cc" % c_ident
)
951 def printCWakeup(self
, path
):
952 '''Output the wakeup loop for the events'''
954 code
= self
.symtab
.codeFormatter()
958 // Auto generated C++ code started by $__file__:$__line__
959 // ${ident}: ${{self.short}}
963 #include "base/misc.hh"
964 #include "debug/RubySlicc.hh"
965 #include "mem/protocol/${ident}_Controller.hh"
966 #include "mem/protocol/${ident}_Event.hh"
967 #include "mem/protocol/${ident}_State.hh"
968 #include "mem/protocol/Types.hh"
969 #include "mem/ruby/common/Global.hh"
970 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
971 #include "mem/ruby/system/System.hh"
976 ${ident}_Controller::wakeup()
980 // Some cases will put us into an infinite loop without this limit
981 assert(counter <= m_transitions_per_cycle);
982 if (counter == m_transitions_per_cycle) {
983 // Count how often we are fully utilized
984 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
986 // Wakeup in another cycle and try again
987 g_eventQueue_ptr->scheduleEvent(this, 1);
997 for port
in self
.in_ports
:
999 code('// ${ident}InPort $port')
1000 if port
.pairs
.has_key("rank"):
1001 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1003 code('m_cur_in_port_rank = 0;')
1004 code('${{port["c_code_in_port"]}}')
1012 break; // If we got this far, we have nothing left todo
1014 // g_eventQueue_ptr->scheduleEvent(this, 1);
1018 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1020 def printCSwitch(self
, path
):
1021 '''Output switch statement for transition table'''
1023 code
= self
.symtab
.codeFormatter()
1027 // Auto generated C++ code started by $__file__:$__line__
1028 // ${ident}: ${{self.short}}
1032 #include "base/misc.hh"
1033 #include "base/trace.hh"
1034 #include "debug/ProtocolTrace.hh"
1035 #include "debug/RubyGenerated.hh"
1036 #include "mem/protocol/${ident}_Controller.hh"
1037 #include "mem/protocol/${ident}_Event.hh"
1038 #include "mem/protocol/${ident}_State.hh"
1039 #include "mem/protocol/Types.hh"
1040 #include "mem/ruby/common/Global.hh"
1041 #include "mem/ruby/system/System.hh"
1043 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1045 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1046 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1049 ${ident}_Controller::doTransition(${ident}_Event event,
1051 if self
.EntryType
!= None:
1053 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1055 if self
.TBEType
!= None:
1057 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1060 const Address &addr)
1063 if self
.TBEType
!= None and self
.EntryType
!= None:
1064 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1065 elif self
.TBEType
!= None:
1066 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1067 elif self
.EntryType
!= None:
1068 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1070 code('${ident}_State state = getState(addr);')
1073 ${ident}_State next_state = state;
1075 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1077 g_eventQueue_ptr->getTime(),
1078 ${ident}_State_to_string(state),
1079 ${ident}_Event_to_string(event),
1082 TransitionResult result =
1084 if self
.TBEType
!= None and self
.EntryType
!= None:
1085 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1086 elif self
.TBEType
!= None:
1087 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1088 elif self
.EntryType
!= None:
1089 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1091 code('doTransitionWorker(event, state, next_state, addr);')
1094 if (result == TransitionResult_Valid) {
1095 DPRINTF(RubyGenerated, "next_state: %s\\n",
1096 ${ident}_State_to_string(next_state));
1097 m_profiler.countTransition(state, event);
1098 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1099 curTick(), m_version, "${ident}",
1100 ${ident}_Event_to_string(event),
1101 ${ident}_State_to_string(state),
1102 ${ident}_State_to_string(next_state),
1103 addr, GET_TRANSITION_COMMENT());
1105 CLEAR_TRANSITION_COMMENT();
1107 if self
.TBEType
!= None and self
.EntryType
!= None:
1108 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1109 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1110 elif self
.TBEType
!= None:
1111 code('setState(m_tbe_ptr, addr, next_state);')
1112 code('setAccessPermission(addr, next_state);')
1113 elif self
.EntryType
!= None:
1114 code('setState(m_cache_entry_ptr, addr, next_state);')
1115 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1117 code('setState(addr, next_state);')
1118 code('setAccessPermission(addr, next_state);')
1121 } else if (result == TransitionResult_ResourceStall) {
1122 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1123 curTick(), m_version, "${ident}",
1124 ${ident}_Event_to_string(event),
1125 ${ident}_State_to_string(state),
1126 ${ident}_State_to_string(next_state),
1127 addr, "Resource Stall");
1128 } else if (result == TransitionResult_ProtocolStall) {
1129 DPRINTF(RubyGenerated, "stalling\\n");
1130 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1131 curTick(), m_version, "${ident}",
1132 ${ident}_Event_to_string(event),
1133 ${ident}_State_to_string(state),
1134 ${ident}_State_to_string(next_state),
1135 addr, "Protocol Stall");
1142 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1143 ${ident}_State state,
1144 ${ident}_State& next_state,
1147 if self
.TBEType
!= None:
1149 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1151 if self
.EntryType
!= None:
1153 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1156 const Address& addr)
1158 switch(HASH_FUN(state, event)) {
1161 # This map will allow suppress generating duplicate code
1164 for trans
in self
.transitions
:
1165 case_string
= "%s_State_%s, %s_Event_%s" % \
1166 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1168 case
= self
.symtab
.codeFormatter()
1169 # Only set next_state if it changes
1170 if trans
.state
!= trans
.nextState
:
1171 ns_ident
= trans
.nextState
.ident
1172 case('next_state = ${ident}_State_${ns_ident};')
1174 actions
= trans
.actions
1176 # Check for resources
1178 res
= trans
.resources
1179 for key
,val
in res
.iteritems():
1180 if key
.type.ident
!= "DNUCAStopTable":
1182 if (!%s.areNSlotsAvailable(%s))
1183 return TransitionResult_ResourceStall;
1184 ''' % (key
.code
, val
)
1185 case_sorter
.append(val
)
1188 # Emit the code sequences in a sorted order. This makes the
1189 # output deterministic (without this the output order can vary
1190 # since Map's keys() on a vector of pointers is not deterministic
1191 for c
in sorted(case_sorter
):
1194 # Figure out if we stall
1196 for action
in actions
:
1197 if action
.ident
== "z_stall":
1202 case('return TransitionResult_ProtocolStall;')
1204 if self
.TBEType
!= None and self
.EntryType
!= None:
1205 for action
in actions
:
1206 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1207 elif self
.TBEType
!= None:
1208 for action
in actions
:
1209 case('${{action.ident}}(m_tbe_ptr, addr);')
1210 elif self
.EntryType
!= None:
1211 for action
in actions
:
1212 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1214 for action
in actions
:
1215 case('${{action.ident}}(addr);')
1216 case('return TransitionResult_Valid;')
1220 # Look to see if this transition code is unique.
1221 if case
not in cases
:
1224 cases
[case
].append(case_string
)
1226 # Walk through all of the unique code blocks and spit out the
1227 # corresponding case statement elements
1228 for case
,transitions
in cases
.iteritems():
1229 # Iterative over all the multiple transitions that share
1231 for trans
in transitions
:
1232 code(' case HASH_FUN($trans):')
1237 fatal("Invalid transition\\n"
1238 "%s time: %d addr: %s event: %s state: %s\\n",
1239 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1241 return TransitionResult_Valid;
1244 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1246 def printProfileDumperHH(self
, path
):
1247 code
= self
.symtab
.codeFormatter()
1251 // Auto generated C++ code started by $__file__:$__line__
1252 // ${ident}: ${{self.short}}
1254 #ifndef __${ident}_PROFILE_DUMPER_HH__
1255 #define __${ident}_PROFILE_DUMPER_HH__
1261 #include "${ident}_Event.hh"
1262 #include "${ident}_Profiler.hh"
1264 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1266 class ${ident}_ProfileDumper
1269 ${ident}_ProfileDumper();
1270 void registerProfiler(${ident}_Profiler* profiler);
1271 void dumpStats(std::ostream& out) const;
1274 ${ident}_profilers m_profilers;
1277 #endif // __${ident}_PROFILE_DUMPER_HH__
1279 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1281 def printProfileDumperCC(self
, path
):
1282 code
= self
.symtab
.codeFormatter()
1286 // Auto generated C++ code started by $__file__:$__line__
1287 // ${ident}: ${{self.short}}
1289 #include "mem/protocol/${ident}_ProfileDumper.hh"
1291 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1296 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1298 m_profilers.push_back(profiler);
1302 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1304 out << " --- ${ident} ---\\n";
1305 out << " - Event Counts -\\n";
1306 for (${ident}_Event event = ${ident}_Event_FIRST;
1307 event < ${ident}_Event_NUM;
1309 out << (${ident}_Event) event << " [";
1311 for (int i = 0; i < m_profilers.size(); i++) {
1312 out << m_profilers[i]->getEventCount(event) << " ";
1313 total += m_profilers[i]->getEventCount(event);
1315 out << "] " << total << "\\n";
1318 out << " - Transitions -\\n";
1319 for (${ident}_State state = ${ident}_State_FIRST;
1320 state < ${ident}_State_NUM;
1322 for (${ident}_Event event = ${ident}_Event_FIRST;
1323 event < ${ident}_Event_NUM;
1325 if (m_profilers[0]->isPossible(state, event)) {
1326 out << (${ident}_State) state << " "
1327 << (${ident}_Event) event << " [";
1329 for (int i = 0; i < m_profilers.size(); i++) {
1330 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1331 total += m_profilers[i]->getTransitionCount(state, event);
1333 out << "] " << total << "\\n";
1340 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1342 def printProfilerHH(self
, path
):
1343 code
= self
.symtab
.codeFormatter()
1347 // Auto generated C++ code started by $__file__:$__line__
1348 // ${ident}: ${{self.short}}
1350 #ifndef __${ident}_PROFILER_HH__
1351 #define __${ident}_PROFILER_HH__
1356 #include "mem/protocol/${ident}_Event.hh"
1357 #include "mem/protocol/${ident}_State.hh"
1358 #include "mem/ruby/common/TypeDefines.hh"
1360 class ${ident}_Profiler
1363 ${ident}_Profiler();
1364 void setVersion(int version);
1365 void countTransition(${ident}_State state, ${ident}_Event event);
1366 void possibleTransition(${ident}_State state, ${ident}_Event event);
1367 uint64 getEventCount(${ident}_Event event);
1368 bool isPossible(${ident}_State state, ${ident}_Event event);
1369 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1373 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1374 int m_event_counters[${ident}_Event_NUM];
1375 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1379 #endif // __${ident}_PROFILER_HH__
1381 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1383 def printProfilerCC(self
, path
):
1384 code
= self
.symtab
.codeFormatter()
1388 // Auto generated C++ code started by $__file__:$__line__
1389 // ${ident}: ${{self.short}}
1393 #include "mem/protocol/${ident}_Profiler.hh"
1395 ${ident}_Profiler::${ident}_Profiler()
1397 for (int state = 0; state < ${ident}_State_NUM; state++) {
1398 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1399 m_possible[state][event] = false;
1400 m_counters[state][event] = 0;
1403 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1404 m_event_counters[event] = 0;
1409 ${ident}_Profiler::setVersion(int version)
1411 m_version = version;
1415 ${ident}_Profiler::clearStats()
1417 for (int state = 0; state < ${ident}_State_NUM; state++) {
1418 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1419 m_counters[state][event] = 0;
1423 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1424 m_event_counters[event] = 0;
1428 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1430 assert(m_possible[state][event]);
1431 m_counters[state][event]++;
1432 m_event_counters[event]++;
1435 ${ident}_Profiler::possibleTransition(${ident}_State state,
1436 ${ident}_Event event)
1438 m_possible[state][event] = true;
1442 ${ident}_Profiler::getEventCount(${ident}_Event event)
1444 return m_event_counters[event];
1448 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1450 return m_possible[state][event];
1454 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1455 ${ident}_Event event)
1457 return m_counters[state][event];
1461 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1463 # **************************
1464 # ******* HTML Files *******
1465 # **************************
1466 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1467 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1468 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1469 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1470 parent.frames[$over_num].location='$over_href'
1472 ${{html.formatShorthand(text)}}
1476 def writeHTMLFiles(self
, path
):
1477 # Create table with no row hilighted
1478 self
.printHTMLTransitions(path
, None)
1480 # Generate transition tables
1481 for state
in self
.states
.itervalues():
1482 self
.printHTMLTransitions(path
, state
)
1484 # Generate action descriptions
1485 for action
in self
.actions
.itervalues():
1486 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1487 code
= html
.createSymbol(action
, "Action")
1488 code
.write(path
, name
)
1490 # Generate state descriptions
1491 for state
in self
.states
.itervalues():
1492 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1493 code
= html
.createSymbol(state
, "State")
1494 code
.write(path
, name
)
1496 # Generate event descriptions
1497 for event
in self
.events
.itervalues():
1498 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1499 code
= html
.createSymbol(event
, "Event")
1500 code
.write(path
, name
)
1502 def printHTMLTransitions(self
, path
, active_state
):
1503 code
= self
.symtab
.codeFormatter()
1507 <BODY link="blue" vlink="blue">
1509 <H1 align="center">${{html.formatShorthand(self.short)}}:
1512 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1521 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1532 for event
in self
.events
.itervalues():
1533 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1534 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1535 code('<TH bgcolor=white>$ref</TH>')
1539 for state
in self
.states
.itervalues():
1541 if state
== active_state
:
1546 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1547 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1548 text
= html
.formatShorthand(state
.short
)
1549 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1552 <TH bgcolor=$color>$ref</TH>
1555 # -- One column for each event
1556 for event
in self
.events
.itervalues():
1557 trans
= self
.table
.get((state
,event
), None)
1559 # This is the no transition case
1560 if state
== active_state
:
1565 code('<TD bgcolor=$color> </TD>')
1568 next
= trans
.nextState
1569 stall_action
= False
1571 # -- Get the actions
1572 for action
in trans
.actions
:
1573 if action
.ident
== "z_stall" or \
1574 action
.ident
== "zz_recycleMandatoryQueue":
1577 # -- Print out "actions/next-state"
1579 if state
== active_state
:
1584 elif active_state
and next
.ident
== active_state
.ident
:
1586 elif state
== active_state
:
1591 code('<TD bgcolor=$color>')
1592 for action
in trans
.actions
:
1593 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1594 ref
= self
.frameRef(href
, "Status", href
, "1",
1600 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1601 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1602 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1607 if state
== active_state
:
1612 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1613 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1614 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1616 <TH bgcolor=$color>$ref</TH>
1625 for event
in self
.events
.itervalues():
1626 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1627 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1628 code('<TH bgcolor=white>$ref</TH>')
1637 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1639 name
= "%s_table.html" % self
.ident
1640 code
.write(path
, name
)
1642 __all__
= [ "StateMachine" ]