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 void stallBuffer(MessageBuffer* buf, Address addr);
257 void wakeUpBuffers(Address addr);
258 void wakeUpAllBuffers();
259 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
260 void print(std::ostream& out) const;
261 void printConfig(std::ostream& out) const;
263 void printStats(std::ostream& out) const;
265 void blockOnQueue(Address addr, MessageBuffer* port);
266 void unblock(Address addr);
273 for param
in self
.config_parameters
:
275 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
277 code('${{param.type_ast.type}} m_${{param.ident}};')
280 int m_number_of_TBEs;
282 TransitionResult doTransition(${ident}_Event event,
285 if self
.EntryType
!= None:
287 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
289 if self
.TBEType
!= None:
291 ${{self.TBEType.c_ident}}* m_tbe_ptr,
295 const Address& addr);
297 TransitionResult doTransitionWorker(${ident}_Event event,
298 ${ident}_State state,
299 ${ident}_State& next_state,
302 if self
.TBEType
!= None:
304 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
306 if self
.EntryType
!= None:
308 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
312 const Address& addr);
315 int m_transitions_per_cycle;
317 int m_recycle_latency;
318 std::map<std::string, std::string> m_cfg;
321 MachineID m_machineID;
323 std::map<Address, MessageBuffer*> m_block_map;
324 typedef std::vector<MessageBuffer*> MsgVecType;
325 typedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
326 WaitingBufType m_waiting_buffers;
327 int m_max_in_port_rank;
328 int m_cur_in_port_rank;
329 static ${ident}_ProfileDumper s_profileDumper;
330 ${ident}_Profiler m_profiler;
331 static int m_num_controllers;
333 // Internal functions
336 for func
in self
.functions
:
337 proto
= func
.prototype
341 if self
.EntryType
!= None:
344 // Set and Reset for cache_entry variable
345 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
346 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
349 if self
.TBEType
!= None:
352 // Set and Reset for tbe variable
353 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
354 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
361 if self
.TBEType
!= None and self
.EntryType
!= None:
362 for action
in self
.actions
.itervalues():
363 code('/** \\brief ${{action.desc}} */')
364 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
365 elif self
.TBEType
!= None:
366 for action
in self
.actions
.itervalues():
367 code('/** \\brief ${{action.desc}} */')
368 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
369 elif self
.EntryType
!= None:
370 for action
in self
.actions
.itervalues():
371 code('/** \\brief ${{action.desc}} */')
372 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
374 for action
in self
.actions
.itervalues():
375 code('/** \\brief ${{action.desc}} */')
376 code('void ${{action.ident}}(const Address& addr);')
378 # the controller internal variables
383 for var
in self
.objects
:
384 th
= var
.get("template_hack", "")
385 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
387 if var
.type.ident
== "MessageBuffer":
388 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
392 code('#endif // __${ident}_CONTROLLER_H__')
393 code
.write(path
, '%s.hh' % c_ident
)
395 def printControllerCC(self
, path
):
396 '''Output the actions for performing the actions'''
398 code
= self
.symtab
.codeFormatter()
400 c_ident
= "%s_Controller" % self
.ident
403 /** \\file $c_ident.cc
405 * Auto generated C++ code started by $__file__:$__line__
406 * Created by slicc definition of Module "${{self.short}}"
413 #include "base/compiler.hh"
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::stallBuffer(MessageBuffer* buf, Address addr)
711 if (m_waiting_buffers.count(addr) == 0) {
712 MsgVecType* msgVec = new MsgVecType;
713 msgVec->resize(m_max_in_port_rank, NULL);
714 m_waiting_buffers[addr] = msgVec;
716 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
720 $c_ident::wakeUpBuffers(Address addr)
722 if (m_waiting_buffers.count(addr) > 0) {
724 // Wake up all possible lower rank (i.e. lower priority) buffers that could
725 // be waiting on this message.
727 for (int in_port_rank = m_cur_in_port_rank - 1;
730 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
731 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
734 delete m_waiting_buffers[addr];
735 m_waiting_buffers.erase(addr);
740 $c_ident::wakeUpAllBuffers()
743 // Wake up all possible buffers that could be waiting on any message.
746 std::vector<MsgVecType*> wokeUpMsgVecs;
748 if(m_waiting_buffers.size() > 0) {
749 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
750 buf_iter != m_waiting_buffers.end();
752 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
753 vec_iter != buf_iter->second->end();
755 if (*vec_iter != NULL) {
756 (*vec_iter)->reanalyzeAllMessages();
759 wokeUpMsgVecs.push_back(buf_iter->second);
762 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
763 wb_iter != wokeUpMsgVecs.end();
768 m_waiting_buffers.clear();
773 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
775 m_is_blocking = true;
776 m_block_map[addr] = port;
780 $c_ident::unblock(Address addr)
782 m_block_map.erase(addr);
783 if (m_block_map.size() == 0) {
784 m_is_blocking = false;
789 $c_ident::print(ostream& out) const
791 out << "[$c_ident " << m_version << "]";
795 $c_ident::printConfig(ostream& out) const
797 out << "$c_ident config: " << m_name << endl;
798 out << " version: " << m_version << endl;
799 map<string, string>::const_iterator it;
800 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
801 out << " " << it->first << ": " << it->second << endl;
805 $c_ident::printStats(ostream& out) const
809 # Cache and Memory Controllers have specific profilers associated with
810 # them. Print out these stats before dumping state transition stats.
812 for param
in self
.config_parameters
:
813 if param
.type_ast
.type.ident
== "CacheMemory" or \
814 param
.type_ast
.type.ident
== "DirectoryMemory" or \
815 param
.type_ast
.type.ident
== "MemoryControl":
816 assert(param
.pointer
)
817 code(' m_${{param.ident}}_ptr->printStats(out);')
820 if (m_version == 0) {
821 s_profileDumper.dumpStats(out);
825 void $c_ident::clearStats() {
828 # Cache and Memory Controllers have specific profilers associated with
829 # them. These stats must be cleared too.
831 for param
in self
.config_parameters
:
832 if param
.type_ast
.type.ident
== "CacheMemory" or \
833 param
.type_ast
.type.ident
== "MemoryControl":
834 assert(param
.pointer
)
835 code(' m_${{param.ident}}_ptr->clearStats();')
838 m_profiler.clearStats();
842 if self
.EntryType
!= None:
845 // Set and Reset for cache_entry variable
847 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
849 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
853 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
855 m_cache_entry_ptr = 0;
859 if self
.TBEType
!= None:
862 // Set and Reset for tbe variable
864 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
866 m_tbe_ptr = m_new_tbe;
870 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
880 if self
.TBEType
!= None and self
.EntryType
!= None:
881 for action
in self
.actions
.itervalues():
882 if "c_code" not in action
:
886 /** \\brief ${{action.desc}} */
888 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
890 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
891 ${{action["c_code"]}}
895 elif self
.TBEType
!= None:
896 for action
in self
.actions
.itervalues():
897 if "c_code" not in action
:
901 /** \\brief ${{action.desc}} */
903 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
905 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
906 ${{action["c_code"]}}
910 elif self
.EntryType
!= None:
911 for action
in self
.actions
.itervalues():
912 if "c_code" not in action
:
916 /** \\brief ${{action.desc}} */
918 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
920 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
921 ${{action["c_code"]}}
926 for action
in self
.actions
.itervalues():
927 if "c_code" not in action
:
931 /** \\brief ${{action.desc}} */
933 $c_ident::${{action.ident}}(const Address& addr)
935 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
936 ${{action["c_code"]}}
940 for func
in self
.functions
:
941 code(func
.generateCode())
943 code
.write(path
, "%s.cc" % c_ident
)
945 def printCWakeup(self
, path
):
946 '''Output the wakeup loop for the events'''
948 code
= self
.symtab
.codeFormatter()
952 // Auto generated C++ code started by $__file__:$__line__
953 // ${ident}: ${{self.short}}
957 #include "base/misc.hh"
958 #include "debug/RubySlicc.hh"
959 #include "mem/protocol/${ident}_Controller.hh"
960 #include "mem/protocol/${ident}_Event.hh"
961 #include "mem/protocol/${ident}_State.hh"
962 #include "mem/protocol/Types.hh"
963 #include "mem/ruby/common/Global.hh"
964 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
965 #include "mem/ruby/system/System.hh"
970 ${ident}_Controller::wakeup()
974 // Some cases will put us into an infinite loop without this limit
975 assert(counter <= m_transitions_per_cycle);
976 if (counter == m_transitions_per_cycle) {
977 // Count how often we are fully utilized
978 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
980 // Wakeup in another cycle and try again
981 g_eventQueue_ptr->scheduleEvent(this, 1);
991 for port
in self
.in_ports
:
993 code('// ${ident}InPort $port')
994 if port
.pairs
.has_key("rank"):
995 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
997 code('m_cur_in_port_rank = 0;')
998 code('${{port["c_code_in_port"]}}')
1006 break; // If we got this far, we have nothing left todo
1008 // g_eventQueue_ptr->scheduleEvent(this, 1);
1012 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1014 def printCSwitch(self
, path
):
1015 '''Output switch statement for transition table'''
1017 code
= self
.symtab
.codeFormatter()
1021 // Auto generated C++ code started by $__file__:$__line__
1022 // ${ident}: ${{self.short}}
1026 #include "base/misc.hh"
1027 #include "base/trace.hh"
1028 #include "debug/ProtocolTrace.hh"
1029 #include "debug/RubyGenerated.hh"
1030 #include "mem/protocol/${ident}_Controller.hh"
1031 #include "mem/protocol/${ident}_Event.hh"
1032 #include "mem/protocol/${ident}_State.hh"
1033 #include "mem/protocol/Types.hh"
1034 #include "mem/ruby/common/Global.hh"
1035 #include "mem/ruby/system/System.hh"
1037 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1039 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1040 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1043 ${ident}_Controller::doTransition(${ident}_Event event,
1045 if self
.EntryType
!= None:
1047 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1049 if self
.TBEType
!= None:
1051 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1054 const Address &addr)
1057 if self
.TBEType
!= None and self
.EntryType
!= None:
1058 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1059 elif self
.TBEType
!= None:
1060 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1061 elif self
.EntryType
!= None:
1062 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1064 code('${ident}_State state = getState(addr);')
1067 ${ident}_State next_state = state;
1069 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1071 g_eventQueue_ptr->getTime(),
1072 ${ident}_State_to_string(state),
1073 ${ident}_Event_to_string(event),
1076 TransitionResult result =
1078 if self
.TBEType
!= None and self
.EntryType
!= None:
1079 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1080 elif self
.TBEType
!= None:
1081 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1082 elif self
.EntryType
!= None:
1083 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1085 code('doTransitionWorker(event, state, next_state, addr);')
1088 if (result == TransitionResult_Valid) {
1089 DPRINTF(RubyGenerated, "next_state: %s\\n",
1090 ${ident}_State_to_string(next_state));
1091 m_profiler.countTransition(state, event);
1092 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1093 curTick(), m_version, "${ident}",
1094 ${ident}_Event_to_string(event),
1095 ${ident}_State_to_string(state),
1096 ${ident}_State_to_string(next_state),
1097 addr, GET_TRANSITION_COMMENT());
1099 CLEAR_TRANSITION_COMMENT();
1101 if self
.TBEType
!= None and self
.EntryType
!= None:
1102 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1103 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1104 elif self
.TBEType
!= None:
1105 code('setState(m_tbe_ptr, addr, next_state);')
1106 code('setAccessPermission(addr, next_state);')
1107 elif self
.EntryType
!= None:
1108 code('setState(m_cache_entry_ptr, addr, next_state);')
1109 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1111 code('setState(addr, next_state);')
1112 code('setAccessPermission(addr, next_state);')
1115 } else if (result == TransitionResult_ResourceStall) {
1116 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1117 curTick(), m_version, "${ident}",
1118 ${ident}_Event_to_string(event),
1119 ${ident}_State_to_string(state),
1120 ${ident}_State_to_string(next_state),
1121 addr, "Resource Stall");
1122 } else if (result == TransitionResult_ProtocolStall) {
1123 DPRINTF(RubyGenerated, "stalling\\n");
1124 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1125 curTick(), m_version, "${ident}",
1126 ${ident}_Event_to_string(event),
1127 ${ident}_State_to_string(state),
1128 ${ident}_State_to_string(next_state),
1129 addr, "Protocol Stall");
1136 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1137 ${ident}_State state,
1138 ${ident}_State& next_state,
1141 if self
.TBEType
!= None:
1143 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1145 if self
.EntryType
!= None:
1147 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1150 const Address& addr)
1152 switch(HASH_FUN(state, event)) {
1155 # This map will allow suppress generating duplicate code
1158 for trans
in self
.transitions
:
1159 case_string
= "%s_State_%s, %s_Event_%s" % \
1160 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1162 case
= self
.symtab
.codeFormatter()
1163 # Only set next_state if it changes
1164 if trans
.state
!= trans
.nextState
:
1165 ns_ident
= trans
.nextState
.ident
1166 case('next_state = ${ident}_State_${ns_ident};')
1168 actions
= trans
.actions
1170 # Check for resources
1172 res
= trans
.resources
1173 for key
,val
in res
.iteritems():
1174 if key
.type.ident
!= "DNUCAStopTable":
1176 if (!%s.areNSlotsAvailable(%s))
1177 return TransitionResult_ResourceStall;
1178 ''' % (key
.code
, val
)
1179 case_sorter
.append(val
)
1182 # Emit the code sequences in a sorted order. This makes the
1183 # output deterministic (without this the output order can vary
1184 # since Map's keys() on a vector of pointers is not deterministic
1185 for c
in sorted(case_sorter
):
1188 # Figure out if we stall
1190 for action
in actions
:
1191 if action
.ident
== "z_stall":
1196 case('return TransitionResult_ProtocolStall;')
1198 if self
.TBEType
!= None and self
.EntryType
!= None:
1199 for action
in actions
:
1200 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1201 elif self
.TBEType
!= None:
1202 for action
in actions
:
1203 case('${{action.ident}}(m_tbe_ptr, addr);')
1204 elif self
.EntryType
!= None:
1205 for action
in actions
:
1206 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1208 for action
in actions
:
1209 case('${{action.ident}}(addr);')
1210 case('return TransitionResult_Valid;')
1214 # Look to see if this transition code is unique.
1215 if case
not in cases
:
1218 cases
[case
].append(case_string
)
1220 # Walk through all of the unique code blocks and spit out the
1221 # corresponding case statement elements
1222 for case
,transitions
in cases
.iteritems():
1223 # Iterative over all the multiple transitions that share
1225 for trans
in transitions
:
1226 code(' case HASH_FUN($trans):')
1231 fatal("Invalid transition\\n"
1232 "%s time: %d addr: %s event: %s state: %s\\n",
1233 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1235 return TransitionResult_Valid;
1238 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1240 def printProfileDumperHH(self
, path
):
1241 code
= self
.symtab
.codeFormatter()
1245 // Auto generated C++ code started by $__file__:$__line__
1246 // ${ident}: ${{self.short}}
1248 #ifndef __${ident}_PROFILE_DUMPER_HH__
1249 #define __${ident}_PROFILE_DUMPER_HH__
1255 #include "${ident}_Event.hh"
1256 #include "${ident}_Profiler.hh"
1258 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1260 class ${ident}_ProfileDumper
1263 ${ident}_ProfileDumper();
1264 void registerProfiler(${ident}_Profiler* profiler);
1265 void dumpStats(std::ostream& out) const;
1268 ${ident}_profilers m_profilers;
1271 #endif // __${ident}_PROFILE_DUMPER_HH__
1273 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1275 def printProfileDumperCC(self
, path
):
1276 code
= self
.symtab
.codeFormatter()
1280 // Auto generated C++ code started by $__file__:$__line__
1281 // ${ident}: ${{self.short}}
1283 #include "mem/protocol/${ident}_ProfileDumper.hh"
1285 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1290 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1292 m_profilers.push_back(profiler);
1296 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1298 out << " --- ${ident} ---\\n";
1299 out << " - Event Counts -\\n";
1300 for (${ident}_Event event = ${ident}_Event_FIRST;
1301 event < ${ident}_Event_NUM;
1303 out << (${ident}_Event) event << " [";
1305 for (int i = 0; i < m_profilers.size(); i++) {
1306 out << m_profilers[i]->getEventCount(event) << " ";
1307 total += m_profilers[i]->getEventCount(event);
1309 out << "] " << total << "\\n";
1312 out << " - Transitions -\\n";
1313 for (${ident}_State state = ${ident}_State_FIRST;
1314 state < ${ident}_State_NUM;
1316 for (${ident}_Event event = ${ident}_Event_FIRST;
1317 event < ${ident}_Event_NUM;
1319 if (m_profilers[0]->isPossible(state, event)) {
1320 out << (${ident}_State) state << " "
1321 << (${ident}_Event) event << " [";
1323 for (int i = 0; i < m_profilers.size(); i++) {
1324 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1325 total += m_profilers[i]->getTransitionCount(state, event);
1327 out << "] " << total << "\\n";
1334 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1336 def printProfilerHH(self
, path
):
1337 code
= self
.symtab
.codeFormatter()
1341 // Auto generated C++ code started by $__file__:$__line__
1342 // ${ident}: ${{self.short}}
1344 #ifndef __${ident}_PROFILER_HH__
1345 #define __${ident}_PROFILER_HH__
1350 #include "mem/protocol/${ident}_Event.hh"
1351 #include "mem/protocol/${ident}_State.hh"
1352 #include "mem/ruby/common/TypeDefines.hh"
1354 class ${ident}_Profiler
1357 ${ident}_Profiler();
1358 void setVersion(int version);
1359 void countTransition(${ident}_State state, ${ident}_Event event);
1360 void possibleTransition(${ident}_State state, ${ident}_Event event);
1361 uint64 getEventCount(${ident}_Event event);
1362 bool isPossible(${ident}_State state, ${ident}_Event event);
1363 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1367 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1368 int m_event_counters[${ident}_Event_NUM];
1369 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1373 #endif // __${ident}_PROFILER_HH__
1375 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1377 def printProfilerCC(self
, path
):
1378 code
= self
.symtab
.codeFormatter()
1382 // Auto generated C++ code started by $__file__:$__line__
1383 // ${ident}: ${{self.short}}
1387 #include "mem/protocol/${ident}_Profiler.hh"
1389 ${ident}_Profiler::${ident}_Profiler()
1391 for (int state = 0; state < ${ident}_State_NUM; state++) {
1392 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1393 m_possible[state][event] = false;
1394 m_counters[state][event] = 0;
1397 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1398 m_event_counters[event] = 0;
1403 ${ident}_Profiler::setVersion(int version)
1405 m_version = version;
1409 ${ident}_Profiler::clearStats()
1411 for (int state = 0; state < ${ident}_State_NUM; state++) {
1412 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1413 m_counters[state][event] = 0;
1417 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1418 m_event_counters[event] = 0;
1422 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1424 assert(m_possible[state][event]);
1425 m_counters[state][event]++;
1426 m_event_counters[event]++;
1429 ${ident}_Profiler::possibleTransition(${ident}_State state,
1430 ${ident}_Event event)
1432 m_possible[state][event] = true;
1436 ${ident}_Profiler::getEventCount(${ident}_Event event)
1438 return m_event_counters[event];
1442 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1444 return m_possible[state][event];
1448 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1449 ${ident}_Event event)
1451 return m_counters[state][event];
1455 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1457 # **************************
1458 # ******* HTML Files *******
1459 # **************************
1460 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1461 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1462 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1463 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1464 parent.frames[$over_num].location='$over_href'
1466 ${{html.formatShorthand(text)}}
1470 def writeHTMLFiles(self
, path
):
1471 # Create table with no row hilighted
1472 self
.printHTMLTransitions(path
, None)
1474 # Generate transition tables
1475 for state
in self
.states
.itervalues():
1476 self
.printHTMLTransitions(path
, state
)
1478 # Generate action descriptions
1479 for action
in self
.actions
.itervalues():
1480 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1481 code
= html
.createSymbol(action
, "Action")
1482 code
.write(path
, name
)
1484 # Generate state descriptions
1485 for state
in self
.states
.itervalues():
1486 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1487 code
= html
.createSymbol(state
, "State")
1488 code
.write(path
, name
)
1490 # Generate event descriptions
1491 for event
in self
.events
.itervalues():
1492 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1493 code
= html
.createSymbol(event
, "Event")
1494 code
.write(path
, name
)
1496 def printHTMLTransitions(self
, path
, active_state
):
1497 code
= self
.symtab
.codeFormatter()
1501 <BODY link="blue" vlink="blue">
1503 <H1 align="center">${{html.formatShorthand(self.short)}}:
1506 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1515 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1526 for event
in self
.events
.itervalues():
1527 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1528 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1529 code('<TH bgcolor=white>$ref</TH>')
1533 for state
in self
.states
.itervalues():
1535 if state
== active_state
:
1540 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1541 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1542 text
= html
.formatShorthand(state
.short
)
1543 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1546 <TH bgcolor=$color>$ref</TH>
1549 # -- One column for each event
1550 for event
in self
.events
.itervalues():
1551 trans
= self
.table
.get((state
,event
), None)
1553 # This is the no transition case
1554 if state
== active_state
:
1559 code('<TD bgcolor=$color> </TD>')
1562 next
= trans
.nextState
1563 stall_action
= False
1565 # -- Get the actions
1566 for action
in trans
.actions
:
1567 if action
.ident
== "z_stall" or \
1568 action
.ident
== "zz_recycleMandatoryQueue":
1571 # -- Print out "actions/next-state"
1573 if state
== active_state
:
1578 elif active_state
and next
.ident
== active_state
.ident
:
1580 elif state
== active_state
:
1585 code('<TD bgcolor=$color>')
1586 for action
in trans
.actions
:
1587 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1588 ref
= self
.frameRef(href
, "Status", href
, "1",
1594 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1595 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1596 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1601 if state
== active_state
:
1606 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1607 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1608 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1610 <TH bgcolor=$color>$ref</TH>
1619 for event
in self
.events
.itervalues():
1620 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1621 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1622 code('<TH bgcolor=white>$ref</TH>')
1631 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1633 name
= "%s_table.html" % self
.ident
1634 code
.write(path
, name
)
1636 __all__
= [ "StateMachine" ]