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 "debug/RubyGenerated.hh"
421 #include "debug/RubySlicc.hh"
422 #include "mem/protocol/${ident}_Controller.hh"
423 #include "mem/protocol/${ident}_Event.hh"
424 #include "mem/protocol/${ident}_State.hh"
425 #include "mem/protocol/Types.hh"
426 #include "mem/ruby/common/Global.hh"
427 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
428 #include "mem/ruby/system/System.hh"
433 # include object classes
435 for var
in self
.objects
:
436 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
437 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
438 seen_types
.add(var
.type.ident
)
442 ${c_ident}Params::create()
444 return new $c_ident(this);
447 int $c_ident::m_num_controllers = 0;
448 ${ident}_ProfileDumper $c_ident::s_profileDumper;
450 // for adding information to the protocol debug trace
451 stringstream ${ident}_transitionComment;
452 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
454 /** \\brief constructor */
455 $c_ident::$c_ident(const Params *p)
456 : AbstractController(p)
458 m_version = p->version;
459 m_transitions_per_cycle = p->transitions_per_cycle;
460 m_buffer_size = p->buffer_size;
461 m_recycle_latency = p->recycle_latency;
462 m_number_of_TBEs = p->number_of_TBEs;
463 m_is_blocking = false;
466 # max_port_rank is used to size vectors and thus should be one plus the
469 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
470 code(' m_max_in_port_rank = $max_port_rank;')
474 # After initializing the universal machine parameters, initialize the
475 # this machines config parameters. Also detemine if these configuration
476 # params include a sequencer. This information will be used later for
477 # contecting the sequencer back to the L1 cache controller.
479 contains_dma_sequencer
= False
481 for param
in self
.config_parameters
:
482 if param
.name
== "dma_sequencer":
483 contains_dma_sequencer
= True
484 elif re
.compile("sequencer").search(param
.name
):
485 sequencers
.append(param
.name
)
487 code('m_${{param.name}}_ptr = p->${{param.name}};')
489 code('m_${{param.name}} = p->${{param.name}};')
492 # For the l1 cache controller, add the special atomic support which
493 # includes passing the sequencer a pointer to the controller.
495 if self
.ident
== "L1Cache":
497 self
.error("The L1Cache controller must include the sequencer " \
498 "configuration parameter")
500 for seq
in sequencers
:
502 m_${{seq}}_ptr->setController(this);
505 # For the DMA controller, pass the sequencer a pointer to the
508 if self
.ident
== "DMA":
509 if not contains_dma_sequencer
:
510 self
.error("The DMA controller must include the sequencer " \
511 "configuration parameter")
514 m_dma_sequencer_ptr->setController(this);
517 code('m_num_controllers++;')
518 for var
in self
.objects
:
519 if var
.ident
.find("mandatoryQueue") >= 0:
520 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
529 MachineType machine_type;
532 m_machineID.type = MachineType_${ident};
533 m_machineID.num = m_version;
535 // initialize objects
536 m_profiler.setVersion(m_version);
537 s_profileDumper.registerProfiler(&m_profiler);
542 for var
in self
.objects
:
544 vid
= "m_%s_ptr" % var
.c_ident
545 if "network" not in var
:
546 # Not a network port object
547 if "primitive" in vtype
:
548 code('$vid = new ${{vtype.c_ident}};')
550 code('(*$vid) = ${{var["default"]}};')
555 code('$vid = ${{var["factory"]}};')
556 elif var
.ident
.find("mandatoryQueue") < 0:
557 th
= var
.get("template_hack", "")
558 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
561 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
562 if expr
.find("TBETable") >= 0:
563 args
= "m_number_of_TBEs"
565 args
= var
.get("constructor_hack", "")
567 code('$expr($args);')
569 code('assert($vid != NULL);')
572 code('*$vid = ${{var["default"]}}; // Object default')
573 elif "default" in vtype
:
574 comment
= "Type %s default" % vtype
.ident
575 code('*$vid = ${{vtype["default"]}}; // $comment')
578 if "ordered" in var
and "trigger_queue" not in var
:
580 code('$vid->setOrdering(${{var["ordered"]}});')
585 code('$vid->setRandomization(${{var["random"]}});')
588 if vtype
.isBuffer
and \
589 "rank" in var
and "trigger_queue" not in var
:
590 code('$vid->setPriority(${{var["rank"]}});')
593 # Network port object
594 network
= var
["network"]
595 ordered
= var
["ordered"]
596 vnet
= var
["virtual_network"]
598 assert var
.machine
is not None
600 machine_type = string_to_MachineType("${{var.machine.ident}}");
601 base = MachineType_base_number(machine_type);
602 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
605 code('assert($vid != NULL);')
610 code('$vid->setOrdering(${{var["ordered"]}});')
615 code('$vid->setRandomization(${{var["random"]}});')
619 code('$vid->setPriority(${{var["rank"]}})')
624 if (m_buffer_size > 0) {
625 $vid->resize(m_buffer_size);
629 # set description (may be overriden later by port def)
631 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
636 if "recycle_latency" in var
:
637 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
639 code('$vid->setRecycleLatency(m_recycle_latency);')
642 # Set the queue consumers
644 for port
in self
.in_ports
:
645 code('${{port.code}}.setConsumer(this);')
647 # Set the queue descriptions
649 for port
in self
.in_ports
:
650 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
652 # Initialize the transition profiling
654 for trans
in self
.transitions
:
655 # Figure out if we stall
657 for action
in trans
.actions
:
658 if action
.ident
== "z_stall":
661 # Only possible if it is not a 'z' case
663 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
664 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
665 code('m_profiler.possibleTransition($state, $event);')
670 has_mandatory_q
= False
671 for port
in self
.in_ports
:
672 if port
.code
.find("mandatoryQueue_ptr") >= 0:
673 has_mandatory_q
= True
676 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
682 $c_ident::getNumControllers()
684 return m_num_controllers;
688 $c_ident::getMandatoryQueue() const
694 $c_ident::getVersion() const
700 $c_ident::toString() const
706 $c_ident::getName() const
712 $c_ident::getMachineType() const
714 return MachineType_${ident};
718 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
720 if (m_waiting_buffers.count(addr) == 0) {
721 MsgVecType* msgVec = new MsgVecType;
722 msgVec->resize(m_max_in_port_rank, NULL);
723 m_waiting_buffers[addr] = msgVec;
725 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
729 $c_ident::wakeUpBuffers(Address addr)
731 if (m_waiting_buffers.count(addr) > 0) {
733 // Wake up all possible lower rank (i.e. lower priority) buffers that could
734 // be waiting on this message.
736 for (int in_port_rank = m_cur_in_port_rank - 1;
739 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
740 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
743 delete m_waiting_buffers[addr];
744 m_waiting_buffers.erase(addr);
749 $c_ident::wakeUpAllBuffers()
752 // Wake up all possible buffers that could be waiting on any message.
755 std::vector<MsgVecType*> wokeUpMsgVecs;
757 if(m_waiting_buffers.size() > 0) {
758 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
759 buf_iter != m_waiting_buffers.end();
761 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
762 vec_iter != buf_iter->second->end();
764 if (*vec_iter != NULL) {
765 (*vec_iter)->reanalyzeAllMessages();
768 wokeUpMsgVecs.push_back(buf_iter->second);
771 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
772 wb_iter != wokeUpMsgVecs.end();
777 m_waiting_buffers.clear();
782 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
784 m_is_blocking = true;
785 m_block_map[addr] = port;
789 $c_ident::unblock(Address addr)
791 m_block_map.erase(addr);
792 if (m_block_map.size() == 0) {
793 m_is_blocking = false;
798 $c_ident::print(ostream& out) const
800 out << "[$c_ident " << m_version << "]";
804 $c_ident::printConfig(ostream& out) const
806 out << "$c_ident config: " << m_name << endl;
807 out << " version: " << m_version << endl;
808 map<string, string>::const_iterator it;
809 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
810 out << " " << it->first << ": " << it->second << endl;
814 $c_ident::printStats(ostream& out) const
818 # Cache and Memory Controllers have specific profilers associated with
819 # them. Print out these stats before dumping state transition stats.
821 for param
in self
.config_parameters
:
822 if param
.type_ast
.type.ident
== "CacheMemory" or \
823 param
.type_ast
.type.ident
== "DirectoryMemory" or \
824 param
.type_ast
.type.ident
== "MemoryControl":
825 assert(param
.pointer
)
826 code(' m_${{param.ident}}_ptr->printStats(out);')
829 if (m_version == 0) {
830 s_profileDumper.dumpStats(out);
834 void $c_ident::clearStats() {
837 # Cache and Memory Controllers have specific profilers associated with
838 # them. These stats must be cleared too.
840 for param
in self
.config_parameters
:
841 if param
.type_ast
.type.ident
== "CacheMemory" or \
842 param
.type_ast
.type.ident
== "MemoryControl":
843 assert(param
.pointer
)
844 code(' m_${{param.ident}}_ptr->clearStats();')
847 m_profiler.clearStats();
851 if self
.EntryType
!= None:
854 // Set and Reset for cache_entry variable
856 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
858 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
862 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
864 m_cache_entry_ptr = 0;
868 $c_ident::set_permission(${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
869 AccessPermission perm)
871 if (m_cache_entry_ptr != NULL) {
872 m_cache_entry_ptr->changePermission(perm);
877 if self
.TBEType
!= None:
880 // Set and Reset for tbe variable
882 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
884 m_tbe_ptr = m_new_tbe;
888 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
898 if self
.TBEType
!= None and self
.EntryType
!= None:
899 for action
in self
.actions
.itervalues():
900 if "c_code" not in action
:
904 /** \\brief ${{action.desc}} */
906 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
908 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
909 ${{action["c_code"]}}
913 elif self
.TBEType
!= None:
914 for action
in self
.actions
.itervalues():
915 if "c_code" not in action
:
919 /** \\brief ${{action.desc}} */
921 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
923 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
924 ${{action["c_code"]}}
928 elif self
.EntryType
!= None:
929 for action
in self
.actions
.itervalues():
930 if "c_code" not in action
:
934 /** \\brief ${{action.desc}} */
936 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
938 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
939 ${{action["c_code"]}}
944 for action
in self
.actions
.itervalues():
945 if "c_code" not in action
:
949 /** \\brief ${{action.desc}} */
951 $c_ident::${{action.ident}}(const Address& addr)
953 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
954 ${{action["c_code"]}}
958 code
.write(path
, "%s.cc" % c_ident
)
960 def printCWakeup(self
, path
):
961 '''Output the wakeup loop for the events'''
963 code
= self
.symtab
.codeFormatter()
967 // Auto generated C++ code started by $__file__:$__line__
968 // ${ident}: ${{self.short}}
972 #include "base/misc.hh"
973 #include "debug/RubySlicc.hh"
974 #include "mem/protocol/${ident}_Controller.hh"
975 #include "mem/protocol/${ident}_Event.hh"
976 #include "mem/protocol/${ident}_State.hh"
977 #include "mem/protocol/Types.hh"
978 #include "mem/ruby/common/Global.hh"
979 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
980 #include "mem/ruby/system/System.hh"
985 ${ident}_Controller::wakeup()
989 // Some cases will put us into an infinite loop without this limit
990 assert(counter <= m_transitions_per_cycle);
991 if (counter == m_transitions_per_cycle) {
992 // Count how often we are fully utilized
993 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
995 // Wakeup in another cycle and try again
996 g_eventQueue_ptr->scheduleEvent(this, 1);
1006 for port
in self
.in_ports
:
1008 code('// ${ident}InPort $port')
1009 if port
.pairs
.has_key("rank"):
1010 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1012 code('m_cur_in_port_rank = 0;')
1013 code('${{port["c_code_in_port"]}}')
1021 break; // If we got this far, we have nothing left todo
1023 // g_eventQueue_ptr->scheduleEvent(this, 1);
1027 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1029 def printCSwitch(self
, path
):
1030 '''Output switch statement for transition table'''
1032 code
= self
.symtab
.codeFormatter()
1036 // Auto generated C++ code started by $__file__:$__line__
1037 // ${ident}: ${{self.short}}
1041 #include "base/misc.hh"
1042 #include "base/trace.hh"
1043 #include "debug/ProtocolTrace.hh"
1044 #include "debug/RubyGenerated.hh"
1045 #include "mem/protocol/${ident}_Controller.hh"
1046 #include "mem/protocol/${ident}_Event.hh"
1047 #include "mem/protocol/${ident}_State.hh"
1048 #include "mem/protocol/Types.hh"
1049 #include "mem/ruby/common/Global.hh"
1050 #include "mem/ruby/system/System.hh"
1052 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1054 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1055 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1058 ${ident}_Controller::doTransition(${ident}_Event event,
1060 if self
.EntryType
!= None:
1062 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1064 if self
.TBEType
!= None:
1066 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1069 const Address &addr)
1072 if self
.TBEType
!= None and self
.EntryType
!= None:
1073 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1074 elif self
.TBEType
!= None:
1075 code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);')
1076 elif self
.EntryType
!= None:
1077 code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);')
1079 code('${ident}_State state = ${ident}_getState(addr);')
1082 ${ident}_State next_state = state;
1084 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1086 g_eventQueue_ptr->getTime(),
1087 ${ident}_State_to_string(state),
1088 ${ident}_Event_to_string(event),
1091 TransitionResult result =
1093 if self
.TBEType
!= None and self
.EntryType
!= None:
1094 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1095 elif self
.TBEType
!= None:
1096 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1097 elif self
.EntryType
!= None:
1098 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1100 code('doTransitionWorker(event, state, next_state, addr);')
1103 if (result == TransitionResult_Valid) {
1104 DPRINTF(RubyGenerated, "next_state: %s\\n",
1105 ${ident}_State_to_string(next_state));
1106 m_profiler.countTransition(state, event);
1107 DPRINTFR(ProtocolTrace, "%7d %3s %10s%20s %6s>%-6s %s %s\\n",
1108 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1109 ${ident}_Event_to_string(event),
1110 ${ident}_State_to_string(state),
1111 ${ident}_State_to_string(next_state),
1112 addr, GET_TRANSITION_COMMENT());
1114 CLEAR_TRANSITION_COMMENT();
1116 if self
.TBEType
!= None and self
.EntryType
!= None:
1117 code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1118 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));')
1119 elif self
.TBEType
!= None:
1120 code('${ident}_setState(m_tbe_ptr, addr, next_state);')
1121 elif self
.EntryType
!= None:
1122 code('${ident}_setState(m_cache_entry_ptr, addr, next_state);')
1123 code('set_permission(m_cache_entry_ptr, ${ident}_State_to_permission(next_state));')
1125 code('${ident}_setState(addr, next_state);')
1128 } else if (result == TransitionResult_ResourceStall) {
1129 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1130 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1131 ${ident}_Event_to_string(event),
1132 ${ident}_State_to_string(state),
1133 ${ident}_State_to_string(next_state),
1134 addr, "Resource Stall");
1135 } else if (result == TransitionResult_ProtocolStall) {
1136 DPRINTF(RubyGenerated, "stalling\\n");
1137 DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n",
1138 g_eventQueue_ptr->getTime(), m_version, "${ident}",
1139 ${ident}_Event_to_string(event),
1140 ${ident}_State_to_string(state),
1141 ${ident}_State_to_string(next_state),
1142 addr, "Protocol Stall");
1149 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1150 ${ident}_State state,
1151 ${ident}_State& next_state,
1154 if self
.TBEType
!= None:
1156 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1158 if self
.EntryType
!= None:
1160 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1163 const Address& addr)
1165 switch(HASH_FUN(state, event)) {
1168 # This map will allow suppress generating duplicate code
1171 for trans
in self
.transitions
:
1172 case_string
= "%s_State_%s, %s_Event_%s" % \
1173 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1175 case
= self
.symtab
.codeFormatter()
1176 # Only set next_state if it changes
1177 if trans
.state
!= trans
.nextState
:
1178 ns_ident
= trans
.nextState
.ident
1179 case('next_state = ${ident}_State_${ns_ident};')
1181 actions
= trans
.actions
1183 # Check for resources
1185 res
= trans
.resources
1186 for key
,val
in res
.iteritems():
1187 if key
.type.ident
!= "DNUCAStopTable":
1189 if (!%s.areNSlotsAvailable(%s))
1190 return TransitionResult_ResourceStall;
1191 ''' % (key
.code
, val
)
1192 case_sorter
.append(val
)
1195 # Emit the code sequences in a sorted order. This makes the
1196 # output deterministic (without this the output order can vary
1197 # since Map's keys() on a vector of pointers is not deterministic
1198 for c
in sorted(case_sorter
):
1201 # Figure out if we stall
1203 for action
in actions
:
1204 if action
.ident
== "z_stall":
1209 case('return TransitionResult_ProtocolStall;')
1211 if self
.TBEType
!= None and self
.EntryType
!= None:
1212 for action
in actions
:
1213 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1214 elif self
.TBEType
!= None:
1215 for action
in actions
:
1216 case('${{action.ident}}(m_tbe_ptr, addr);')
1217 elif self
.EntryType
!= None:
1218 for action
in actions
:
1219 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1221 for action
in actions
:
1222 case('${{action.ident}}(addr);')
1223 case('return TransitionResult_Valid;')
1227 # Look to see if this transition code is unique.
1228 if case
not in cases
:
1231 cases
[case
].append(case_string
)
1233 # Walk through all of the unique code blocks and spit out the
1234 # corresponding case statement elements
1235 for case
,transitions
in cases
.iteritems():
1236 # Iterative over all the multiple transitions that share
1238 for trans
in transitions
:
1239 code(' case HASH_FUN($trans):')
1244 fatal("Invalid transition\\n"
1245 "%s time: %d addr: %s event: %s state: %s\\n",
1246 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1248 return TransitionResult_Valid;
1251 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1253 def printProfileDumperHH(self
, path
):
1254 code
= self
.symtab
.codeFormatter()
1258 // Auto generated C++ code started by $__file__:$__line__
1259 // ${ident}: ${{self.short}}
1261 #ifndef __${ident}_PROFILE_DUMPER_HH__
1262 #define __${ident}_PROFILE_DUMPER_HH__
1268 #include "${ident}_Event.hh"
1269 #include "${ident}_Profiler.hh"
1271 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1273 class ${ident}_ProfileDumper
1276 ${ident}_ProfileDumper();
1277 void registerProfiler(${ident}_Profiler* profiler);
1278 void dumpStats(std::ostream& out) const;
1281 ${ident}_profilers m_profilers;
1284 #endif // __${ident}_PROFILE_DUMPER_HH__
1286 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1288 def printProfileDumperCC(self
, path
):
1289 code
= self
.symtab
.codeFormatter()
1293 // Auto generated C++ code started by $__file__:$__line__
1294 // ${ident}: ${{self.short}}
1296 #include "mem/protocol/${ident}_ProfileDumper.hh"
1298 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1303 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1305 m_profilers.push_back(profiler);
1309 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1311 out << " --- ${ident} ---\\n";
1312 out << " - Event Counts -\\n";
1313 for (${ident}_Event event = ${ident}_Event_FIRST;
1314 event < ${ident}_Event_NUM;
1316 out << (${ident}_Event) event << " [";
1318 for (int i = 0; i < m_profilers.size(); i++) {
1319 out << m_profilers[i]->getEventCount(event) << " ";
1320 total += m_profilers[i]->getEventCount(event);
1322 out << "] " << total << "\\n";
1325 out << " - Transitions -\\n";
1326 for (${ident}_State state = ${ident}_State_FIRST;
1327 state < ${ident}_State_NUM;
1329 for (${ident}_Event event = ${ident}_Event_FIRST;
1330 event < ${ident}_Event_NUM;
1332 if (m_profilers[0]->isPossible(state, event)) {
1333 out << (${ident}_State) state << " "
1334 << (${ident}_Event) event << " [";
1336 for (int i = 0; i < m_profilers.size(); i++) {
1337 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1338 total += m_profilers[i]->getTransitionCount(state, event);
1340 out << "] " << total << "\\n";
1347 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1349 def printProfilerHH(self
, path
):
1350 code
= self
.symtab
.codeFormatter()
1354 // Auto generated C++ code started by $__file__:$__line__
1355 // ${ident}: ${{self.short}}
1357 #ifndef __${ident}_PROFILER_HH__
1358 #define __${ident}_PROFILER_HH__
1363 #include "mem/protocol/${ident}_Event.hh"
1364 #include "mem/protocol/${ident}_State.hh"
1365 #include "mem/ruby/common/Global.hh"
1367 class ${ident}_Profiler
1370 ${ident}_Profiler();
1371 void setVersion(int version);
1372 void countTransition(${ident}_State state, ${ident}_Event event);
1373 void possibleTransition(${ident}_State state, ${ident}_Event event);
1374 uint64 getEventCount(${ident}_Event event);
1375 bool isPossible(${ident}_State state, ${ident}_Event event);
1376 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1380 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1381 int m_event_counters[${ident}_Event_NUM];
1382 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1386 #endif // __${ident}_PROFILER_HH__
1388 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1390 def printProfilerCC(self
, path
):
1391 code
= self
.symtab
.codeFormatter()
1395 // Auto generated C++ code started by $__file__:$__line__
1396 // ${ident}: ${{self.short}}
1400 #include "mem/protocol/${ident}_Profiler.hh"
1402 ${ident}_Profiler::${ident}_Profiler()
1404 for (int state = 0; state < ${ident}_State_NUM; state++) {
1405 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1406 m_possible[state][event] = false;
1407 m_counters[state][event] = 0;
1410 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1411 m_event_counters[event] = 0;
1416 ${ident}_Profiler::setVersion(int version)
1418 m_version = version;
1422 ${ident}_Profiler::clearStats()
1424 for (int state = 0; state < ${ident}_State_NUM; state++) {
1425 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1426 m_counters[state][event] = 0;
1430 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1431 m_event_counters[event] = 0;
1435 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1437 assert(m_possible[state][event]);
1438 m_counters[state][event]++;
1439 m_event_counters[event]++;
1442 ${ident}_Profiler::possibleTransition(${ident}_State state,
1443 ${ident}_Event event)
1445 m_possible[state][event] = true;
1449 ${ident}_Profiler::getEventCount(${ident}_Event event)
1451 return m_event_counters[event];
1455 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1457 return m_possible[state][event];
1461 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1462 ${ident}_Event event)
1464 return m_counters[state][event];
1468 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1470 # **************************
1471 # ******* HTML Files *******
1472 # **************************
1473 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1474 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1475 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1476 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1477 parent.frames[$over_num].location='$over_href'
1479 ${{html.formatShorthand(text)}}
1483 def writeHTMLFiles(self
, path
):
1484 # Create table with no row hilighted
1485 self
.printHTMLTransitions(path
, None)
1487 # Generate transition tables
1488 for state
in self
.states
.itervalues():
1489 self
.printHTMLTransitions(path
, state
)
1491 # Generate action descriptions
1492 for action
in self
.actions
.itervalues():
1493 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1494 code
= html
.createSymbol(action
, "Action")
1495 code
.write(path
, name
)
1497 # Generate state descriptions
1498 for state
in self
.states
.itervalues():
1499 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1500 code
= html
.createSymbol(state
, "State")
1501 code
.write(path
, name
)
1503 # Generate event descriptions
1504 for event
in self
.events
.itervalues():
1505 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1506 code
= html
.createSymbol(event
, "Event")
1507 code
.write(path
, name
)
1509 def printHTMLTransitions(self
, path
, active_state
):
1510 code
= self
.symtab
.codeFormatter()
1514 <BODY link="blue" vlink="blue">
1516 <H1 align="center">${{html.formatShorthand(self.short)}}:
1519 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1528 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1539 for event
in self
.events
.itervalues():
1540 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1541 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1542 code('<TH bgcolor=white>$ref</TH>')
1546 for state
in self
.states
.itervalues():
1548 if state
== active_state
:
1553 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1554 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1555 text
= html
.formatShorthand(state
.short
)
1556 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1559 <TH bgcolor=$color>$ref</TH>
1562 # -- One column for each event
1563 for event
in self
.events
.itervalues():
1564 trans
= self
.table
.get((state
,event
), None)
1566 # This is the no transition case
1567 if state
== active_state
:
1572 code('<TD bgcolor=$color> </TD>')
1575 next
= trans
.nextState
1576 stall_action
= False
1578 # -- Get the actions
1579 for action
in trans
.actions
:
1580 if action
.ident
== "z_stall" or \
1581 action
.ident
== "zz_recycleMandatoryQueue":
1584 # -- Print out "actions/next-state"
1586 if state
== active_state
:
1591 elif active_state
and next
.ident
== active_state
.ident
:
1593 elif state
== active_state
:
1598 code('<TD bgcolor=$color>')
1599 for action
in trans
.actions
:
1600 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1601 ref
= self
.frameRef(href
, "Status", href
, "1",
1607 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1608 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1609 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1614 if state
== active_state
:
1619 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1620 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1621 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1623 <TH bgcolor=$color>$ref</TH>
1632 for event
in self
.events
.itervalues():
1633 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1634 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1635 code('<TH bgcolor=white>$ref</TH>')
1644 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1646 name
= "%s_table.html" % self
.ident
1647 code
.write(path
, name
)
1649 __all__
= [ "StateMachine" ]