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);
351 // Set permissions for the cache_entry
352 void set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AccessPermission perm);
355 if self
.TBEType
!= None:
358 // Set and Reset for tbe variable
359 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
360 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
367 if self
.TBEType
!= None and self
.EntryType
!= 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, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
371 elif self
.TBEType
!= None:
372 for action
in self
.actions
.itervalues():
373 code('/** \\brief ${{action.desc}} */')
374 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
375 elif self
.EntryType
!= None:
376 for action
in self
.actions
.itervalues():
377 code('/** \\brief ${{action.desc}} */')
378 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
380 for action
in self
.actions
.itervalues():
381 code('/** \\brief ${{action.desc}} */')
382 code('void ${{action.ident}}(const Address& addr);')
384 # the controller internal variables
389 for var
in self
.objects
:
390 th
= var
.get("template_hack", "")
391 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
393 if var
.type.ident
== "MessageBuffer":
394 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
398 code('#endif // __${ident}_CONTROLLER_H__')
399 code
.write(path
, '%s.hh' % c_ident
)
401 def printControllerCC(self
, path
):
402 '''Output the actions for performing the actions'''
404 code
= self
.symtab
.codeFormatter()
406 c_ident
= "%s_Controller" % self
.ident
409 /** \\file $c_ident.cc
411 * Auto generated C++ code started by $__file__:$__line__
412 * Created by slicc definition of Module "${{self.short}}"
419 #include "base/cprintf.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"]
596 assert var
.machine
is not None
598 machine_type = string_to_MachineType("${{var.machine.ident}}");
599 base = MachineType_base_number(machine_type);
600 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
603 code('assert($vid != NULL);')
608 code('$vid->setOrdering(${{var["ordered"]}});')
613 code('$vid->setRandomization(${{var["random"]}});')
617 code('$vid->setPriority(${{var["rank"]}})')
622 if (m_buffer_size > 0) {
623 $vid->resize(m_buffer_size);
627 # set description (may be overriden later by port def)
629 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
634 if "recycle_latency" in var
:
635 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
637 code('$vid->setRecycleLatency(m_recycle_latency);')
640 # Set the queue consumers
642 for port
in self
.in_ports
:
643 code('${{port.code}}.setConsumer(this);')
645 # Set the queue descriptions
647 for port
in self
.in_ports
:
648 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
650 # Initialize the transition profiling
652 for trans
in self
.transitions
:
653 # Figure out if we stall
655 for action
in trans
.actions
:
656 if action
.ident
== "z_stall":
659 # Only possible if it is not a 'z' case
661 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
662 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
663 code('m_profiler.possibleTransition($state, $event);')
668 has_mandatory_q
= False
669 for port
in self
.in_ports
:
670 if port
.code
.find("mandatoryQueue_ptr") >= 0:
671 has_mandatory_q
= True
674 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
680 $c_ident::getNumControllers()
682 return m_num_controllers;
686 $c_ident::getMandatoryQueue() const
692 $c_ident::getVersion() const
698 $c_ident::toString() const
704 $c_ident::getName() const
710 $c_ident::getMachineType() const
712 return MachineType_${ident};
716 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
718 if (m_waiting_buffers.count(addr) == 0) {
719 MsgVecType* msgVec = new MsgVecType;
720 msgVec->resize(m_max_in_port_rank, NULL);
721 m_waiting_buffers[addr] = msgVec;
723 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
727 $c_ident::wakeUpBuffers(Address addr)
729 if (m_waiting_buffers.count(addr) > 0) {
731 // Wake up all possible lower rank (i.e. lower priority) buffers that could
732 // be waiting on this message.
734 for (int in_port_rank = m_cur_in_port_rank - 1;
737 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
738 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
741 delete m_waiting_buffers[addr];
742 m_waiting_buffers.erase(addr);
747 $c_ident::wakeUpAllBuffers()
750 // Wake up all possible buffers that could be waiting on any message.
753 std::vector<MsgVecType*> wokeUpMsgVecs;
755 if(m_waiting_buffers.size() > 0) {
756 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
757 buf_iter != m_waiting_buffers.end();
759 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
760 vec_iter != buf_iter->second->end();
762 if (*vec_iter != NULL) {
763 (*vec_iter)->reanalyzeAllMessages();
766 wokeUpMsgVecs.push_back(buf_iter->second);
769 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
770 wb_iter != wokeUpMsgVecs.end();
775 m_waiting_buffers.clear();
780 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
782 m_is_blocking = true;
783 m_block_map[addr] = port;
787 $c_ident::unblock(Address addr)
789 m_block_map.erase(addr);
790 if (m_block_map.size() == 0) {
791 m_is_blocking = false;
796 $c_ident::print(ostream& out) const
798 out << "[$c_ident " << m_version << "]";
802 $c_ident::printConfig(ostream& out) const
804 out << "$c_ident config: " << m_name << endl;
805 out << " version: " << m_version << endl;
806 map<string, string>::const_iterator it;
807 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
808 out << " " << it->first << ": " << it->second << endl;
812 $c_ident::printStats(ostream& out) const
816 # Cache and Memory Controllers have specific profilers associated with
817 # them. Print out these stats before dumping state transition stats.
819 for param
in self
.config_parameters
:
820 if param
.type_ast
.type.ident
== "CacheMemory" or \
821 param
.type_ast
.type.ident
== "DirectoryMemory" or \
822 param
.type_ast
.type.ident
== "MemoryControl":
823 assert(param
.pointer
)
824 code(' m_${{param.ident}}_ptr->printStats(out);')
827 if (m_version == 0) {
828 s_profileDumper.dumpStats(out);
832 void $c_ident::clearStats() {
835 # Cache and Memory Controllers have specific profilers associated with
836 # them. These stats must be cleared too.
838 for param
in self
.config_parameters
:
839 if param
.type_ast
.type.ident
== "CacheMemory" or \
840 param
.type_ast
.type.ident
== "MemoryControl":
841 assert(param
.pointer
)
842 code(' m_${{param.ident}}_ptr->clearStats();')
845 m_profiler.clearStats();
849 if self
.EntryType
!= None:
852 // Set and Reset for cache_entry variable
854 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
856 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
860 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
862 m_cache_entry_ptr = 0;
866 $c_ident::set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
867 AccessPermission perm)
869 if (m_cache_entry_ptr != NULL) {
870 m_cache_entry_ptr->changePermission(perm);
875 if self
.TBEType
!= None:
878 // Set and Reset for tbe variable
880 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
882 m_tbe_ptr = m_new_tbe;
886 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
896 if self
.TBEType
!= None and self
.EntryType
!= None:
897 for action
in self
.actions
.itervalues():
898 if "c_code" not in action
:
902 /** \\brief ${{action.desc}} */
904 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
906 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
907 ${{action["c_code"]}}
911 elif self
.TBEType
!= None:
912 for action
in self
.actions
.itervalues():
913 if "c_code" not in action
:
917 /** \\brief ${{action.desc}} */
919 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
921 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
922 ${{action["c_code"]}}
926 elif self
.EntryType
!= None:
927 for action
in self
.actions
.itervalues():
928 if "c_code" not in action
:
932 /** \\brief ${{action.desc}} */
934 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
936 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
937 ${{action["c_code"]}}
942 for action
in self
.actions
.itervalues():
943 if "c_code" not in action
:
947 /** \\brief ${{action.desc}} */
949 $c_ident::${{action.ident}}(const Address& addr)
951 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
952 ${{action["c_code"]}}
956 code
.write(path
, "%s.cc" % c_ident
)
958 def printCWakeup(self
, path
):
959 '''Output the wakeup loop for the events'''
961 code
= self
.symtab
.codeFormatter()
965 // Auto generated C++ code started by $__file__:$__line__
966 // ${ident}: ${{self.short}}
970 #include "base/misc.hh"
971 #include "mem/protocol/${ident}_Controller.hh"
972 #include "mem/protocol/${ident}_Event.hh"
973 #include "mem/protocol/${ident}_State.hh"
974 #include "mem/protocol/Types.hh"
975 #include "mem/ruby/common/Global.hh"
976 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
977 #include "mem/ruby/system/System.hh"
982 ${ident}_Controller::wakeup()
986 // Some cases will put us into an infinite loop without this limit
987 assert(counter <= m_transitions_per_cycle);
988 if (counter == m_transitions_per_cycle) {
989 // Count how often we are fully utilized
990 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
992 // Wakeup in another cycle and try again
993 g_eventQueue_ptr->scheduleEvent(this, 1);
1003 for port
in self
.in_ports
:
1005 code('// ${ident}InPort $port')
1006 if port
.pairs
.has_key("rank"):
1007 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1009 code('m_cur_in_port_rank = 0;')
1010 code('${{port["c_code_in_port"]}}')
1018 break; // If we got this far, we have nothing left todo
1020 // g_eventQueue_ptr->scheduleEvent(this, 1);
1024 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1026 def printCSwitch(self
, path
):
1027 '''Output switch statement for transition table'''
1029 code
= self
.symtab
.codeFormatter()
1033 // Auto generated C++ code started by $__file__:$__line__
1034 // ${ident}: ${{self.short}}
1038 #include "base/misc.hh"
1039 #include "base/trace.hh"
1040 #include "mem/protocol/${ident}_Controller.hh"
1041 #include "mem/protocol/${ident}_Event.hh"
1042 #include "mem/protocol/${ident}_State.hh"
1043 #include "mem/protocol/Types.hh"
1044 #include "mem/ruby/common/Global.hh"
1045 #include "mem/ruby/system/System.hh"
1047 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1049 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1050 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1053 ${ident}_Controller::doTransition(${ident}_Event event,
1055 if self
.EntryType
!= None:
1057 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1059 if self
.TBEType
!= None:
1061 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1064 const Address &addr)
1067 if self
.TBEType
!= None and self
.EntryType
!= None:
1068 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1069 elif self
.TBEType
!= None:
1070 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);')
1071 elif self
.EntryType
!= None:
1072 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);')
1074 code('${ident}_State state = ${ident}_getState(addr);')
1077 ${ident}_State next_state = state;
1079 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1081 g_eventQueue_ptr->getTime(),
1082 ${ident}_State_to_string(state),
1083 ${ident}_Event_to_string(event),
1086 TransitionResult result =
1088 if self
.TBEType
!= None and self
.EntryType
!= None:
1089 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1090 elif self
.TBEType
!= None:
1091 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1092 elif self
.EntryType
!= None:
1093 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1095 code('doTransitionWorker(event, state, next_state, addr);')
1098 if (result == TransitionResult_Valid) {
1099 DPRINTF(RubyGenerated, "next_state: %s\\n",
1100 ${ident}_State_to_string(next_state));
1101 m_profiler.countTransition(state, event);
1102 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n",
1103 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1104 ${ident}_Event_to_string(event),
1105 ${ident}_State_to_string(state),
1106 ${ident}_State_to_string(next_state),
1107 addr, GET_TRANSITION_COMMENT());
1109 CLEAR_TRANSITION_COMMENT();
1111 if self
.TBEType
!= None and self
.EntryType
!= None:
1112 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1113 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));')
1114 elif self
.TBEType
!= None:
1115 code('${ident}_setState(m_tbe_ptr, addr, next_state);')
1116 elif self
.EntryType
!= None:
1117 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);')
1118 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));')
1120 code('${ident}_setState(addr, next_state);')
1123 } else if (result == TransitionResult_ResourceStall) {
1124 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1125 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1126 ${ident}_Event_to_string(event),
1127 ${ident}_State_to_string(state),
1128 ${ident}_State_to_string(next_state),
1129 addr, "Resource Stall");
1130 } else if (result == TransitionResult_ProtocolStall) {
1131 DPRINTF(RubyGenerated, "stalling\\n");
1132 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1133 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1134 ${ident}_Event_to_string(event),
1135 ${ident}_State_to_string(state),
1136 ${ident}_State_to_string(next_state),
1137 addr, "Protocol Stall");
1144 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1145 ${ident}_State state,
1146 ${ident}_State& next_state,
1149 if self
.TBEType
!= None:
1151 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1153 if self
.EntryType
!= None:
1155 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1158 const Address& addr)
1160 switch(HASH_FUN(state, event)) {
1163 # This map will allow suppress generating duplicate code
1166 for trans
in self
.transitions
:
1167 case_string
= "%s_State_%s, %s_Event_%s" % \
1168 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1170 case
= self
.symtab
.codeFormatter()
1171 # Only set next_state if it changes
1172 if trans
.state
!= trans
.nextState
:
1173 ns_ident
= trans
.nextState
.ident
1174 case('next_state = ${ident}_State_${ns_ident};')
1176 actions
= trans
.actions
1178 # Check for resources
1180 res
= trans
.resources
1181 for key
,val
in res
.iteritems():
1182 if key
.type.ident
!= "DNUCAStopTable":
1184 if (!%s.areNSlotsAvailable(%s))
1185 return TransitionResult_ResourceStall;
1186 ''' % (key
.code
, val
)
1187 case_sorter
.append(val
)
1190 # Emit the code sequences in a sorted order. This makes the
1191 # output deterministic (without this the output order can vary
1192 # since Map's keys() on a vector of pointers is not deterministic
1193 for c
in sorted(case_sorter
):
1196 # Figure out if we stall
1198 for action
in actions
:
1199 if action
.ident
== "z_stall":
1204 case('return TransitionResult_ProtocolStall;')
1206 if self
.TBEType
!= None and self
.EntryType
!= None:
1207 for action
in actions
:
1208 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1209 elif self
.TBEType
!= None:
1210 for action
in actions
:
1211 case('${{action.ident}}(m_tbe_ptr, addr);')
1212 elif self
.EntryType
!= None:
1213 for action
in actions
:
1214 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1216 for action
in actions
:
1217 case('${{action.ident}}(addr);')
1218 case('return TransitionResult_Valid;')
1222 # Look to see if this transition code is unique.
1223 if case
not in cases
:
1226 cases
[case
].append(case_string
)
1228 # Walk through all of the unique code blocks and spit out the
1229 # corresponding case statement elements
1230 for case
,transitions
in cases
.iteritems():
1231 # Iterative over all the multiple transitions that share
1233 for trans
in transitions
:
1234 code(' case HASH_FUN($trans):')
1239 fatal("Invalid transition\\n"
1240 "%s time: %d addr: %s event: %s state: %s\\n",
1241 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1243 return TransitionResult_Valid;
1246 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1248 def printProfileDumperHH(self
, path
):
1249 code
= self
.symtab
.codeFormatter()
1253 // Auto generated C++ code started by $__file__:$__line__
1254 // ${ident}: ${{self.short}}
1256 #ifndef __${ident}_PROFILE_DUMPER_HH__
1257 #define __${ident}_PROFILE_DUMPER_HH__
1263 #include "${ident}_Event.hh"
1264 #include "${ident}_Profiler.hh"
1266 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1268 class ${ident}_ProfileDumper
1271 ${ident}_ProfileDumper();
1272 void registerProfiler(${ident}_Profiler* profiler);
1273 void dumpStats(std::ostream& out) const;
1276 ${ident}_profilers m_profilers;
1279 #endif // __${ident}_PROFILE_DUMPER_HH__
1281 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1283 def printProfileDumperCC(self
, path
):
1284 code
= self
.symtab
.codeFormatter()
1288 // Auto generated C++ code started by $__file__:$__line__
1289 // ${ident}: ${{self.short}}
1291 #include "mem/protocol/${ident}_ProfileDumper.hh"
1293 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1298 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1300 m_profilers.push_back(profiler);
1304 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1306 out << " --- ${ident} ---\\n";
1307 out << " - Event Counts -\\n";
1308 for (${ident}_Event event = ${ident}_Event_FIRST;
1309 event < ${ident}_Event_NUM;
1311 out << (${ident}_Event) event << " [";
1313 for (int i = 0; i < m_profilers.size(); i++) {
1314 out << m_profilers[i]->getEventCount(event) << " ";
1315 total += m_profilers[i]->getEventCount(event);
1317 out << "] " << total << "\\n";
1320 out << " - Transitions -\\n";
1321 for (${ident}_State state = ${ident}_State_FIRST;
1322 state < ${ident}_State_NUM;
1324 for (${ident}_Event event = ${ident}_Event_FIRST;
1325 event < ${ident}_Event_NUM;
1327 if (m_profilers[0]->isPossible(state, event)) {
1328 out << (${ident}_State) state << " "
1329 << (${ident}_Event) event << " [";
1331 for (int i = 0; i < m_profilers.size(); i++) {
1332 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1333 total += m_profilers[i]->getTransitionCount(state, event);
1335 out << "] " << total << "\\n";
1342 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1344 def printProfilerHH(self
, path
):
1345 code
= self
.symtab
.codeFormatter()
1349 // Auto generated C++ code started by $__file__:$__line__
1350 // ${ident}: ${{self.short}}
1352 #ifndef __${ident}_PROFILER_HH__
1353 #define __${ident}_PROFILER_HH__
1358 #include "mem/protocol/${ident}_Event.hh"
1359 #include "mem/protocol/${ident}_State.hh"
1360 #include "mem/ruby/common/Global.hh"
1362 class ${ident}_Profiler
1365 ${ident}_Profiler();
1366 void setVersion(int version);
1367 void countTransition(${ident}_State state, ${ident}_Event event);
1368 void possibleTransition(${ident}_State state, ${ident}_Event event);
1369 uint64 getEventCount(${ident}_Event event);
1370 bool isPossible(${ident}_State state, ${ident}_Event event);
1371 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1375 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1376 int m_event_counters[${ident}_Event_NUM];
1377 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1381 #endif // __${ident}_PROFILER_HH__
1383 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1385 def printProfilerCC(self
, path
):
1386 code
= self
.symtab
.codeFormatter()
1390 // Auto generated C++ code started by $__file__:$__line__
1391 // ${ident}: ${{self.short}}
1395 #include "mem/protocol/${ident}_Profiler.hh"
1397 ${ident}_Profiler::${ident}_Profiler()
1399 for (int state = 0; state < ${ident}_State_NUM; state++) {
1400 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1401 m_possible[state][event] = false;
1402 m_counters[state][event] = 0;
1405 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1406 m_event_counters[event] = 0;
1411 ${ident}_Profiler::setVersion(int version)
1413 m_version = version;
1417 ${ident}_Profiler::clearStats()
1419 for (int state = 0; state < ${ident}_State_NUM; state++) {
1420 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1421 m_counters[state][event] = 0;
1425 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1426 m_event_counters[event] = 0;
1430 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1432 assert(m_possible[state][event]);
1433 m_counters[state][event]++;
1434 m_event_counters[event]++;
1437 ${ident}_Profiler::possibleTransition(${ident}_State state,
1438 ${ident}_Event event)
1440 m_possible[state][event] = true;
1444 ${ident}_Profiler::getEventCount(${ident}_Event event)
1446 return m_event_counters[event];
1450 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1452 return m_possible[state][event];
1456 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1457 ${ident}_Event event)
1459 return m_counters[state][event];
1463 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1465 # **************************
1466 # ******* HTML Files *******
1467 # **************************
1468 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1469 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1470 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1471 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1472 parent.frames[$over_num].location='$over_href'
1474 ${{html.formatShorthand(text)}}
1478 def writeHTMLFiles(self
, path
):
1479 # Create table with no row hilighted
1480 self
.printHTMLTransitions(path
, None)
1482 # Generate transition tables
1483 for state
in self
.states
.itervalues():
1484 self
.printHTMLTransitions(path
, state
)
1486 # Generate action descriptions
1487 for action
in self
.actions
.itervalues():
1488 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1489 code
= html
.createSymbol(action
, "Action")
1490 code
.write(path
, name
)
1492 # Generate state descriptions
1493 for state
in self
.states
.itervalues():
1494 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1495 code
= html
.createSymbol(state
, "State")
1496 code
.write(path
, name
)
1498 # Generate event descriptions
1499 for event
in self
.events
.itervalues():
1500 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1501 code
= html
.createSymbol(event
, "Event")
1502 code
.write(path
, name
)
1504 def printHTMLTransitions(self
, path
, active_state
):
1505 code
= self
.symtab
.codeFormatter()
1509 <BODY link="blue" vlink="blue">
1511 <H1 align="center">${{html.formatShorthand(self.short)}}:
1514 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1523 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1534 for event
in self
.events
.itervalues():
1535 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1536 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1537 code('<TH bgcolor=white>$ref</TH>')
1541 for state
in self
.states
.itervalues():
1543 if state
== active_state
:
1548 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1549 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1550 text
= html
.formatShorthand(state
.short
)
1551 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1554 <TH bgcolor=$color>$ref</TH>
1557 # -- One column for each event
1558 for event
in self
.events
.itervalues():
1559 trans
= self
.table
.get((state
,event
), None)
1561 # This is the no transition case
1562 if state
== active_state
:
1567 code('<TD bgcolor=$color> </TD>')
1570 next
= trans
.nextState
1571 stall_action
= False
1573 # -- Get the actions
1574 for action
in trans
.actions
:
1575 if action
.ident
== "z_stall" or \
1576 action
.ident
== "zz_recycleMandatoryQueue":
1579 # -- Print out "actions/next-state"
1581 if state
== active_state
:
1586 elif active_state
and next
.ident
== active_state
.ident
:
1588 elif state
== active_state
:
1593 code('<TD bgcolor=$color>')
1594 for action
in trans
.actions
:
1595 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1596 ref
= self
.frameRef(href
, "Status", href
, "1",
1602 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1603 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1604 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1609 if state
== active_state
:
1614 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1615 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1616 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1618 <TH bgcolor=$color>$ref</TH>
1627 for event
in self
.events
.itervalues():
1628 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1629 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1630 code('<TH bgcolor=white>$ref</TH>')
1639 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1641 name
= "%s_table.html" % self
.ident
1642 code
.write(path
, name
)
1644 __all__
= [ "StateMachine" ]