1 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2 # Copyright (c) 2009 The Hewlett-Packard Development Company
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 from m5
.util
import orderdict
30 from slicc
.symbols
.Symbol
import Symbol
31 from slicc
.symbols
.Var
import Var
32 import slicc
.generate
.html
as html
34 python_class_map
= {"int": "Int",
35 "std::string": "String",
37 "CacheMemory": "RubyCache",
38 "Sequencer": "RubySequencer",
39 "DirectoryMemory": "RubyDirectoryMemory",
40 "MemoryControl": "RubyMemoryControl",
41 "DMASequencer": "DMASequencer"
44 class StateMachine(Symbol
):
45 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
46 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
48 self
.config_parameters
= config_parameters
49 for param
in config_parameters
:
51 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
52 "(*m_%s_ptr)" % param
.name
, {}, self
)
54 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
55 "m_%s" % param
.name
, {}, self
)
56 self
.symtab
.registerSym(param
.name
, var
)
58 self
.states
= orderdict()
59 self
.events
= orderdict()
60 self
.actions
= orderdict()
66 self
.message_buffer_names
= []
69 return "[StateMachine: %s]" % self
.ident
71 def addState(self
, state
):
72 assert self
.table
is None
73 self
.states
[state
.ident
] = state
75 def addEvent(self
, event
):
76 assert self
.table
is None
77 self
.events
[event
.ident
] = event
79 def addAction(self
, action
):
80 assert self
.table
is None
82 # Check for duplicate action
83 for other
in self
.actions
.itervalues():
84 if action
.ident
== other
.ident
:
85 action
.warning("Duplicate action definition: %s" % action
.ident
)
86 action
.error("Duplicate action definition: %s" % action
.ident
)
87 if action
.short
== other
.short
:
88 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
89 other
.warning(" shorthand = %s" % other
.short
)
90 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
91 action
.error(" shorthand = %s" % action
.short
)
93 self
.actions
[action
.ident
] = action
95 def addTransition(self
, trans
):
96 assert self
.table
is None
97 self
.transitions
.append(trans
)
99 def addInPort(self
, var
):
100 self
.in_ports
.append(var
)
102 def addFunc(self
, func
):
103 # register func in the symbol table
104 self
.symtab
.registerSym(str(func
), func
)
105 self
.functions
.append(func
)
107 def addObject(self
, obj
):
108 self
.objects
.append(obj
)
110 # Needs to be called before accessing the table
111 def buildTable(self
):
112 assert self
.table
is None
116 for trans
in self
.transitions
:
117 # Track which actions we touch so we know if we use them
118 # all -- really this should be done for all symbols as
119 # part of the symbol table, then only trigger it for
120 # Actions, States, Events, etc.
122 for action
in trans
.actions
:
125 index
= (trans
.state
, trans
.event
)
127 table
[index
].warning("Duplicate transition: %s" % table
[index
])
128 trans
.error("Duplicate transition: %s" % trans
)
131 # Look at all actions to make sure we used them all
132 for action
in self
.actions
.itervalues():
134 error_msg
= "Unused action: %s" % action
.ident
136 error_msg
+= ", " + action
.desc
137 action
.warning(error_msg
)
140 def writeCodeFiles(self
, path
):
141 self
.printControllerPython(path
)
142 self
.printControllerHH(path
)
143 self
.printControllerCC(path
)
144 self
.printCSwitch(path
)
145 self
.printCWakeup(path
)
146 self
.printProfilerCC(path
)
147 self
.printProfilerHH(path
)
148 self
.printProfileDumperCC(path
)
149 self
.printProfileDumperHH(path
)
151 for func
in self
.functions
:
152 func
.writeCodeFiles(path
)
154 def printControllerPython(self
, path
):
155 code
= self
.symtab
.codeFormatter()
157 py_ident
= "%s_Controller" % ident
158 c_ident
= "%s_Controller" % self
.ident
160 from m5.params import *
161 from m5.SimObject import SimObject
162 from Controller import RubyController
164 class $py_ident(RubyController):
168 for param
in self
.config_parameters
:
170 if param
.default
is not None:
171 dflt_str
= str(param
.default
) + ', '
172 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
173 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
174 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
176 self
.error("Unknown c++ to python class conversion for c++ " \
177 "type: '%s'. Please update the python_class_map " \
178 "in StateMachine.py", param
.type_ast
.type.c_ident
)
180 code
.write(path
, '%s.py' % py_ident
)
183 def printControllerHH(self
, path
):
184 '''Output the method declarations for the class declaration'''
185 code
= self
.symtab
.codeFormatter()
187 c_ident
= "%s_Controller" % self
.ident
189 self
.message_buffer_names
= []
192 /** \\file $c_ident.hh
194 * Auto generated C++ code started by $__file__:$__line__
195 * Created by slicc definition of Module "${{self.short}}"
198 #ifndef __${ident}_CONTROLLER_HH__
199 #define __${ident}_CONTROLLER_HH__
205 #include "params/$c_ident.hh"
207 #include "mem/ruby/common/Global.hh"
208 #include "mem/ruby/common/Consumer.hh"
209 #include "mem/ruby/slicc_interface/AbstractController.hh"
210 #include "mem/protocol/TransitionResult.hh"
211 #include "mem/protocol/Types.hh"
212 #include "mem/protocol/${ident}_Profiler.hh"
213 #include "mem/protocol/${ident}_ProfileDumper.hh"
217 for var
in self
.objects
:
218 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
219 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
220 seen_types
.add(var
.type.ident
)
222 # for adding information to the protocol debug trace
224 extern std::stringstream ${ident}_transitionComment;
226 class $c_ident : public AbstractController
228 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
229 // making the Chip a friend class is an easy way to do this for now
232 typedef ${c_ident}Params Params;
233 $c_ident(const Params *p);
234 static int getNumControllers();
236 MessageBuffer* getMandatoryQueue() const;
237 const int & getVersion() const;
238 const std::string toString() const;
239 const std::string getName() const;
240 const MachineType getMachineType() const;
241 void stallBuffer(MessageBuffer* buf, Address addr);
242 void wakeUpBuffers(Address addr);
243 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
244 void print(std::ostream& out) const;
245 void printConfig(std::ostream& out) const;
247 void printStats(std::ostream& out) const;
249 void blockOnQueue(Address addr, MessageBuffer* port);
250 void unblock(Address addr);
257 for param
in self
.config_parameters
:
259 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
261 code('${{param.type_ast.type}} m_${{param.ident}};')
264 int m_number_of_TBEs;
266 TransitionResult doTransition(${ident}_Event event,
267 ${ident}_State state,
268 const Address& addr);
270 TransitionResult doTransitionWorker(${ident}_Event event,
271 ${ident}_State state,
272 ${ident}_State& next_state,
273 const Address& addr);
276 int m_transitions_per_cycle;
278 int m_recycle_latency;
279 std::map<std::string, std::string> m_cfg;
282 MachineID m_machineID;
284 std::map<Address, MessageBuffer*> m_block_map;
285 typedef std::vector<MessageBuffer*> MsgVecType;
286 typedef m5::hash_map< Address, MsgVecType* > WaitingBufType;
287 WaitingBufType m_waiting_buffers;
288 int m_max_in_port_rank;
289 int m_cur_in_port_rank;
290 static ${ident}_ProfileDumper s_profileDumper;
291 ${ident}_Profiler m_profiler;
292 static int m_num_controllers;
294 // Internal functions
297 for func
in self
.functions
:
298 proto
= func
.prototype
306 for action
in self
.actions
.itervalues():
307 code('/** \\brief ${{action.desc}} */')
308 code('void ${{action.ident}}(const Address& addr);')
310 # the controller internal variables
315 for var
in self
.objects
:
316 th
= var
.get("template_hack", "")
317 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
319 if var
.type.ident
== "MessageBuffer":
320 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
324 code('#endif // __${ident}_CONTROLLER_H__')
325 code
.write(path
, '%s.hh' % c_ident
)
327 def printControllerCC(self
, path
):
328 '''Output the actions for performing the actions'''
330 code
= self
.symtab
.codeFormatter()
332 c_ident
= "%s_Controller" % self
.ident
335 /** \\file $c_ident.cc
337 * Auto generated C++ code started by $__file__:$__line__
338 * Created by slicc definition of Module "${{self.short}}"
344 #include "base/cprintf.hh"
345 #include "mem/protocol/${ident}_Controller.hh"
346 #include "mem/protocol/${ident}_State.hh"
347 #include "mem/protocol/${ident}_Event.hh"
348 #include "mem/protocol/Types.hh"
349 #include "mem/ruby/common/Global.hh"
350 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
351 #include "mem/ruby/system/System.hh"
356 # include object classes
358 for var
in self
.objects
:
359 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
360 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
361 seen_types
.add(var
.type.ident
)
365 ${c_ident}Params::create()
367 return new $c_ident(this);
370 int $c_ident::m_num_controllers = 0;
371 ${ident}_ProfileDumper $c_ident::s_profileDumper;
373 // for adding information to the protocol debug trace
374 stringstream ${ident}_transitionComment;
375 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
377 /** \\brief constructor */
378 $c_ident::$c_ident(const Params *p)
379 : AbstractController(p)
381 m_version = p->version;
382 m_transitions_per_cycle = p->transitions_per_cycle;
383 m_buffer_size = p->buffer_size;
384 m_recycle_latency = p->recycle_latency;
385 m_number_of_TBEs = p->number_of_TBEs;
386 m_is_blocking = false;
389 # max_port_rank is used to size vectors and thus should be one plus the
392 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
393 code(' m_max_in_port_rank = $max_port_rank;')
397 # After initializing the universal machine parameters, initialize the
398 # this machines config parameters. Also detemine if these configuration
399 # params include a sequencer. This information will be used later for
400 # contecting the sequencer back to the L1 cache controller.
402 contains_sequencer
= False
403 for param
in self
.config_parameters
:
404 if param
.name
== "sequencer" or param
.name
== "dma_sequencer":
405 contains_sequencer
= True
407 code('m_${{param.name}}_ptr = p->${{param.name}};')
409 code('m_${{param.name}} = p->${{param.name}};')
412 # For the l1 cache controller, add the special atomic support which
413 # includes passing the sequencer a pointer to the controller.
415 if self
.ident
== "L1Cache":
416 if not contains_sequencer
:
417 self
.error("The L1Cache controller must include the sequencer " \
418 "configuration parameter")
421 m_sequencer_ptr->setController(this);
424 # For the DMA controller, pass the sequencer a pointer to the
427 if self
.ident
== "DMA":
428 if not contains_sequencer
:
429 self
.error("The DMA controller must include the sequencer " \
430 "configuration parameter")
433 m_dma_sequencer_ptr->setController(this);
436 code('m_num_controllers++;')
437 for var
in self
.objects
:
438 if var
.ident
.find("mandatoryQueue") >= 0:
439 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
448 MachineType machine_type;
451 m_machineID.type = MachineType_${ident};
452 m_machineID.num = m_version;
454 // initialize objects
455 m_profiler.setVersion(m_version);
456 s_profileDumper.registerProfiler(&m_profiler);
461 for var
in self
.objects
:
463 vid
= "m_%s_ptr" % var
.c_ident
464 if "network" not in var
:
465 # Not a network port object
466 if "primitive" in vtype
:
467 code('$vid = new ${{vtype.c_ident}};')
469 code('(*$vid) = ${{var["default"]}};')
474 code('$vid = ${{var["factory"]}};')
475 elif var
.ident
.find("mandatoryQueue") < 0:
476 th
= var
.get("template_hack", "")
477 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
480 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
481 if expr
.find("TBETable") >= 0:
482 args
= "m_number_of_TBEs"
484 args
= var
.get("constructor_hack", "")
486 code('$expr($args);')
488 code('assert($vid != NULL);')
491 code('*$vid = ${{var["default"]}}; // Object default')
492 elif "default" in vtype
:
493 comment
= "Type %s default" % vtype
.ident
494 code('*$vid = ${{vtype["default"]}}; // $comment')
497 if "ordered" in var
and "trigger_queue" not in var
:
499 code('$vid->setOrdering(${{var["ordered"]}});')
504 code('$vid->setRandomization(${{var["random"]}});')
507 if vtype
.isBuffer
and \
508 "rank" in var
and "trigger_queue" not in var
:
509 code('$vid->setPriority(${{var["rank"]}});')
512 # Network port object
513 network
= var
["network"]
514 ordered
= var
["ordered"]
515 vnet
= var
["virtual_network"]
517 assert var
.machine
is not None
519 machine_type = string_to_MachineType("${{var.machine.ident}}");
520 base = MachineType_base_number(machine_type);
521 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
524 code('assert($vid != NULL);')
529 code('$vid->setOrdering(${{var["ordered"]}});')
534 code('$vid->setRandomization(${{var["random"]}})')
538 code('$vid->setPriority(${{var["rank"]}})')
543 if (m_buffer_size > 0) {
544 $vid->resize(m_buffer_size);
548 # set description (may be overriden later by port def)
550 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
555 if "recycle_latency" in var
:
556 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
558 code('$vid->setRecycleLatency(m_recycle_latency);')
561 # Set the queue consumers
562 code
.insert_newline()
563 for port
in self
.in_ports
:
564 code('${{port.code}}.setConsumer(this);')
566 # Set the queue descriptions
567 code
.insert_newline()
568 for port
in self
.in_ports
:
569 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
571 # Initialize the transition profiling
572 code
.insert_newline()
573 for trans
in self
.transitions
:
574 # Figure out if we stall
576 for action
in trans
.actions
:
577 if action
.ident
== "z_stall":
580 # Only possible if it is not a 'z' case
582 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
583 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
584 code('m_profiler.possibleTransition($state, $event);')
589 has_mandatory_q
= False
590 for port
in self
.in_ports
:
591 if port
.code
.find("mandatoryQueue_ptr") >= 0:
592 has_mandatory_q
= True
595 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
601 $c_ident::getNumControllers()
603 return m_num_controllers;
607 $c_ident::getMandatoryQueue() const
613 $c_ident::getVersion() const
619 $c_ident::toString() const
625 $c_ident::getName() const
631 $c_ident::getMachineType() const
633 return MachineType_${ident};
637 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
639 if (m_waiting_buffers.count(addr) == 0) {
640 MsgVecType* msgVec = new MsgVecType;
641 msgVec->resize(m_max_in_port_rank, NULL);
642 m_waiting_buffers[addr] = msgVec;
644 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
648 $c_ident::wakeUpBuffers(Address addr)
651 // Wake up all possible lower rank (i.e. lower priority) buffers that could
652 // be waiting on this message.
654 for (int in_port_rank = m_cur_in_port_rank - 1;
657 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
658 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
661 delete m_waiting_buffers[addr];
662 m_waiting_buffers.erase(addr);
666 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
668 m_is_blocking = true;
669 m_block_map[addr] = port;
673 $c_ident::unblock(Address addr)
675 m_block_map.erase(addr);
676 if (m_block_map.size() == 0) {
677 m_is_blocking = false;
682 $c_ident::print(ostream& out) const
684 out << "[$c_ident " << m_version << "]";
688 $c_ident::printConfig(ostream& out) const
690 out << "$c_ident config: " << m_name << endl;
691 out << " version: " << m_version << endl;
692 map<string, string>::const_iterator it;
693 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
694 out << " " << it->first << ": " << it->second << endl;
698 $c_ident::printStats(ostream& out) const
702 # Cache and Memory Controllers have specific profilers associated with
703 # them. Print out these stats before dumping state transition stats.
705 for param
in self
.config_parameters
:
706 if param
.type_ast
.type.ident
== "CacheMemory" or \
707 param
.type_ast
.type.ident
== "DirectoryMemory" or \
708 param
.type_ast
.type.ident
== "MemoryControl":
709 assert(param
.pointer
)
710 code(' m_${{param.ident}}_ptr->printStats(out);')
713 if (m_version == 0) {
714 s_profileDumper.dumpStats(out);
718 void $c_ident::clearStats() {
721 # Cache and Memory Controllers have specific profilers associated with
722 # them. These stats must be cleared too.
724 for param
in self
.config_parameters
:
725 if param
.type_ast
.type.ident
== "CacheMemory" or \
726 param
.type_ast
.type.ident
== "MemoryControl":
727 assert(param
.pointer
)
728 code(' m_${{param.ident}}_ptr->clearStats();')
731 m_profiler.clearStats();
737 for action
in self
.actions
.itervalues():
738 if "c_code" not in action
:
742 /** \\brief ${{action.desc}} */
744 $c_ident::${{action.ident}}(const Address& addr)
746 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
747 ${{action["c_code"]}}
751 code
.write(path
, "%s.cc" % c_ident
)
753 def printCWakeup(self
, path
):
754 '''Output the wakeup loop for the events'''
756 code
= self
.symtab
.codeFormatter()
760 // Auto generated C++ code started by $__file__:$__line__
761 // ${ident}: ${{self.short}}
763 #include "base/misc.hh"
764 #include "mem/ruby/common/Global.hh"
765 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
766 #include "mem/protocol/${ident}_Controller.hh"
767 #include "mem/protocol/${ident}_State.hh"
768 #include "mem/protocol/${ident}_Event.hh"
769 #include "mem/protocol/Types.hh"
770 #include "mem/ruby/system/System.hh"
775 ${ident}_Controller::wakeup()
777 // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this);
778 // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
782 // Some cases will put us into an infinite loop without this limit
783 assert(counter <= m_transitions_per_cycle);
784 if (counter == m_transitions_per_cycle) {
785 // Count how often we are fully utilized
786 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
788 // Wakeup in another cycle and try again
789 g_eventQueue_ptr->scheduleEvent(this, 1);
799 for port
in self
.in_ports
:
801 code('// ${ident}InPort $port')
802 if port
.pairs
.has_key("rank"):
803 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
805 code('m_cur_in_port_rank = 0;')
806 code('${{port["c_code_in_port"]}}')
814 break; // If we got this far, we have nothing left todo
816 // g_eventQueue_ptr->scheduleEvent(this, 1);
817 // DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
821 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
823 def printCSwitch(self
, path
):
824 '''Output switch statement for transition table'''
826 code
= self
.symtab
.codeFormatter()
830 // Auto generated C++ code started by $__file__:$__line__
831 // ${ident}: ${{self.short}}
833 #include "mem/ruby/common/Global.hh"
834 #include "mem/protocol/${ident}_Controller.hh"
835 #include "mem/protocol/${ident}_State.hh"
836 #include "mem/protocol/${ident}_Event.hh"
837 #include "mem/protocol/Types.hh"
838 #include "mem/ruby/system/System.hh"
840 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
842 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
843 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
846 ${ident}_Controller::doTransition(${ident}_Event event,
847 ${ident}_State state,
850 ${ident}_State next_state = state;
852 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
853 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
854 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
855 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
856 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
857 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
859 TransitionResult result =
860 doTransitionWorker(event, state, next_state, addr);
862 if (result == TransitionResult_Valid) {
863 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
864 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
865 m_profiler.countTransition(state, event);
866 if (Debug::getProtocolTrace()) {
867 g_system_ptr->getProfiler()->profileTransition("${ident}",
869 ${ident}_State_to_string(state),
870 ${ident}_Event_to_string(event),
871 ${ident}_State_to_string(next_state),
872 GET_TRANSITION_COMMENT());
874 CLEAR_TRANSITION_COMMENT();
875 ${ident}_setState(addr, next_state);
877 } else if (result == TransitionResult_ResourceStall) {
878 if (Debug::getProtocolTrace()) {
879 g_system_ptr->getProfiler()->profileTransition("${ident}",
881 ${ident}_State_to_string(state),
882 ${ident}_Event_to_string(event),
883 ${ident}_State_to_string(next_state),
886 } else if (result == TransitionResult_ProtocolStall) {
887 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
888 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
889 if (Debug::getProtocolTrace()) {
890 g_system_ptr->getProfiler()->profileTransition("${ident}",
892 ${ident}_State_to_string(state),
893 ${ident}_Event_to_string(event),
894 ${ident}_State_to_string(next_state),
903 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
904 ${ident}_State state,
905 ${ident}_State& next_state,
908 switch(HASH_FUN(state, event)) {
911 # This map will allow suppress generating duplicate code
914 for trans
in self
.transitions
:
915 case_string
= "%s_State_%s, %s_Event_%s" % \
916 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
918 case
= self
.symtab
.codeFormatter()
919 # Only set next_state if it changes
920 if trans
.state
!= trans
.nextState
:
921 ns_ident
= trans
.nextState
.ident
922 case('next_state = ${ident}_State_${ns_ident};')
924 actions
= trans
.actions
926 # Check for resources
928 res
= trans
.resources
929 for key
,val
in res
.iteritems():
930 if key
.type.ident
!= "DNUCAStopTable":
932 if (!%s.areNSlotsAvailable(%s))
933 return TransitionResult_ResourceStall;
934 ''' % (key
.code
, val
)
935 case_sorter
.append(val
)
938 # Emit the code sequences in a sorted order. This makes the
939 # output deterministic (without this the output order can vary
940 # since Map's keys() on a vector of pointers is not deterministic
941 for c
in sorted(case_sorter
):
944 # Figure out if we stall
946 for action
in actions
:
947 if action
.ident
== "z_stall":
952 case('return TransitionResult_ProtocolStall;')
954 for action
in actions
:
955 case('${{action.ident}}(addr);')
956 case('return TransitionResult_Valid;')
960 # Look to see if this transition code is unique.
961 if case
not in cases
:
964 cases
[case
].append(case_string
)
966 # Walk through all of the unique code blocks and spit out the
967 # corresponding case statement elements
968 for case
,transitions
in cases
.iteritems():
969 # Iterative over all the multiple transitions that share
971 for trans
in transitions
:
972 code(' case HASH_FUN($trans):')
977 WARN_EXPR(m_version);
978 WARN_EXPR(g_eventQueue_ptr->getTime());
982 ERROR_MSG(\"Invalid transition\");
984 return TransitionResult_Valid;
987 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
989 def printProfileDumperHH(self
, path
):
990 code
= self
.symtab
.codeFormatter()
994 // Auto generated C++ code started by $__file__:$__line__
995 // ${ident}: ${{self.short}}
997 #ifndef __${ident}_PROFILE_DUMPER_HH__
998 #define __${ident}_PROFILE_DUMPER_HH__
1003 #include "${ident}_Profiler.hh"
1004 #include "${ident}_Event.hh"
1006 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1008 class ${ident}_ProfileDumper
1011 ${ident}_ProfileDumper();
1012 void registerProfiler(${ident}_Profiler* profiler);
1013 void dumpStats(std::ostream& out) const;
1016 ${ident}_profilers m_profilers;
1019 #endif // __${ident}_PROFILE_DUMPER_HH__
1021 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1023 def printProfileDumperCC(self
, path
):
1024 code
= self
.symtab
.codeFormatter()
1028 // Auto generated C++ code started by $__file__:$__line__
1029 // ${ident}: ${{self.short}}
1031 #include "mem/protocol/${ident}_ProfileDumper.hh"
1033 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1038 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1040 m_profilers.push_back(profiler);
1044 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1046 out << " --- ${ident} ---\\n";
1047 out << " - Event Counts -\\n";
1048 for (${ident}_Event event = ${ident}_Event_FIRST;
1049 event < ${ident}_Event_NUM;
1051 out << (${ident}_Event) event << " [";
1053 for (int i = 0; i < m_profilers.size(); i++) {
1054 out << m_profilers[i]->getEventCount(event) << " ";
1055 total += m_profilers[i]->getEventCount(event);
1057 out << "] " << total << "\\n";
1060 out << " - Transitions -\\n";
1061 for (${ident}_State state = ${ident}_State_FIRST;
1062 state < ${ident}_State_NUM;
1064 for (${ident}_Event event = ${ident}_Event_FIRST;
1065 event < ${ident}_Event_NUM;
1067 if (m_profilers[0]->isPossible(state, event)) {
1068 out << (${ident}_State) state << " "
1069 << (${ident}_Event) event << " [";
1071 for (int i = 0; i < m_profilers.size(); i++) {
1072 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1073 total += m_profilers[i]->getTransitionCount(state, event);
1075 out << "] " << total << "\\n";
1082 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1084 def printProfilerHH(self
, path
):
1085 code
= self
.symtab
.codeFormatter()
1089 // Auto generated C++ code started by $__file__:$__line__
1090 // ${ident}: ${{self.short}}
1092 #ifndef __${ident}_PROFILER_HH__
1093 #define __${ident}_PROFILER_HH__
1097 #include "mem/ruby/common/Global.hh"
1098 #include "mem/protocol/${ident}_State.hh"
1099 #include "mem/protocol/${ident}_Event.hh"
1101 class ${ident}_Profiler
1104 ${ident}_Profiler();
1105 void setVersion(int version);
1106 void countTransition(${ident}_State state, ${ident}_Event event);
1107 void possibleTransition(${ident}_State state, ${ident}_Event event);
1108 uint64 getEventCount(${ident}_Event event);
1109 bool isPossible(${ident}_State state, ${ident}_Event event);
1110 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1114 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1115 int m_event_counters[${ident}_Event_NUM];
1116 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1120 #endif // __${ident}_PROFILER_HH__
1122 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1124 def printProfilerCC(self
, path
):
1125 code
= self
.symtab
.codeFormatter()
1129 // Auto generated C++ code started by $__file__:$__line__
1130 // ${ident}: ${{self.short}}
1132 #include "mem/protocol/${ident}_Profiler.hh"
1134 ${ident}_Profiler::${ident}_Profiler()
1136 for (int state = 0; state < ${ident}_State_NUM; state++) {
1137 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1138 m_possible[state][event] = false;
1139 m_counters[state][event] = 0;
1142 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1143 m_event_counters[event] = 0;
1148 ${ident}_Profiler::setVersion(int version)
1150 m_version = version;
1154 ${ident}_Profiler::clearStats()
1156 for (int state = 0; state < ${ident}_State_NUM; state++) {
1157 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1158 m_counters[state][event] = 0;
1162 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1163 m_event_counters[event] = 0;
1167 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1169 assert(m_possible[state][event]);
1170 m_counters[state][event]++;
1171 m_event_counters[event]++;
1174 ${ident}_Profiler::possibleTransition(${ident}_State state,
1175 ${ident}_Event event)
1177 m_possible[state][event] = true;
1181 ${ident}_Profiler::getEventCount(${ident}_Event event)
1183 return m_event_counters[event];
1187 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1189 return m_possible[state][event];
1193 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1194 ${ident}_Event event)
1196 return m_counters[state][event];
1200 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1202 # **************************
1203 # ******* HTML Files *******
1204 # **************************
1205 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1206 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1207 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1208 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1209 parent.frames[$over_num].location='$over_href'
1211 ${{html.formatShorthand(text)}}
1215 def writeHTMLFiles(self
, path
):
1216 # Create table with no row hilighted
1217 self
.printHTMLTransitions(path
, None)
1219 # Generate transition tables
1220 for state
in self
.states
.itervalues():
1221 self
.printHTMLTransitions(path
, state
)
1223 # Generate action descriptions
1224 for action
in self
.actions
.itervalues():
1225 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1226 code
= html
.createSymbol(action
, "Action")
1227 code
.write(path
, name
)
1229 # Generate state descriptions
1230 for state
in self
.states
.itervalues():
1231 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1232 code
= html
.createSymbol(state
, "State")
1233 code
.write(path
, name
)
1235 # Generate event descriptions
1236 for event
in self
.events
.itervalues():
1237 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1238 code
= html
.createSymbol(event
, "Event")
1239 code
.write(path
, name
)
1241 def printHTMLTransitions(self
, path
, active_state
):
1242 code
= self
.symtab
.codeFormatter()
1246 <BODY link="blue" vlink="blue">
1248 <H1 align="center">${{html.formatShorthand(self.short)}}:
1251 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1260 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1271 for event
in self
.events
.itervalues():
1272 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1273 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1274 code('<TH bgcolor=white>$ref</TH>')
1278 for state
in self
.states
.itervalues():
1280 if state
== active_state
:
1285 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1286 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1287 text
= html
.formatShorthand(state
.short
)
1288 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1291 <TH bgcolor=$color>$ref</TH>
1294 # -- One column for each event
1295 for event
in self
.events
.itervalues():
1296 trans
= self
.table
.get((state
,event
), None)
1298 # This is the no transition case
1299 if state
== active_state
:
1304 code('<TD bgcolor=$color> </TD>')
1307 next
= trans
.nextState
1308 stall_action
= False
1310 # -- Get the actions
1311 for action
in trans
.actions
:
1312 if action
.ident
== "z_stall" or \
1313 action
.ident
== "zz_recycleMandatoryQueue":
1316 # -- Print out "actions/next-state"
1318 if state
== active_state
:
1323 elif active_state
and next
.ident
== active_state
.ident
:
1325 elif state
== active_state
:
1330 code('<TD bgcolor=$color>')
1331 for action
in trans
.actions
:
1332 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1333 ref
= self
.frameRef(href
, "Status", href
, "1",
1339 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1340 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1341 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1346 if state
== active_state
:
1351 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1352 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1353 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1355 <TH bgcolor=$color>$ref</TH>
1364 for event
in self
.events
.itervalues():
1365 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1366 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1367 code('<TH bgcolor=white>$ref</TH>')
1376 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1378 name
= "%s_table.html" % self
.ident
1379 code
.write(path
, name
)
1381 __all__
= [ "StateMachine" ]