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
34 python_class_map
= {"int": "Int",
35 "std::string": "String",
37 "CacheMemory": "RubyCache",
38 "Sequencer": "RubySequencer",
39 "DirectoryMemory": "RubyDirectoryMemory",
40 "MemoryControl": "RubyMemoryControl",
41 "DMASequencer": "DMASequencer"
44 class StateMachine(Symbol
):
45 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
46 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
48 self
.config_parameters
= config_parameters
50 for param
in config_parameters
:
52 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
53 "(*m_%s_ptr)" % param
.name
, {}, self
)
55 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
56 "m_%s" % param
.name
, {}, self
)
57 self
.symtab
.registerSym(param
.name
, var
)
59 self
.states
= orderdict()
60 self
.events
= orderdict()
61 self
.actions
= orderdict()
69 self
.message_buffer_names
= []
72 return "[StateMachine: %s]" % self
.ident
74 def addState(self
, state
):
75 assert self
.table
is None
76 self
.states
[state
.ident
] = state
78 def addEvent(self
, event
):
79 assert self
.table
is None
80 self
.events
[event
.ident
] = event
82 def addAction(self
, action
):
83 assert self
.table
is None
85 # Check for duplicate action
86 for other
in self
.actions
.itervalues():
87 if action
.ident
== other
.ident
:
88 action
.warning("Duplicate action definition: %s" % action
.ident
)
89 action
.error("Duplicate action definition: %s" % action
.ident
)
90 if action
.short
== other
.short
:
91 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
92 other
.warning(" shorthand = %s" % other
.short
)
93 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
94 action
.error(" shorthand = %s" % action
.short
)
96 self
.actions
[action
.ident
] = action
98 def addTransition(self
, trans
):
99 assert self
.table
is None
100 self
.transitions
.append(trans
)
102 def addInPort(self
, var
):
103 self
.in_ports
.append(var
)
105 def addFunc(self
, func
):
106 # register func in the symbol table
107 self
.symtab
.registerSym(str(func
), func
)
108 self
.functions
.append(func
)
110 def addObject(self
, obj
):
111 self
.objects
.append(obj
)
113 def addType(self
, type):
114 type_ident
= '%s' % type.c_ident
116 if type_ident
== "%s_TBE" %self
.ident
:
117 if self
.TBEType
!= None:
118 self
.error("Multiple Transaction Buffer types in a " \
122 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
123 if self
.EntryType
!= None:
124 self
.error("Multiple AbstractCacheEntry types in a " \
126 self
.EntryType
= type
128 # Needs to be called before accessing the table
129 def buildTable(self
):
130 assert self
.table
is None
134 for trans
in self
.transitions
:
135 # Track which actions we touch so we know if we use them
136 # all -- really this should be done for all symbols as
137 # part of the symbol table, then only trigger it for
138 # Actions, States, Events, etc.
140 for action
in trans
.actions
:
143 index
= (trans
.state
, trans
.event
)
145 table
[index
].warning("Duplicate transition: %s" % table
[index
])
146 trans
.error("Duplicate transition: %s" % trans
)
149 # Look at all actions to make sure we used them all
150 for action
in self
.actions
.itervalues():
152 error_msg
= "Unused action: %s" % action
.ident
154 error_msg
+= ", " + action
.desc
155 action
.warning(error_msg
)
158 def writeCodeFiles(self
, path
):
159 self
.printControllerPython(path
)
160 self
.printControllerHH(path
)
161 self
.printControllerCC(path
)
162 self
.printCSwitch(path
)
163 self
.printCWakeup(path
)
164 self
.printProfilerCC(path
)
165 self
.printProfilerHH(path
)
166 self
.printProfileDumperCC(path
)
167 self
.printProfileDumperHH(path
)
169 for func
in self
.functions
:
170 func
.writeCodeFiles(path
)
172 def printControllerPython(self
, path
):
173 code
= self
.symtab
.codeFormatter()
175 py_ident
= "%s_Controller" % ident
176 c_ident
= "%s_Controller" % self
.ident
178 from m5.params import *
179 from m5.SimObject import SimObject
180 from Controller import RubyController
182 class $py_ident(RubyController):
186 for param
in self
.config_parameters
:
188 if param
.default
is not None:
189 dflt_str
= str(param
.default
) + ', '
190 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
191 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
192 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
194 self
.error("Unknown c++ to python class conversion for c++ " \
195 "type: '%s'. Please update the python_class_map " \
196 "in StateMachine.py", param
.type_ast
.type.c_ident
)
198 code
.write(path
, '%s.py' % py_ident
)
201 def printControllerHH(self
, path
):
202 '''Output the method declarations for the class declaration'''
203 code
= self
.symtab
.codeFormatter()
205 c_ident
= "%s_Controller" % self
.ident
207 self
.message_buffer_names
= []
210 /** \\file $c_ident.hh
212 * Auto generated C++ code started by $__file__:$__line__
213 * Created by slicc definition of Module "${{self.short}}"
216 #ifndef __${ident}_CONTROLLER_HH__
217 #define __${ident}_CONTROLLER_HH__
223 #include "params/$c_ident.hh"
225 #include "mem/ruby/common/Global.hh"
226 #include "mem/ruby/common/Consumer.hh"
227 #include "mem/ruby/slicc_interface/AbstractController.hh"
228 #include "mem/protocol/TransitionResult.hh"
229 #include "mem/protocol/Types.hh"
230 #include "mem/protocol/${ident}_Profiler.hh"
231 #include "mem/protocol/${ident}_ProfileDumper.hh"
235 for var
in self
.objects
:
236 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
237 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
238 seen_types
.add(var
.type.ident
)
240 # for adding information to the protocol debug trace
242 extern std::stringstream ${ident}_transitionComment;
244 class $c_ident : public AbstractController
246 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
247 // making the Chip a friend class is an easy way to do this for now
250 typedef ${c_ident}Params Params;
251 $c_ident(const Params *p);
252 static int getNumControllers();
254 MessageBuffer* getMandatoryQueue() const;
255 const int & getVersion() const;
256 const std::string toString() const;
257 const std::string getName() const;
258 const MachineType getMachineType() const;
259 void stallBuffer(MessageBuffer* buf, Address addr);
260 void wakeUpBuffers(Address addr);
261 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
262 void print(std::ostream& out) const;
263 void printConfig(std::ostream& out) const;
265 void printStats(std::ostream& out) const;
267 void blockOnQueue(Address addr, MessageBuffer* port);
268 void unblock(Address addr);
275 for param
in self
.config_parameters
:
277 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
279 code('${{param.type_ast.type}} m_${{param.ident}};')
282 int m_number_of_TBEs;
284 TransitionResult doTransition(${ident}_Event event,
287 if self
.EntryType
!= None:
289 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
291 if self
.TBEType
!= None:
293 ${{self.TBEType.c_ident}}* m_tbe_ptr,
297 const Address& addr);
299 TransitionResult doTransitionWorker(${ident}_Event event,
300 ${ident}_State state,
301 ${ident}_State& next_state,
304 if self
.TBEType
!= None:
306 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
308 if self
.EntryType
!= None:
310 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
314 const Address& addr);
317 int m_transitions_per_cycle;
319 int m_recycle_latency;
320 std::map<std::string, std::string> m_cfg;
323 MachineID m_machineID;
325 std::map<Address, MessageBuffer*> m_block_map;
326 typedef std::vector<MessageBuffer*> MsgVecType;
327 typedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
328 WaitingBufType m_waiting_buffers;
329 int m_max_in_port_rank;
330 int m_cur_in_port_rank;
331 static ${ident}_ProfileDumper s_profileDumper;
332 ${ident}_Profiler m_profiler;
333 static int m_num_controllers;
335 // Internal functions
338 for func
in self
.functions
:
339 proto
= func
.prototype
343 if self
.EntryType
!= None:
346 // Set and Reset for cache_entry variable
347 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
348 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
351 if self
.TBEType
!= None:
354 // Set and Reset for tbe variable
355 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
356 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
363 if self
.TBEType
!= None and self
.EntryType
!= None:
364 for action
in self
.actions
.itervalues():
365 code('/** \\brief ${{action.desc}} */')
366 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
367 elif self
.TBEType
!= None:
368 for action
in self
.actions
.itervalues():
369 code('/** \\brief ${{action.desc}} */')
370 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
371 elif self
.EntryType
!= None:
372 for action
in self
.actions
.itervalues():
373 code('/** \\brief ${{action.desc}} */')
374 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
376 for action
in self
.actions
.itervalues():
377 code('/** \\brief ${{action.desc}} */')
378 code('void ${{action.ident}}(const Address& addr);')
380 # the controller internal variables
385 for var
in self
.objects
:
386 th
= var
.get("template_hack", "")
387 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
389 if var
.type.ident
== "MessageBuffer":
390 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
394 code('#endif // __${ident}_CONTROLLER_H__')
395 code
.write(path
, '%s.hh' % c_ident
)
397 def printControllerCC(self
, path
):
398 '''Output the actions for performing the actions'''
400 code
= self
.symtab
.codeFormatter()
402 c_ident
= "%s_Controller" % self
.ident
405 /** \\file $c_ident.cc
407 * Auto generated C++ code started by $__file__:$__line__
408 * Created by slicc definition of Module "${{self.short}}"
415 #include "base/cprintf.hh"
416 #include "mem/protocol/${ident}_Controller.hh"
417 #include "mem/protocol/${ident}_State.hh"
418 #include "mem/protocol/${ident}_Event.hh"
419 #include "mem/protocol/Types.hh"
420 #include "mem/ruby/common/Global.hh"
421 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
422 #include "mem/ruby/system/System.hh"
427 # include object classes
429 for var
in self
.objects
:
430 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
431 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
432 seen_types
.add(var
.type.ident
)
436 ${c_ident}Params::create()
438 return new $c_ident(this);
441 int $c_ident::m_num_controllers = 0;
442 ${ident}_ProfileDumper $c_ident::s_profileDumper;
444 // for adding information to the protocol debug trace
445 stringstream ${ident}_transitionComment;
446 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
448 /** \\brief constructor */
449 $c_ident::$c_ident(const Params *p)
450 : AbstractController(p)
452 m_version = p->version;
453 m_transitions_per_cycle = p->transitions_per_cycle;
454 m_buffer_size = p->buffer_size;
455 m_recycle_latency = p->recycle_latency;
456 m_number_of_TBEs = p->number_of_TBEs;
457 m_is_blocking = false;
460 # max_port_rank is used to size vectors and thus should be one plus the
463 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
464 code(' m_max_in_port_rank = $max_port_rank;')
468 # After initializing the universal machine parameters, initialize the
469 # this machines config parameters. Also detemine if these configuration
470 # params include a sequencer. This information will be used later for
471 # contecting the sequencer back to the L1 cache controller.
473 contains_sequencer
= False
474 for param
in self
.config_parameters
:
475 if param
.name
== "sequencer" or param
.name
== "dma_sequencer":
476 contains_sequencer
= True
478 code('m_${{param.name}}_ptr = p->${{param.name}};')
480 code('m_${{param.name}} = p->${{param.name}};')
483 # For the l1 cache controller, add the special atomic support which
484 # includes passing the sequencer a pointer to the controller.
486 if self
.ident
== "L1Cache":
487 if not contains_sequencer
:
488 self
.error("The L1Cache controller must include the sequencer " \
489 "configuration parameter")
492 m_sequencer_ptr->setController(this);
495 # For the DMA controller, pass the sequencer a pointer to the
498 if self
.ident
== "DMA":
499 if not contains_sequencer
:
500 self
.error("The DMA controller must include the sequencer " \
501 "configuration parameter")
504 m_dma_sequencer_ptr->setController(this);
507 code('m_num_controllers++;')
508 for var
in self
.objects
:
509 if var
.ident
.find("mandatoryQueue") >= 0:
510 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
519 MachineType machine_type;
522 m_machineID.type = MachineType_${ident};
523 m_machineID.num = m_version;
525 // initialize objects
526 m_profiler.setVersion(m_version);
527 s_profileDumper.registerProfiler(&m_profiler);
532 for var
in self
.objects
:
534 vid
= "m_%s_ptr" % var
.c_ident
535 if "network" not in var
:
536 # Not a network port object
537 if "primitive" in vtype
:
538 code('$vid = new ${{vtype.c_ident}};')
540 code('(*$vid) = ${{var["default"]}};')
545 code('$vid = ${{var["factory"]}};')
546 elif var
.ident
.find("mandatoryQueue") < 0:
547 th
= var
.get("template_hack", "")
548 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
551 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
552 if expr
.find("TBETable") >= 0:
553 args
= "m_number_of_TBEs"
555 args
= var
.get("constructor_hack", "")
557 code('$expr($args);')
559 code('assert($vid != NULL);')
562 code('*$vid = ${{var["default"]}}; // Object default')
563 elif "default" in vtype
:
564 comment
= "Type %s default" % vtype
.ident
565 code('*$vid = ${{vtype["default"]}}; // $comment')
568 if "ordered" in var
and "trigger_queue" not in var
:
570 code('$vid->setOrdering(${{var["ordered"]}});')
575 code('$vid->setRandomization(${{var["random"]}});')
578 if vtype
.isBuffer
and \
579 "rank" in var
and "trigger_queue" not in var
:
580 code('$vid->setPriority(${{var["rank"]}});')
583 # Network port object
584 network
= var
["network"]
585 ordered
= var
["ordered"]
586 vnet
= var
["virtual_network"]
588 assert var
.machine
is not None
590 machine_type = string_to_MachineType("${{var.machine.ident}}");
591 base = MachineType_base_number(machine_type);
592 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
595 code('assert($vid != NULL);')
600 code('$vid->setOrdering(${{var["ordered"]}});')
605 code('$vid->setRandomization(${{var["random"]}})')
609 code('$vid->setPriority(${{var["rank"]}})')
614 if (m_buffer_size > 0) {
615 $vid->resize(m_buffer_size);
619 # set description (may be overriden later by port def)
621 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
626 if "recycle_latency" in var
:
627 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
629 code('$vid->setRecycleLatency(m_recycle_latency);')
632 # Set the queue consumers
634 for port
in self
.in_ports
:
635 code('${{port.code}}.setConsumer(this);')
637 # Set the queue descriptions
639 for port
in self
.in_ports
:
640 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
642 # Initialize the transition profiling
644 for trans
in self
.transitions
:
645 # Figure out if we stall
647 for action
in trans
.actions
:
648 if action
.ident
== "z_stall":
651 # Only possible if it is not a 'z' case
653 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
654 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
655 code('m_profiler.possibleTransition($state, $event);')
660 has_mandatory_q
= False
661 for port
in self
.in_ports
:
662 if port
.code
.find("mandatoryQueue_ptr") >= 0:
663 has_mandatory_q
= True
666 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
672 $c_ident::getNumControllers()
674 return m_num_controllers;
678 $c_ident::getMandatoryQueue() const
684 $c_ident::getVersion() const
690 $c_ident::toString() const
696 $c_ident::getName() const
702 $c_ident::getMachineType() const
704 return MachineType_${ident};
708 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
710 if (m_waiting_buffers.count(addr) == 0) {
711 MsgVecType* msgVec = new MsgVecType;
712 msgVec->resize(m_max_in_port_rank, NULL);
713 m_waiting_buffers[addr] = msgVec;
715 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
719 $c_ident::wakeUpBuffers(Address addr)
722 // Wake up all possible lower rank (i.e. lower priority) buffers that could
723 // be waiting on this message.
725 for (int in_port_rank = m_cur_in_port_rank - 1;
728 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
729 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
732 delete m_waiting_buffers[addr];
733 m_waiting_buffers.erase(addr);
737 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
739 m_is_blocking = true;
740 m_block_map[addr] = port;
744 $c_ident::unblock(Address addr)
746 m_block_map.erase(addr);
747 if (m_block_map.size() == 0) {
748 m_is_blocking = false;
753 $c_ident::print(ostream& out) const
755 out << "[$c_ident " << m_version << "]";
759 $c_ident::printConfig(ostream& out) const
761 out << "$c_ident config: " << m_name << endl;
762 out << " version: " << m_version << endl;
763 map<string, string>::const_iterator it;
764 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
765 out << " " << it->first << ": " << it->second << endl;
769 $c_ident::printStats(ostream& out) const
773 # Cache and Memory Controllers have specific profilers associated with
774 # them. Print out these stats before dumping state transition stats.
776 for param
in self
.config_parameters
:
777 if param
.type_ast
.type.ident
== "CacheMemory" or \
778 param
.type_ast
.type.ident
== "DirectoryMemory" or \
779 param
.type_ast
.type.ident
== "MemoryControl":
780 assert(param
.pointer
)
781 code(' m_${{param.ident}}_ptr->printStats(out);')
784 if (m_version == 0) {
785 s_profileDumper.dumpStats(out);
789 void $c_ident::clearStats() {
792 # Cache and Memory Controllers have specific profilers associated with
793 # them. These stats must be cleared too.
795 for param
in self
.config_parameters
:
796 if param
.type_ast
.type.ident
== "CacheMemory" or \
797 param
.type_ast
.type.ident
== "MemoryControl":
798 assert(param
.pointer
)
799 code(' m_${{param.ident}}_ptr->clearStats();')
802 m_profiler.clearStats();
806 if self
.EntryType
!= None:
809 // Set and Reset for cache_entry variable
811 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
813 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
817 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
819 m_cache_entry_ptr = 0;
823 if self
.TBEType
!= None:
826 // Set and Reset for tbe variable
828 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
830 m_tbe_ptr = m_new_tbe;
834 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
844 if self
.TBEType
!= None and self
.EntryType
!= None:
845 for action
in self
.actions
.itervalues():
846 if "c_code" not in action
:
850 /** \\brief ${{action.desc}} */
852 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
854 DPRINTF(RubyGenerated, "executing\\n");
855 ${{action["c_code"]}}
859 elif self
.TBEType
!= None:
860 for action
in self
.actions
.itervalues():
861 if "c_code" not in action
:
865 /** \\brief ${{action.desc}} */
867 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
869 DPRINTF(RubyGenerated, "executing\\n");
870 ${{action["c_code"]}}
874 elif self
.EntryType
!= None:
875 for action
in self
.actions
.itervalues():
876 if "c_code" not in action
:
880 /** \\brief ${{action.desc}} */
882 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
884 DPRINTF(RubyGenerated, "executing\\n");
885 ${{action["c_code"]}}
890 for action
in self
.actions
.itervalues():
891 if "c_code" not in action
:
895 /** \\brief ${{action.desc}} */
897 $c_ident::${{action.ident}}(const Address& addr)
899 DPRINTF(RubyGenerated, "executing\\n");
900 ${{action["c_code"]}}
904 code
.write(path
, "%s.cc" % c_ident
)
906 def printCWakeup(self
, path
):
907 '''Output the wakeup loop for the events'''
909 code
= self
.symtab
.codeFormatter()
913 // Auto generated C++ code started by $__file__:$__line__
914 // ${ident}: ${{self.short}}
918 #include "base/misc.hh"
919 #include "mem/ruby/common/Global.hh"
920 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
921 #include "mem/protocol/${ident}_Controller.hh"
922 #include "mem/protocol/${ident}_State.hh"
923 #include "mem/protocol/${ident}_Event.hh"
924 #include "mem/protocol/Types.hh"
925 #include "mem/ruby/system/System.hh"
930 ${ident}_Controller::wakeup()
934 // Some cases will put us into an infinite loop without this limit
935 assert(counter <= m_transitions_per_cycle);
936 if (counter == m_transitions_per_cycle) {
937 // Count how often we are fully utilized
938 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
940 // Wakeup in another cycle and try again
941 g_eventQueue_ptr->scheduleEvent(this, 1);
951 for port
in self
.in_ports
:
953 code('// ${ident}InPort $port')
954 if port
.pairs
.has_key("rank"):
955 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
957 code('m_cur_in_port_rank = 0;')
958 code('${{port["c_code_in_port"]}}')
966 break; // If we got this far, we have nothing left todo
968 // g_eventQueue_ptr->scheduleEvent(this, 1);
972 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
974 def printCSwitch(self
, path
):
975 '''Output switch statement for transition table'''
977 code
= self
.symtab
.codeFormatter()
981 // Auto generated C++ code started by $__file__:$__line__
982 // ${ident}: ${{self.short}}
986 #include "base/misc.hh"
987 #include "base/trace.hh"
988 #include "mem/ruby/common/Global.hh"
989 #include "mem/protocol/${ident}_Controller.hh"
990 #include "mem/protocol/${ident}_State.hh"
991 #include "mem/protocol/${ident}_Event.hh"
992 #include "mem/protocol/Types.hh"
993 #include "mem/ruby/system/System.hh"
995 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
997 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
998 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1001 ${ident}_Controller::doTransition(${ident}_Event event,
1003 if self
.EntryType
!= None:
1005 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1007 if self
.TBEType
!= None:
1009 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1012 const Address &addr)
1015 if self
.TBEType
!= None and self
.EntryType
!= None:
1016 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1017 elif self
.TBEType
!= None:
1018 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);')
1019 elif self
.EntryType
!= None:
1020 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);')
1022 code('${ident}_State state = ${ident}_getState(addr);')
1025 ${ident}_State next_state = state;
1027 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1029 g_eventQueue_ptr->getTime(),
1030 ${ident}_State_to_string(state),
1031 ${ident}_Event_to_string(event),
1034 TransitionResult result =
1036 if self
.TBEType
!= None and self
.EntryType
!= None:
1037 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1038 elif self
.TBEType
!= None:
1039 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1040 elif self
.EntryType
!= None:
1041 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1043 code('doTransitionWorker(event, state, next_state, addr);')
1046 if (result == TransitionResult_Valid) {
1047 DPRINTF(RubyGenerated, "next_state: %s\\n",
1048 ${ident}_State_to_string(next_state));
1049 m_profiler.countTransition(state, event);
1050 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n",
1051 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1052 ${ident}_Event_to_string(event),
1053 ${ident}_State_to_string(state),
1054 ${ident}_State_to_string(next_state),
1055 addr, GET_TRANSITION_COMMENT());
1057 CLEAR_TRANSITION_COMMENT();
1059 if self
.TBEType
!= None and self
.EntryType
!= None:
1060 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1061 elif self
.TBEType
!= None:
1062 code('${ident}_setState(m_tbe_ptr, addr, next_state);')
1063 elif self
.EntryType
!= None:
1064 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);')
1066 code('${ident}_setState(addr, next_state);')
1069 } else if (result == TransitionResult_ResourceStall) {
1070 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1071 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1072 ${ident}_Event_to_string(event),
1073 ${ident}_State_to_string(state),
1074 ${ident}_State_to_string(next_state),
1075 addr, "Resource Stall");
1076 } else if (result == TransitionResult_ProtocolStall) {
1077 DPRINTF(RubyGenerated, "stalling\\n");
1078 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1079 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1080 ${ident}_Event_to_string(event),
1081 ${ident}_State_to_string(state),
1082 ${ident}_State_to_string(next_state),
1083 addr, "Protocol Stall");
1090 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1091 ${ident}_State state,
1092 ${ident}_State& next_state,
1095 if self
.TBEType
!= None:
1097 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1099 if self
.EntryType
!= None:
1101 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1104 const Address& addr)
1106 switch(HASH_FUN(state, event)) {
1109 # This map will allow suppress generating duplicate code
1112 for trans
in self
.transitions
:
1113 case_string
= "%s_State_%s, %s_Event_%s" % \
1114 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1116 case
= self
.symtab
.codeFormatter()
1117 # Only set next_state if it changes
1118 if trans
.state
!= trans
.nextState
:
1119 ns_ident
= trans
.nextState
.ident
1120 case('next_state = ${ident}_State_${ns_ident};')
1122 actions
= trans
.actions
1124 # Check for resources
1126 res
= trans
.resources
1127 for key
,val
in res
.iteritems():
1128 if key
.type.ident
!= "DNUCAStopTable":
1130 if (!%s.areNSlotsAvailable(%s))
1131 return TransitionResult_ResourceStall;
1132 ''' % (key
.code
, val
)
1133 case_sorter
.append(val
)
1136 # Emit the code sequences in a sorted order. This makes the
1137 # output deterministic (without this the output order can vary
1138 # since Map's keys() on a vector of pointers is not deterministic
1139 for c
in sorted(case_sorter
):
1142 # Figure out if we stall
1144 for action
in actions
:
1145 if action
.ident
== "z_stall":
1150 case('return TransitionResult_ProtocolStall;')
1152 if self
.TBEType
!= None and self
.EntryType
!= None:
1153 for action
in actions
:
1154 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1155 elif self
.TBEType
!= None:
1156 for action
in actions
:
1157 case('${{action.ident}}(m_tbe_ptr, addr);')
1158 elif self
.EntryType
!= None:
1159 for action
in actions
:
1160 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1162 for action
in actions
:
1163 case('${{action.ident}}(addr);')
1164 case('return TransitionResult_Valid;')
1168 # Look to see if this transition code is unique.
1169 if case
not in cases
:
1172 cases
[case
].append(case_string
)
1174 # Walk through all of the unique code blocks and spit out the
1175 # corresponding case statement elements
1176 for case
,transitions
in cases
.iteritems():
1177 # Iterative over all the multiple transitions that share
1179 for trans
in transitions
:
1180 code(' case HASH_FUN($trans):')
1185 fatal("Invalid transition\\n"
1186 "version: %d time: %d addr: %s event: %s state: %s\\n",
1187 m_version, g_eventQueue_ptr->getTime(), addr, event, state);
1189 return TransitionResult_Valid;
1192 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1194 def printProfileDumperHH(self
, path
):
1195 code
= self
.symtab
.codeFormatter()
1199 // Auto generated C++ code started by $__file__:$__line__
1200 // ${ident}: ${{self.short}}
1202 #ifndef __${ident}_PROFILE_DUMPER_HH__
1203 #define __${ident}_PROFILE_DUMPER_HH__
1209 #include "${ident}_Profiler.hh"
1210 #include "${ident}_Event.hh"
1212 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1214 class ${ident}_ProfileDumper
1217 ${ident}_ProfileDumper();
1218 void registerProfiler(${ident}_Profiler* profiler);
1219 void dumpStats(std::ostream& out) const;
1222 ${ident}_profilers m_profilers;
1225 #endif // __${ident}_PROFILE_DUMPER_HH__
1227 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1229 def printProfileDumperCC(self
, path
):
1230 code
= self
.symtab
.codeFormatter()
1234 // Auto generated C++ code started by $__file__:$__line__
1235 // ${ident}: ${{self.short}}
1237 #include "mem/protocol/${ident}_ProfileDumper.hh"
1239 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1244 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1246 m_profilers.push_back(profiler);
1250 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1252 out << " --- ${ident} ---\\n";
1253 out << " - Event Counts -\\n";
1254 for (${ident}_Event event = ${ident}_Event_FIRST;
1255 event < ${ident}_Event_NUM;
1257 out << (${ident}_Event) event << " [";
1259 for (int i = 0; i < m_profilers.size(); i++) {
1260 out << m_profilers[i]->getEventCount(event) << " ";
1261 total += m_profilers[i]->getEventCount(event);
1263 out << "] " << total << "\\n";
1266 out << " - Transitions -\\n";
1267 for (${ident}_State state = ${ident}_State_FIRST;
1268 state < ${ident}_State_NUM;
1270 for (${ident}_Event event = ${ident}_Event_FIRST;
1271 event < ${ident}_Event_NUM;
1273 if (m_profilers[0]->isPossible(state, event)) {
1274 out << (${ident}_State) state << " "
1275 << (${ident}_Event) event << " [";
1277 for (int i = 0; i < m_profilers.size(); i++) {
1278 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1279 total += m_profilers[i]->getTransitionCount(state, event);
1281 out << "] " << total << "\\n";
1288 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1290 def printProfilerHH(self
, path
):
1291 code
= self
.symtab
.codeFormatter()
1295 // Auto generated C++ code started by $__file__:$__line__
1296 // ${ident}: ${{self.short}}
1298 #ifndef __${ident}_PROFILER_HH__
1299 #define __${ident}_PROFILER_HH__
1304 #include "mem/ruby/common/Global.hh"
1305 #include "mem/protocol/${ident}_State.hh"
1306 #include "mem/protocol/${ident}_Event.hh"
1308 class ${ident}_Profiler
1311 ${ident}_Profiler();
1312 void setVersion(int version);
1313 void countTransition(${ident}_State state, ${ident}_Event event);
1314 void possibleTransition(${ident}_State state, ${ident}_Event event);
1315 uint64 getEventCount(${ident}_Event event);
1316 bool isPossible(${ident}_State state, ${ident}_Event event);
1317 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1321 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1322 int m_event_counters[${ident}_Event_NUM];
1323 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1327 #endif // __${ident}_PROFILER_HH__
1329 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1331 def printProfilerCC(self
, path
):
1332 code
= self
.symtab
.codeFormatter()
1336 // Auto generated C++ code started by $__file__:$__line__
1337 // ${ident}: ${{self.short}}
1341 #include "mem/protocol/${ident}_Profiler.hh"
1343 ${ident}_Profiler::${ident}_Profiler()
1345 for (int state = 0; state < ${ident}_State_NUM; state++) {
1346 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1347 m_possible[state][event] = false;
1348 m_counters[state][event] = 0;
1351 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1352 m_event_counters[event] = 0;
1357 ${ident}_Profiler::setVersion(int version)
1359 m_version = version;
1363 ${ident}_Profiler::clearStats()
1365 for (int state = 0; state < ${ident}_State_NUM; state++) {
1366 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1367 m_counters[state][event] = 0;
1371 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1372 m_event_counters[event] = 0;
1376 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1378 assert(m_possible[state][event]);
1379 m_counters[state][event]++;
1380 m_event_counters[event]++;
1383 ${ident}_Profiler::possibleTransition(${ident}_State state,
1384 ${ident}_Event event)
1386 m_possible[state][event] = true;
1390 ${ident}_Profiler::getEventCount(${ident}_Event event)
1392 return m_event_counters[event];
1396 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1398 return m_possible[state][event];
1402 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1403 ${ident}_Event event)
1405 return m_counters[state][event];
1409 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1411 # **************************
1412 # ******* HTML Files *******
1413 # **************************
1414 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1415 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1416 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1417 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1418 parent.frames[$over_num].location='$over_href'
1420 ${{html.formatShorthand(text)}}
1424 def writeHTMLFiles(self
, path
):
1425 # Create table with no row hilighted
1426 self
.printHTMLTransitions(path
, None)
1428 # Generate transition tables
1429 for state
in self
.states
.itervalues():
1430 self
.printHTMLTransitions(path
, state
)
1432 # Generate action descriptions
1433 for action
in self
.actions
.itervalues():
1434 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1435 code
= html
.createSymbol(action
, "Action")
1436 code
.write(path
, name
)
1438 # Generate state descriptions
1439 for state
in self
.states
.itervalues():
1440 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1441 code
= html
.createSymbol(state
, "State")
1442 code
.write(path
, name
)
1444 # Generate event descriptions
1445 for event
in self
.events
.itervalues():
1446 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1447 code
= html
.createSymbol(event
, "Event")
1448 code
.write(path
, name
)
1450 def printHTMLTransitions(self
, path
, active_state
):
1451 code
= self
.symtab
.codeFormatter()
1455 <BODY link="blue" vlink="blue">
1457 <H1 align="center">${{html.formatShorthand(self.short)}}:
1460 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1469 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1480 for event
in self
.events
.itervalues():
1481 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1482 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1483 code('<TH bgcolor=white>$ref</TH>')
1487 for state
in self
.states
.itervalues():
1489 if state
== active_state
:
1494 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1495 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1496 text
= html
.formatShorthand(state
.short
)
1497 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1500 <TH bgcolor=$color>$ref</TH>
1503 # -- One column for each event
1504 for event
in self
.events
.itervalues():
1505 trans
= self
.table
.get((state
,event
), None)
1507 # This is the no transition case
1508 if state
== active_state
:
1513 code('<TD bgcolor=$color> </TD>')
1516 next
= trans
.nextState
1517 stall_action
= False
1519 # -- Get the actions
1520 for action
in trans
.actions
:
1521 if action
.ident
== "z_stall" or \
1522 action
.ident
== "zz_recycleMandatoryQueue":
1525 # -- Print out "actions/next-state"
1527 if state
== active_state
:
1532 elif active_state
and next
.ident
== active_state
.ident
:
1534 elif state
== active_state
:
1539 code('<TD bgcolor=$color>')
1540 for action
in trans
.actions
:
1541 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1542 ref
= self
.frameRef(href
, "Status", href
, "1",
1548 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1549 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1550 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1555 if state
== active_state
:
1560 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1561 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1562 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1564 <TH bgcolor=$color>$ref</TH>
1573 for event
in self
.events
.itervalues():
1574 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1575 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1576 code('<TH bgcolor=white>$ref</TH>')
1585 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1587 name
= "%s_table.html" % self
.ident
1588 code
.write(path
, name
)
1590 __all__
= [ "StateMachine" ]