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 for func
in self
.functions
:
172 func
.writeCodeFiles(path
)
174 def printControllerPython(self
, path
):
175 code
= self
.symtab
.codeFormatter()
177 py_ident
= "%s_Controller" % ident
178 c_ident
= "%s_Controller" % self
.ident
180 from m5.params import *
181 from m5.SimObject import SimObject
182 from Controller import RubyController
184 class $py_ident(RubyController):
188 for param
in self
.config_parameters
:
190 if param
.default
is not None:
191 dflt_str
= str(param
.default
) + ', '
192 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
193 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
194 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
196 self
.error("Unknown c++ to python class conversion for c++ " \
197 "type: '%s'. Please update the python_class_map " \
198 "in StateMachine.py", param
.type_ast
.type.c_ident
)
200 code
.write(path
, '%s.py' % py_ident
)
203 def printControllerHH(self
, path
):
204 '''Output the method declarations for the class declaration'''
205 code
= self
.symtab
.codeFormatter()
207 c_ident
= "%s_Controller" % self
.ident
209 self
.message_buffer_names
= []
212 /** \\file $c_ident.hh
214 * Auto generated C++ code started by $__file__:$__line__
215 * Created by slicc definition of Module "${{self.short}}"
218 #ifndef __${ident}_CONTROLLER_HH__
219 #define __${ident}_CONTROLLER_HH__
225 #include "mem/protocol/${ident}_ProfileDumper.hh"
226 #include "mem/protocol/${ident}_Profiler.hh"
227 #include "mem/protocol/TransitionResult.hh"
228 #include "mem/protocol/Types.hh"
229 #include "mem/ruby/common/Consumer.hh"
230 #include "mem/ruby/common/Global.hh"
231 #include "mem/ruby/slicc_interface/AbstractController.hh"
232 #include "params/$c_ident.hh"
236 for var
in self
.objects
:
237 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
238 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
239 seen_types
.add(var
.type.ident
)
241 # for adding information to the protocol debug trace
243 extern std::stringstream ${ident}_transitionComment;
245 class $c_ident : public AbstractController
247 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
248 // making the Chip a friend class is an easy way to do this for now
251 typedef ${c_ident}Params Params;
252 $c_ident(const Params *p);
253 static int getNumControllers();
255 MessageBuffer* getMandatoryQueue() const;
256 const int & getVersion() const;
257 const std::string toString() const;
258 const std::string getName() const;
259 const MachineType getMachineType() const;
260 void stallBuffer(MessageBuffer* buf, Address addr);
261 void wakeUpBuffers(Address addr);
262 void wakeUpAllBuffers();
263 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
264 void print(std::ostream& out) const;
265 void printConfig(std::ostream& out) const;
267 void printStats(std::ostream& out) const;
269 void blockOnQueue(Address addr, MessageBuffer* port);
270 void unblock(Address addr);
277 for param
in self
.config_parameters
:
279 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
281 code('${{param.type_ast.type}} m_${{param.ident}};')
284 int m_number_of_TBEs;
286 TransitionResult doTransition(${ident}_Event event,
289 if self
.EntryType
!= None:
291 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
293 if self
.TBEType
!= None:
295 ${{self.TBEType.c_ident}}* m_tbe_ptr,
299 const Address& addr);
301 TransitionResult doTransitionWorker(${ident}_Event event,
302 ${ident}_State state,
303 ${ident}_State& next_state,
306 if self
.TBEType
!= None:
308 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
310 if self
.EntryType
!= None:
312 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
316 const Address& addr);
319 int m_transitions_per_cycle;
321 int m_recycle_latency;
322 std::map<std::string, std::string> m_cfg;
325 MachineID m_machineID;
327 std::map<Address, MessageBuffer*> m_block_map;
328 typedef std::vector<MessageBuffer*> MsgVecType;
329 typedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
330 WaitingBufType m_waiting_buffers;
331 int m_max_in_port_rank;
332 int m_cur_in_port_rank;
333 static ${ident}_ProfileDumper s_profileDumper;
334 ${ident}_Profiler m_profiler;
335 static int m_num_controllers;
337 // Internal functions
340 for func
in self
.functions
:
341 proto
= func
.prototype
345 if self
.EntryType
!= None:
348 // Set and Reset for cache_entry variable
349 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
350 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
353 if self
.TBEType
!= None:
356 // Set and Reset for tbe variable
357 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
358 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
365 if self
.TBEType
!= None and self
.EntryType
!= 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, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
369 elif self
.TBEType
!= None:
370 for action
in self
.actions
.itervalues():
371 code('/** \\brief ${{action.desc}} */')
372 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
373 elif self
.EntryType
!= None:
374 for action
in self
.actions
.itervalues():
375 code('/** \\brief ${{action.desc}} */')
376 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
378 for action
in self
.actions
.itervalues():
379 code('/** \\brief ${{action.desc}} */')
380 code('void ${{action.ident}}(const Address& addr);')
382 # the controller internal variables
387 for var
in self
.objects
:
388 th
= var
.get("template_hack", "")
389 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
391 if var
.type.ident
== "MessageBuffer":
392 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
396 code('#endif // __${ident}_CONTROLLER_H__')
397 code
.write(path
, '%s.hh' % c_ident
)
399 def printControllerCC(self
, path
):
400 '''Output the actions for performing the actions'''
402 code
= self
.symtab
.codeFormatter()
404 c_ident
= "%s_Controller" % self
.ident
407 /** \\file $c_ident.cc
409 * Auto generated C++ code started by $__file__:$__line__
410 * Created by slicc definition of Module "${{self.short}}"
417 #include "base/cprintf.hh"
418 #include "debug/RubyGenerated.hh"
419 #include "debug/RubySlicc.hh"
420 #include "mem/protocol/${ident}_Controller.hh"
421 #include "mem/protocol/${ident}_Event.hh"
422 #include "mem/protocol/${ident}_State.hh"
423 #include "mem/protocol/Types.hh"
424 #include "mem/ruby/common/Global.hh"
425 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
426 #include "mem/ruby/system/System.hh"
431 # include object classes
433 for var
in self
.objects
:
434 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
435 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
436 seen_types
.add(var
.type.ident
)
440 ${c_ident}Params::create()
442 return new $c_ident(this);
445 int $c_ident::m_num_controllers = 0;
446 ${ident}_ProfileDumper $c_ident::s_profileDumper;
448 // for adding information to the protocol debug trace
449 stringstream ${ident}_transitionComment;
450 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
452 /** \\brief constructor */
453 $c_ident::$c_ident(const Params *p)
454 : AbstractController(p)
456 m_version = p->version;
457 m_transitions_per_cycle = p->transitions_per_cycle;
458 m_buffer_size = p->buffer_size;
459 m_recycle_latency = p->recycle_latency;
460 m_number_of_TBEs = p->number_of_TBEs;
461 m_is_blocking = false;
464 # max_port_rank is used to size vectors and thus should be one plus the
467 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
468 code(' m_max_in_port_rank = $max_port_rank;')
472 # After initializing the universal machine parameters, initialize the
473 # this machines config parameters. Also detemine if these configuration
474 # params include a sequencer. This information will be used later for
475 # contecting the sequencer back to the L1 cache controller.
477 contains_dma_sequencer
= False
479 for param
in self
.config_parameters
:
480 if param
.name
== "dma_sequencer":
481 contains_dma_sequencer
= True
482 elif re
.compile("sequencer").search(param
.name
):
483 sequencers
.append(param
.name
)
485 code('m_${{param.name}}_ptr = p->${{param.name}};')
487 code('m_${{param.name}} = p->${{param.name}};')
490 # For the l1 cache controller, add the special atomic support which
491 # includes passing the sequencer a pointer to the controller.
493 if self
.ident
== "L1Cache":
495 self
.error("The L1Cache controller must include the sequencer " \
496 "configuration parameter")
498 for seq
in sequencers
:
500 m_${{seq}}_ptr->setController(this);
503 # For the DMA controller, pass the sequencer a pointer to the
506 if self
.ident
== "DMA":
507 if not contains_dma_sequencer
:
508 self
.error("The DMA controller must include the sequencer " \
509 "configuration parameter")
512 m_dma_sequencer_ptr->setController(this);
515 code('m_num_controllers++;')
516 for var
in self
.objects
:
517 if var
.ident
.find("mandatoryQueue") >= 0:
518 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
527 MachineType machine_type;
530 m_machineID.type = MachineType_${ident};
531 m_machineID.num = m_version;
533 // initialize objects
534 m_profiler.setVersion(m_version);
535 s_profileDumper.registerProfiler(&m_profiler);
540 for var
in self
.objects
:
542 vid
= "m_%s_ptr" % var
.c_ident
543 if "network" not in var
:
544 # Not a network port object
545 if "primitive" in vtype
:
546 code('$vid = new ${{vtype.c_ident}};')
548 code('(*$vid) = ${{var["default"]}};')
553 code('$vid = ${{var["factory"]}};')
554 elif var
.ident
.find("mandatoryQueue") < 0:
555 th
= var
.get("template_hack", "")
556 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
559 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
560 if expr
.find("TBETable") >= 0:
561 args
= "m_number_of_TBEs"
563 args
= var
.get("constructor_hack", "")
565 code('$expr($args);')
567 code('assert($vid != NULL);')
570 code('*$vid = ${{var["default"]}}; // Object default')
571 elif "default" in vtype
:
572 comment
= "Type %s default" % vtype
.ident
573 code('*$vid = ${{vtype["default"]}}; // $comment')
576 if "ordered" in var
and "trigger_queue" not in var
:
578 code('$vid->setOrdering(${{var["ordered"]}});')
583 code('$vid->setRandomization(${{var["random"]}});')
586 if vtype
.isBuffer
and \
587 "rank" in var
and "trigger_queue" not in var
:
588 code('$vid->setPriority(${{var["rank"]}});')
591 # Network port object
592 network
= var
["network"]
593 ordered
= var
["ordered"]
594 vnet
= var
["virtual_network"]
595 vnet_type
= var
["vnet_type"]
597 assert var
.machine
is not None
599 machine_type = string_to_MachineType("${{var.machine.ident}}");
600 base = MachineType_base_number(machine_type);
601 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
604 code('assert($vid != NULL);')
609 code('$vid->setOrdering(${{var["ordered"]}});')
614 code('$vid->setRandomization(${{var["random"]}});')
618 code('$vid->setPriority(${{var["rank"]}})')
623 if (m_buffer_size > 0) {
624 $vid->resize(m_buffer_size);
628 # set description (may be overriden later by port def)
630 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
635 if "recycle_latency" in var
:
636 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
638 code('$vid->setRecycleLatency(m_recycle_latency);')
641 # Set the queue consumers
643 for port
in self
.in_ports
:
644 code('${{port.code}}.setConsumer(this);')
646 # Set the queue descriptions
648 for port
in self
.in_ports
:
649 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
651 # Initialize the transition profiling
653 for trans
in self
.transitions
:
654 # Figure out if we stall
656 for action
in trans
.actions
:
657 if action
.ident
== "z_stall":
660 # Only possible if it is not a 'z' case
662 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
663 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
664 code('m_profiler.possibleTransition($state, $event);')
669 has_mandatory_q
= False
670 for port
in self
.in_ports
:
671 if port
.code
.find("mandatoryQueue_ptr") >= 0:
672 has_mandatory_q
= True
675 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
681 $c_ident::getNumControllers()
683 return m_num_controllers;
687 $c_ident::getMandatoryQueue() const
693 $c_ident::getVersion() const
699 $c_ident::toString() const
705 $c_ident::getName() const
711 $c_ident::getMachineType() const
713 return MachineType_${ident};
717 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
719 if (m_waiting_buffers.count(addr) == 0) {
720 MsgVecType* msgVec = new MsgVecType;
721 msgVec->resize(m_max_in_port_rank, NULL);
722 m_waiting_buffers[addr] = msgVec;
724 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
728 $c_ident::wakeUpBuffers(Address addr)
730 if (m_waiting_buffers.count(addr) > 0) {
732 // Wake up all possible lower rank (i.e. lower priority) buffers that could
733 // be waiting on this message.
735 for (int in_port_rank = m_cur_in_port_rank - 1;
738 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
739 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
742 delete m_waiting_buffers[addr];
743 m_waiting_buffers.erase(addr);
748 $c_ident::wakeUpAllBuffers()
751 // Wake up all possible buffers that could be waiting on any message.
754 std::vector<MsgVecType*> wokeUpMsgVecs;
756 if(m_waiting_buffers.size() > 0) {
757 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
758 buf_iter != m_waiting_buffers.end();
760 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
761 vec_iter != buf_iter->second->end();
763 if (*vec_iter != NULL) {
764 (*vec_iter)->reanalyzeAllMessages();
767 wokeUpMsgVecs.push_back(buf_iter->second);
770 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
771 wb_iter != wokeUpMsgVecs.end();
776 m_waiting_buffers.clear();
781 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
783 m_is_blocking = true;
784 m_block_map[addr] = port;
788 $c_ident::unblock(Address addr)
790 m_block_map.erase(addr);
791 if (m_block_map.size() == 0) {
792 m_is_blocking = false;
797 $c_ident::print(ostream& out) const
799 out << "[$c_ident " << m_version << "]";
803 $c_ident::printConfig(ostream& out) const
805 out << "$c_ident config: " << m_name << endl;
806 out << " version: " << m_version << endl;
807 map<string, string>::const_iterator it;
808 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
809 out << " " << it->first << ": " << it->second << endl;
813 $c_ident::printStats(ostream& out) const
817 # Cache and Memory Controllers have specific profilers associated with
818 # them. Print out these stats before dumping state transition stats.
820 for param
in self
.config_parameters
:
821 if param
.type_ast
.type.ident
== "CacheMemory" or \
822 param
.type_ast
.type.ident
== "DirectoryMemory" or \
823 param
.type_ast
.type.ident
== "MemoryControl":
824 assert(param
.pointer
)
825 code(' m_${{param.ident}}_ptr->printStats(out);')
828 if (m_version == 0) {
829 s_profileDumper.dumpStats(out);
833 void $c_ident::clearStats() {
836 # Cache and Memory Controllers have specific profilers associated with
837 # them. These stats must be cleared too.
839 for param
in self
.config_parameters
:
840 if param
.type_ast
.type.ident
== "CacheMemory" or \
841 param
.type_ast
.type.ident
== "MemoryControl":
842 assert(param
.pointer
)
843 code(' m_${{param.ident}}_ptr->clearStats();')
846 m_profiler.clearStats();
850 if self
.EntryType
!= None:
853 // Set and Reset for cache_entry variable
855 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
857 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
861 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
863 m_cache_entry_ptr = 0;
867 if self
.TBEType
!= None:
870 // Set and Reset for tbe variable
872 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
874 m_tbe_ptr = m_new_tbe;
878 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
888 if self
.TBEType
!= None and self
.EntryType
!= None:
889 for action
in self
.actions
.itervalues():
890 if "c_code" not in action
:
894 /** \\brief ${{action.desc}} */
896 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
898 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
899 ${{action["c_code"]}}
903 elif self
.TBEType
!= None:
904 for action
in self
.actions
.itervalues():
905 if "c_code" not in action
:
909 /** \\brief ${{action.desc}} */
911 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
913 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
914 ${{action["c_code"]}}
918 elif self
.EntryType
!= None:
919 for action
in self
.actions
.itervalues():
920 if "c_code" not in action
:
924 /** \\brief ${{action.desc}} */
926 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
929 ${{action["c_code"]}}
934 for action
in self
.actions
.itervalues():
935 if "c_code" not in action
:
939 /** \\brief ${{action.desc}} */
941 $c_ident::${{action.ident}}(const Address& addr)
943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
944 ${{action["c_code"]}}
948 code
.write(path
, "%s.cc" % c_ident
)
950 def printCWakeup(self
, path
):
951 '''Output the wakeup loop for the events'''
953 code
= self
.symtab
.codeFormatter()
957 // Auto generated C++ code started by $__file__:$__line__
958 // ${ident}: ${{self.short}}
962 #include "base/misc.hh"
963 #include "debug/RubySlicc.hh"
964 #include "mem/protocol/${ident}_Controller.hh"
965 #include "mem/protocol/${ident}_Event.hh"
966 #include "mem/protocol/${ident}_State.hh"
967 #include "mem/protocol/Types.hh"
968 #include "mem/ruby/common/Global.hh"
969 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
970 #include "mem/ruby/system/System.hh"
975 ${ident}_Controller::wakeup()
979 // Some cases will put us into an infinite loop without this limit
980 assert(counter <= m_transitions_per_cycle);
981 if (counter == m_transitions_per_cycle) {
982 // Count how often we are fully utilized
983 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
985 // Wakeup in another cycle and try again
986 g_eventQueue_ptr->scheduleEvent(this, 1);
996 for port
in self
.in_ports
:
998 code('// ${ident}InPort $port')
999 if port
.pairs
.has_key("rank"):
1000 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1002 code('m_cur_in_port_rank = 0;')
1003 code('${{port["c_code_in_port"]}}')
1011 break; // If we got this far, we have nothing left todo
1013 // g_eventQueue_ptr->scheduleEvent(this, 1);
1017 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1019 def printCSwitch(self
, path
):
1020 '''Output switch statement for transition table'''
1022 code
= self
.symtab
.codeFormatter()
1026 // Auto generated C++ code started by $__file__:$__line__
1027 // ${ident}: ${{self.short}}
1031 #include "base/misc.hh"
1032 #include "base/trace.hh"
1033 #include "debug/ProtocolTrace.hh"
1034 #include "debug/RubyGenerated.hh"
1035 #include "mem/protocol/${ident}_Controller.hh"
1036 #include "mem/protocol/${ident}_Event.hh"
1037 #include "mem/protocol/${ident}_State.hh"
1038 #include "mem/protocol/Types.hh"
1039 #include "mem/ruby/common/Global.hh"
1040 #include "mem/ruby/system/System.hh"
1042 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1044 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1045 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1048 ${ident}_Controller::doTransition(${ident}_Event event,
1050 if self
.EntryType
!= None:
1052 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1054 if self
.TBEType
!= None:
1056 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1059 const Address &addr)
1062 if self
.TBEType
!= None and self
.EntryType
!= None:
1063 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1064 elif self
.TBEType
!= None:
1065 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1066 elif self
.EntryType
!= None:
1067 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1069 code('${ident}_State state = getState(addr);')
1072 ${ident}_State next_state = state;
1074 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1076 g_eventQueue_ptr->getTime(),
1077 ${ident}_State_to_string(state),
1078 ${ident}_Event_to_string(event),
1081 TransitionResult result =
1083 if self
.TBEType
!= None and self
.EntryType
!= None:
1084 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1085 elif self
.TBEType
!= None:
1086 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1087 elif self
.EntryType
!= None:
1088 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1090 code('doTransitionWorker(event, state, next_state, addr);')
1093 if (result == TransitionResult_Valid) {
1094 DPRINTF(RubyGenerated, "next_state: %s\\n",
1095 ${ident}_State_to_string(next_state));
1096 m_profiler.countTransition(state, event);
1097 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1098 curTick(), m_version, "${ident}",
1099 ${ident}_Event_to_string(event),
1100 ${ident}_State_to_string(state),
1101 ${ident}_State_to_string(next_state),
1102 addr, GET_TRANSITION_COMMENT());
1104 CLEAR_TRANSITION_COMMENT();
1106 if self
.TBEType
!= None and self
.EntryType
!= None:
1107 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1108 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1109 elif self
.TBEType
!= None:
1110 code('setState(m_tbe_ptr, addr, next_state);')
1111 code('setAccessPermission(addr, next_state);')
1112 elif self
.EntryType
!= None:
1113 code('setState(m_cache_entry_ptr, addr, next_state);')
1114 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1116 code('setState(addr, next_state);')
1117 code('setAccessPermission(addr, next_state);')
1120 } else if (result == TransitionResult_ResourceStall) {
1121 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1122 curTick(), m_version, "${ident}",
1123 ${ident}_Event_to_string(event),
1124 ${ident}_State_to_string(state),
1125 ${ident}_State_to_string(next_state),
1126 addr, "Resource Stall");
1127 } else if (result == TransitionResult_ProtocolStall) {
1128 DPRINTF(RubyGenerated, "stalling\\n");
1129 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1130 curTick(), m_version, "${ident}",
1131 ${ident}_Event_to_string(event),
1132 ${ident}_State_to_string(state),
1133 ${ident}_State_to_string(next_state),
1134 addr, "Protocol Stall");
1141 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1142 ${ident}_State state,
1143 ${ident}_State& next_state,
1146 if self
.TBEType
!= None:
1148 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1150 if self
.EntryType
!= None:
1152 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1155 const Address& addr)
1157 switch(HASH_FUN(state, event)) {
1160 # This map will allow suppress generating duplicate code
1163 for trans
in self
.transitions
:
1164 case_string
= "%s_State_%s, %s_Event_%s" % \
1165 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1167 case
= self
.symtab
.codeFormatter()
1168 # Only set next_state if it changes
1169 if trans
.state
!= trans
.nextState
:
1170 ns_ident
= trans
.nextState
.ident
1171 case('next_state = ${ident}_State_${ns_ident};')
1173 actions
= trans
.actions
1175 # Check for resources
1177 res
= trans
.resources
1178 for key
,val
in res
.iteritems():
1179 if key
.type.ident
!= "DNUCAStopTable":
1181 if (!%s.areNSlotsAvailable(%s))
1182 return TransitionResult_ResourceStall;
1183 ''' % (key
.code
, val
)
1184 case_sorter
.append(val
)
1187 # Emit the code sequences in a sorted order. This makes the
1188 # output deterministic (without this the output order can vary
1189 # since Map's keys() on a vector of pointers is not deterministic
1190 for c
in sorted(case_sorter
):
1193 # Figure out if we stall
1195 for action
in actions
:
1196 if action
.ident
== "z_stall":
1201 case('return TransitionResult_ProtocolStall;')
1203 if self
.TBEType
!= None and self
.EntryType
!= None:
1204 for action
in actions
:
1205 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1206 elif self
.TBEType
!= None:
1207 for action
in actions
:
1208 case('${{action.ident}}(m_tbe_ptr, addr);')
1209 elif self
.EntryType
!= None:
1210 for action
in actions
:
1211 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1213 for action
in actions
:
1214 case('${{action.ident}}(addr);')
1215 case('return TransitionResult_Valid;')
1219 # Look to see if this transition code is unique.
1220 if case
not in cases
:
1223 cases
[case
].append(case_string
)
1225 # Walk through all of the unique code blocks and spit out the
1226 # corresponding case statement elements
1227 for case
,transitions
in cases
.iteritems():
1228 # Iterative over all the multiple transitions that share
1230 for trans
in transitions
:
1231 code(' case HASH_FUN($trans):')
1236 fatal("Invalid transition\\n"
1237 "%s time: %d addr: %s event: %s state: %s\\n",
1238 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1240 return TransitionResult_Valid;
1243 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1245 def printProfileDumperHH(self
, path
):
1246 code
= self
.symtab
.codeFormatter()
1250 // Auto generated C++ code started by $__file__:$__line__
1251 // ${ident}: ${{self.short}}
1253 #ifndef __${ident}_PROFILE_DUMPER_HH__
1254 #define __${ident}_PROFILE_DUMPER_HH__
1260 #include "${ident}_Event.hh"
1261 #include "${ident}_Profiler.hh"
1263 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1265 class ${ident}_ProfileDumper
1268 ${ident}_ProfileDumper();
1269 void registerProfiler(${ident}_Profiler* profiler);
1270 void dumpStats(std::ostream& out) const;
1273 ${ident}_profilers m_profilers;
1276 #endif // __${ident}_PROFILE_DUMPER_HH__
1278 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1280 def printProfileDumperCC(self
, path
):
1281 code
= self
.symtab
.codeFormatter()
1285 // Auto generated C++ code started by $__file__:$__line__
1286 // ${ident}: ${{self.short}}
1288 #include "mem/protocol/${ident}_ProfileDumper.hh"
1290 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1295 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1297 m_profilers.push_back(profiler);
1301 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1303 out << " --- ${ident} ---\\n";
1304 out << " - Event Counts -\\n";
1305 for (${ident}_Event event = ${ident}_Event_FIRST;
1306 event < ${ident}_Event_NUM;
1308 out << (${ident}_Event) event << " [";
1310 for (int i = 0; i < m_profilers.size(); i++) {
1311 out << m_profilers[i]->getEventCount(event) << " ";
1312 total += m_profilers[i]->getEventCount(event);
1314 out << "] " << total << "\\n";
1317 out << " - Transitions -\\n";
1318 for (${ident}_State state = ${ident}_State_FIRST;
1319 state < ${ident}_State_NUM;
1321 for (${ident}_Event event = ${ident}_Event_FIRST;
1322 event < ${ident}_Event_NUM;
1324 if (m_profilers[0]->isPossible(state, event)) {
1325 out << (${ident}_State) state << " "
1326 << (${ident}_Event) event << " [";
1328 for (int i = 0; i < m_profilers.size(); i++) {
1329 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1330 total += m_profilers[i]->getTransitionCount(state, event);
1332 out << "] " << total << "\\n";
1339 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1341 def printProfilerHH(self
, path
):
1342 code
= self
.symtab
.codeFormatter()
1346 // Auto generated C++ code started by $__file__:$__line__
1347 // ${ident}: ${{self.short}}
1349 #ifndef __${ident}_PROFILER_HH__
1350 #define __${ident}_PROFILER_HH__
1355 #include "mem/protocol/${ident}_Event.hh"
1356 #include "mem/protocol/${ident}_State.hh"
1357 #include "mem/ruby/common/Global.hh"
1359 class ${ident}_Profiler
1362 ${ident}_Profiler();
1363 void setVersion(int version);
1364 void countTransition(${ident}_State state, ${ident}_Event event);
1365 void possibleTransition(${ident}_State state, ${ident}_Event event);
1366 uint64 getEventCount(${ident}_Event event);
1367 bool isPossible(${ident}_State state, ${ident}_Event event);
1368 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1372 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1373 int m_event_counters[${ident}_Event_NUM];
1374 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1378 #endif // __${ident}_PROFILER_HH__
1380 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1382 def printProfilerCC(self
, path
):
1383 code
= self
.symtab
.codeFormatter()
1387 // Auto generated C++ code started by $__file__:$__line__
1388 // ${ident}: ${{self.short}}
1392 #include "mem/protocol/${ident}_Profiler.hh"
1394 ${ident}_Profiler::${ident}_Profiler()
1396 for (int state = 0; state < ${ident}_State_NUM; state++) {
1397 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1398 m_possible[state][event] = false;
1399 m_counters[state][event] = 0;
1402 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1403 m_event_counters[event] = 0;
1408 ${ident}_Profiler::setVersion(int version)
1410 m_version = version;
1414 ${ident}_Profiler::clearStats()
1416 for (int state = 0; state < ${ident}_State_NUM; state++) {
1417 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1418 m_counters[state][event] = 0;
1422 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1423 m_event_counters[event] = 0;
1427 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1429 assert(m_possible[state][event]);
1430 m_counters[state][event]++;
1431 m_event_counters[event]++;
1434 ${ident}_Profiler::possibleTransition(${ident}_State state,
1435 ${ident}_Event event)
1437 m_possible[state][event] = true;
1441 ${ident}_Profiler::getEventCount(${ident}_Event event)
1443 return m_event_counters[event];
1447 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1449 return m_possible[state][event];
1453 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1454 ${ident}_Event event)
1456 return m_counters[state][event];
1460 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1462 # **************************
1463 # ******* HTML Files *******
1464 # **************************
1465 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1466 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1467 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1468 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1469 parent.frames[$over_num].location='$over_href'
1471 ${{html.formatShorthand(text)}}
1475 def writeHTMLFiles(self
, path
):
1476 # Create table with no row hilighted
1477 self
.printHTMLTransitions(path
, None)
1479 # Generate transition tables
1480 for state
in self
.states
.itervalues():
1481 self
.printHTMLTransitions(path
, state
)
1483 # Generate action descriptions
1484 for action
in self
.actions
.itervalues():
1485 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1486 code
= html
.createSymbol(action
, "Action")
1487 code
.write(path
, name
)
1489 # Generate state descriptions
1490 for state
in self
.states
.itervalues():
1491 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1492 code
= html
.createSymbol(state
, "State")
1493 code
.write(path
, name
)
1495 # Generate event descriptions
1496 for event
in self
.events
.itervalues():
1497 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1498 code
= html
.createSymbol(event
, "Event")
1499 code
.write(path
, name
)
1501 def printHTMLTransitions(self
, path
, active_state
):
1502 code
= self
.symtab
.codeFormatter()
1506 <BODY link="blue" vlink="blue">
1508 <H1 align="center">${{html.formatShorthand(self.short)}}:
1511 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1520 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1531 for event
in self
.events
.itervalues():
1532 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1533 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1534 code('<TH bgcolor=white>$ref</TH>')
1538 for state
in self
.states
.itervalues():
1540 if state
== active_state
:
1545 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1546 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1547 text
= html
.formatShorthand(state
.short
)
1548 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1551 <TH bgcolor=$color>$ref</TH>
1554 # -- One column for each event
1555 for event
in self
.events
.itervalues():
1556 trans
= self
.table
.get((state
,event
), None)
1558 # This is the no transition case
1559 if state
== active_state
:
1564 code('<TD bgcolor=$color> </TD>')
1567 next
= trans
.nextState
1568 stall_action
= False
1570 # -- Get the actions
1571 for action
in trans
.actions
:
1572 if action
.ident
== "z_stall" or \
1573 action
.ident
== "zz_recycleMandatoryQueue":
1576 # -- Print out "actions/next-state"
1578 if state
== active_state
:
1583 elif active_state
and next
.ident
== active_state
.ident
:
1585 elif state
== active_state
:
1590 code('<TD bgcolor=$color>')
1591 for action
in trans
.actions
:
1592 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1593 ref
= self
.frameRef(href
, "Status", href
, "1",
1599 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1600 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1601 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1606 if state
== active_state
:
1611 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1612 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1613 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1615 <TH bgcolor=$color>$ref</TH>
1624 for event
in self
.events
.itervalues():
1625 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1626 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1627 code('<TH bgcolor=white>$ref</TH>')
1636 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1638 name
= "%s_table.html" % self
.ident
1639 code
.write(path
, name
)
1641 __all__
= [ "StateMachine" ]