a58c1e9c73f3c44509583388a52c0bb20c03cbcf
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
)
149 for func
in self
.functions
:
150 func
.writeCodeFiles(path
)
152 def printControllerPython(self
, path
):
153 code
= self
.symtab
.codeFormatter()
155 py_ident
= "%s_Controller" % ident
156 c_ident
= "%s_Controller" % self
.ident
158 from m5.params import *
159 from m5.SimObject import SimObject
160 from Controller import RubyController
162 class $py_ident(RubyController):
166 for param
in self
.config_parameters
:
168 if param
.default
is not None:
169 dflt_str
= str(param
.default
) + ', '
170 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
171 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
172 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
174 self
.error("Unknown c++ to python class conversion for c++ " \
175 "type: '%s'. Please update the python_class_map " \
176 "in StateMachine.py", param
.type_ast
.type.c_ident
)
178 code
.write(path
, '%s.py' % py_ident
)
181 def printControllerHH(self
, path
):
182 '''Output the method declarations for the class declaration'''
183 code
= self
.symtab
.codeFormatter()
185 c_ident
= "%s_Controller" % self
.ident
187 self
.message_buffer_names
= []
190 /** \\file $c_ident.hh
192 * Auto generated C++ code started by $__file__:$__line__
193 * Created by slicc definition of Module "${{self.short}}"
196 #ifndef __${ident}_CONTROLLER_HH__
197 #define __${ident}_CONTROLLER_HH__
203 #include "params/$c_ident.hh"
205 #include "mem/ruby/common/Global.hh"
206 #include "mem/ruby/common/Consumer.hh"
207 #include "mem/ruby/slicc_interface/AbstractController.hh"
208 #include "mem/protocol/TransitionResult.hh"
209 #include "mem/protocol/Types.hh"
210 #include "mem/protocol/${ident}_Profiler.hh"
214 for var
in self
.objects
:
215 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
216 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
217 seen_types
.add(var
.type.ident
)
219 # for adding information to the protocol debug trace
221 extern std::stringstream ${ident}_transitionComment;
223 class $c_ident : public AbstractController
225 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
226 // making the Chip a friend class is an easy way to do this for now
229 typedef ${c_ident}Params Params;
230 $c_ident(const Params *p);
231 static int getNumControllers();
233 MessageBuffer* getMandatoryQueue() const;
234 const int & getVersion() const;
235 const std::string toString() const;
236 const std::string getName() const;
237 const MachineType getMachineType() const;
238 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
239 void print(std::ostream& out) const;
240 void printConfig(std::ostream& out) const;
242 void printStats(std::ostream& out) const;
244 void blockOnQueue(Address addr, MessageBuffer* port);
245 void unblock(Address addr);
252 for param
in self
.config_parameters
:
254 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
256 code('${{param.type_ast.type}} m_${{param.ident}};')
259 int m_number_of_TBEs;
261 TransitionResult doTransition(${ident}_Event event,
262 ${ident}_State state,
263 const Address& addr);
265 TransitionResult doTransitionWorker(${ident}_Event event,
266 ${ident}_State state,
267 ${ident}_State& next_state,
268 const Address& addr);
271 int m_transitions_per_cycle;
273 int m_recycle_latency;
274 std::map<std::string, std::string> m_cfg;
277 MachineID m_machineID;
279 std::map<Address, MessageBuffer*> m_block_map;
280 ${ident}_Profiler s_profiler;
281 static int m_num_controllers;
283 // Internal functions
286 for func
in self
.functions
:
287 proto
= func
.prototype
295 for action
in self
.actions
.itervalues():
296 code('/** \\brief ${{action.desc}} */')
297 code('void ${{action.ident}}(const Address& addr);')
299 # the controller internal variables
304 for var
in self
.objects
:
305 th
= var
.get("template_hack", "")
306 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
308 if var
.type.ident
== "MessageBuffer":
309 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
313 code('#endif // __${ident}_CONTROLLER_H__')
314 code
.write(path
, '%s.hh' % c_ident
)
316 def printControllerCC(self
, path
):
317 '''Output the actions for performing the actions'''
319 code
= self
.symtab
.codeFormatter()
321 c_ident
= "%s_Controller" % self
.ident
324 /** \\file $c_ident.cc
326 * Auto generated C++ code started by $__file__:$__line__
327 * Created by slicc definition of Module "${{self.short}}"
333 #include "mem/ruby/common/Global.hh"
334 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
335 #include "mem/protocol/${ident}_Controller.hh"
336 #include "mem/protocol/${ident}_State.hh"
337 #include "mem/protocol/${ident}_Event.hh"
338 #include "mem/protocol/Types.hh"
339 #include "mem/ruby/system/System.hh"
344 # include object classes
346 for var
in self
.objects
:
347 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
348 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
349 seen_types
.add(var
.type.ident
)
353 ${c_ident}Params::create()
355 return new $c_ident(this);
358 int $c_ident::m_num_controllers = 0;
360 // for adding information to the protocol debug trace
361 stringstream ${ident}_transitionComment;
362 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
364 /** \\brief constructor */
365 $c_ident::$c_ident(const Params *p)
366 : AbstractController(p)
368 m_version = p->version;
369 m_transitions_per_cycle = p->transitions_per_cycle;
370 m_buffer_size = p->buffer_size;
371 m_recycle_latency = p->recycle_latency;
372 m_number_of_TBEs = p->number_of_TBEs;
373 m_is_blocking = false;
378 # After initializing the universal machine parameters, initialize the
379 # this machines config parameters. Also detemine if these configuration
380 # params include a sequencer. This information will be used later for
381 # contecting the sequencer back to the L1 cache controller.
383 contains_sequencer
= False
384 for param
in self
.config_parameters
:
385 if param
.name
== "sequencer" or param
.name
== "dma_sequencer":
386 contains_sequencer
= True
388 code('m_${{param.name}}_ptr = p->${{param.name}};')
390 code('m_${{param.name}} = p->${{param.name}};')
393 # For the l1 cache controller, add the special atomic support which
394 # includes passing the sequencer a pointer to the controller.
396 if self
.ident
== "L1Cache":
397 if not contains_sequencer
:
398 self
.error("The L1Cache controller must include the sequencer " \
399 "configuration parameter")
402 m_sequencer_ptr->setController(this);
405 # For the DMA controller, pass the sequencer a pointer to the
408 if self
.ident
== "DMA":
409 if not contains_sequencer
:
410 self
.error("The DMA controller must include the sequencer " \
411 "configuration parameter")
414 m_dma_sequencer_ptr->setController(this);
417 code('m_num_controllers++;')
418 for var
in self
.objects
:
419 if var
.ident
.find("mandatoryQueue") >= 0:
420 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
429 MachineType machine_type;
432 m_machineID.type = MachineType_${ident};
433 m_machineID.num = m_version;
435 // initialize objects
436 s_profiler.setVersion(m_version);
441 for var
in self
.objects
:
443 vid
= "m_%s_ptr" % var
.c_ident
444 if "network" not in var
:
445 # Not a network port object
446 if "primitive" in vtype
:
447 code('$vid = new ${{vtype.c_ident}};')
449 code('(*$vid) = ${{var["default"]}};')
454 code('$vid = ${{var["factory"]}};')
455 elif var
.ident
.find("mandatoryQueue") < 0:
456 th
= var
.get("template_hack", "")
457 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
460 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
461 if expr
.find("TBETable") >= 0:
462 args
= "m_number_of_TBEs"
464 args
= var
.get("constructor_hack", "")
466 code('$expr($args);')
468 code('assert($vid != NULL);')
471 code('*$vid = ${{var["default"]}}; // Object default')
472 elif "default" in vtype
:
473 comment
= "Type %s default" % vtype
.ident
474 code('*$vid = ${{vtype["default"]}}; // $comment')
477 if "ordered" in var
and "trigger_queue" not in var
:
479 code('$vid->setOrdering(${{var["ordered"]}});')
484 code('$vid->setRandomization(${{var["random"]}});')
487 if vtype
.isBuffer
and \
488 "rank" in var
and "trigger_queue" not in var
:
489 code('$vid->setPriority(${{var["rank"]}});')
491 # Network port object
492 network
= var
["network"]
493 ordered
= var
["ordered"]
494 vnet
= var
["virtual_network"]
496 assert var
.machine
is not None
498 machine_type = string_to_MachineType("${{var.machine.ident}}");
499 base = MachineType_base_number(machine_type);
500 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet);
503 code('assert($vid != NULL);')
508 code('$vid->setOrdering(${{var["ordered"]}});')
513 code('$vid->setRandomization(${{var["random"]}})')
517 code('$vid->setPriority(${{var["rank"]}})')
522 if (m_buffer_size > 0) {
523 $vid->setSize(m_buffer_size);
527 # set description (may be overriden later by port def)
529 $vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
533 # Set the queue consumers
534 code
.insert_newline()
535 for port
in self
.in_ports
:
536 code('${{port.code}}.setConsumer(this);')
538 # Set the queue descriptions
539 code
.insert_newline()
540 for port
in self
.in_ports
:
541 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");')
543 # Initialize the transition profiling
544 code
.insert_newline()
545 for trans
in self
.transitions
:
546 # Figure out if we stall
548 for action
in trans
.actions
:
549 if action
.ident
== "z_stall":
552 # Only possible if it is not a 'z' case
554 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
555 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
556 code('s_profiler.possibleTransition($state, $event);')
558 # added by SS to initialize recycle_latency of message buffers
559 for buf
in self
.message_buffer_names
:
560 code("$buf->setRecycleLatency(m_recycle_latency);")
565 has_mandatory_q
= False
566 for port
in self
.in_ports
:
567 if port
.code
.find("mandatoryQueue_ptr") >= 0:
568 has_mandatory_q
= True
571 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
577 $c_ident::getNumControllers()
579 return m_num_controllers;
583 $c_ident::getMandatoryQueue() const
589 $c_ident::getVersion() const
595 $c_ident::toString() const
601 $c_ident::getName() const
607 $c_ident::getMachineType() const
609 return MachineType_${ident};
613 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
615 m_is_blocking = true;
616 m_block_map[addr] = port;
620 $c_ident::unblock(Address addr)
622 m_block_map.erase(addr);
623 if (m_block_map.size() == 0) {
624 m_is_blocking = false;
629 $c_ident::print(ostream& out) const
631 out << "[$c_ident " << m_version << "]";
635 $c_ident::printConfig(ostream& out) const
637 out << "$c_ident config: " << m_name << endl;
638 out << " version: " << m_version << endl;
639 map<string, string>::const_iterator it;
640 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
641 out << " " << it->first << ": " << it->second << endl;
645 $c_ident::printStats(ostream& out) const
649 # Cache and Memory Controllers have specific profilers associated with
650 # them. Print out these stats before dumping state transition stats.
652 for param
in self
.config_parameters
:
653 if param
.type_ast
.type.ident
== "CacheMemory" or \
654 param
.type_ast
.type.ident
== "DirectoryMemory" or \
655 param
.type_ast
.type.ident
== "MemoryControl":
656 assert(param
.pointer
)
657 code(' m_${{param.ident}}_ptr->printStats(out);')
660 s_profiler.dumpStats(out);
663 void $c_ident::clearStats() {
666 # Cache and Memory Controllers have specific profilers associated with
667 # them. These stats must be cleared too.
669 for param
in self
.config_parameters
:
670 if param
.type_ast
.type.ident
== "CacheMemory" or \
671 param
.type_ast
.type.ident
== "MemoryControl":
672 assert(param
.pointer
)
673 code(' m_${{param.ident}}_ptr->clearStats();')
676 s_profiler.clearStats();
682 for action
in self
.actions
.itervalues():
683 if "c_code" not in action
:
687 /** \\brief ${{action.desc}} */
689 $c_ident::${{action.ident}}(const Address& addr)
691 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
692 ${{action["c_code"]}}
696 code
.write(path
, "%s.cc" % c_ident
)
698 def printCWakeup(self
, path
):
699 '''Output the wakeup loop for the events'''
701 code
= self
.symtab
.codeFormatter()
705 // Auto generated C++ code started by $__file__:$__line__
706 // ${ident}: ${{self.short}}
708 #include "base/misc.hh"
709 #include "mem/ruby/common/Global.hh"
710 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
711 #include "mem/protocol/${ident}_Controller.hh"
712 #include "mem/protocol/${ident}_State.hh"
713 #include "mem/protocol/${ident}_Event.hh"
714 #include "mem/protocol/Types.hh"
715 #include "mem/ruby/system/System.hh"
720 ${ident}_Controller::wakeup()
722 // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this);
723 // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
727 // Some cases will put us into an infinite loop without this limit
728 assert(counter <= m_transitions_per_cycle);
729 if (counter == m_transitions_per_cycle) {
730 // Count how often we are fully utilized
731 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
733 // Wakeup in another cycle and try again
734 g_eventQueue_ptr->scheduleEvent(this, 1);
744 for port
in self
.in_ports
:
746 code('// ${ident}InPort $port')
747 code('${{port["c_code_in_port"]}}')
755 break; // If we got this far, we have nothing left todo
757 // g_eventQueue_ptr->scheduleEvent(this, 1);
758 // DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
762 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
764 def printCSwitch(self
, path
):
765 '''Output switch statement for transition table'''
767 code
= self
.symtab
.codeFormatter()
771 // Auto generated C++ code started by $__file__:$__line__
772 // ${ident}: ${{self.short}}
774 #include "mem/ruby/common/Global.hh"
775 #include "mem/protocol/${ident}_Controller.hh"
776 #include "mem/protocol/${ident}_State.hh"
777 #include "mem/protocol/${ident}_Event.hh"
778 #include "mem/protocol/Types.hh"
779 #include "mem/ruby/system/System.hh"
781 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
783 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
784 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
787 ${ident}_Controller::doTransition(${ident}_Event event,
788 ${ident}_State state,
791 ${ident}_State next_state = state;
793 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
794 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
795 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
796 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
797 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
798 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
800 TransitionResult result =
801 doTransitionWorker(event, state, next_state, addr);
803 if (result == TransitionResult_Valid) {
804 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
805 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
806 s_profiler.countTransition(state, event);
807 if (Debug::getProtocolTrace()) {
808 g_system_ptr->getProfiler()->profileTransition("${ident}",
810 ${ident}_State_to_string(state),
811 ${ident}_Event_to_string(event),
812 ${ident}_State_to_string(next_state),
813 GET_TRANSITION_COMMENT());
815 CLEAR_TRANSITION_COMMENT();
816 ${ident}_setState(addr, next_state);
818 } else if (result == TransitionResult_ResourceStall) {
819 if (Debug::getProtocolTrace()) {
820 g_system_ptr->getProfiler()->profileTransition("${ident}",
822 ${ident}_State_to_string(state),
823 ${ident}_Event_to_string(event),
824 ${ident}_State_to_string(next_state),
827 } else if (result == TransitionResult_ProtocolStall) {
828 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
829 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
830 if (Debug::getProtocolTrace()) {
831 g_system_ptr->getProfiler()->profileTransition("${ident}",
833 ${ident}_State_to_string(state),
834 ${ident}_Event_to_string(event),
835 ${ident}_State_to_string(next_state),
844 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
845 ${ident}_State state,
846 ${ident}_State& next_state,
849 switch(HASH_FUN(state, event)) {
852 # This map will allow suppress generating duplicate code
855 for trans
in self
.transitions
:
856 case_string
= "%s_State_%s, %s_Event_%s" % \
857 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
859 case
= self
.symtab
.codeFormatter()
860 # Only set next_state if it changes
861 if trans
.state
!= trans
.nextState
:
862 ns_ident
= trans
.nextState
.ident
863 case('next_state = ${ident}_State_${ns_ident};')
865 actions
= trans
.actions
867 # Check for resources
869 res
= trans
.resources
870 for key
,val
in res
.iteritems():
871 if key
.type.ident
!= "DNUCAStopTable":
873 if (!%s.areNSlotsAvailable(%s))
874 return TransitionResult_ResourceStall;
875 ''' % (key
.code
, val
)
876 case_sorter
.append(val
)
879 # Emit the code sequences in a sorted order. This makes the
880 # output deterministic (without this the output order can vary
881 # since Map's keys() on a vector of pointers is not deterministic
882 for c
in sorted(case_sorter
):
885 # Figure out if we stall
887 for action
in actions
:
888 if action
.ident
== "z_stall":
893 case('return TransitionResult_ProtocolStall;')
895 for action
in actions
:
896 case('${{action.ident}}(addr);')
897 case('return TransitionResult_Valid;')
901 # Look to see if this transition code is unique.
902 if case
not in cases
:
905 cases
[case
].append(case_string
)
907 # Walk through all of the unique code blocks and spit out the
908 # corresponding case statement elements
909 for case
,transitions
in cases
.iteritems():
910 # Iterative over all the multiple transitions that share
912 for trans
in transitions
:
913 code(' case HASH_FUN($trans):')
918 WARN_EXPR(m_version);
919 WARN_EXPR(g_eventQueue_ptr->getTime());
923 ERROR_MSG(\"Invalid transition\");
925 return TransitionResult_Valid;
928 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
930 def printProfilerHH(self
, path
):
931 code
= self
.symtab
.codeFormatter()
935 // Auto generated C++ code started by $__file__:$__line__
936 // ${ident}: ${{self.short}}
938 #ifndef __${ident}_PROFILER_HH_
939 #define __${ident}_PROFILER_HH_
943 #include "mem/ruby/common/Global.hh"
944 #include "mem/protocol/${ident}_State.hh"
945 #include "mem/protocol/${ident}_Event.hh"
947 class ${ident}_Profiler
951 void setVersion(int version);
952 void countTransition(${ident}_State state, ${ident}_Event event);
953 void possibleTransition(${ident}_State state, ${ident}_Event event);
954 void dumpStats(std::ostream& out) const;
958 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
959 int m_event_counters[${ident}_Event_NUM];
960 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
964 #endif // __${ident}_PROFILER_HH__
966 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
968 def printProfilerCC(self
, path
):
969 code
= self
.symtab
.codeFormatter()
973 // Auto generated C++ code started by $__file__:$__line__
974 // ${ident}: ${{self.short}}
976 #include "mem/protocol/${ident}_Profiler.hh"
978 ${ident}_Profiler::${ident}_Profiler()
980 for (int state = 0; state < ${ident}_State_NUM; state++) {
981 for (int event = 0; event < ${ident}_Event_NUM; event++) {
982 m_possible[state][event] = false;
983 m_counters[state][event] = 0;
986 for (int event = 0; event < ${ident}_Event_NUM; event++) {
987 m_event_counters[event] = 0;
992 ${ident}_Profiler::setVersion(int version)
998 ${ident}_Profiler::clearStats()
1000 for (int state = 0; state < ${ident}_State_NUM; state++) {
1001 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1002 m_counters[state][event] = 0;
1006 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1007 m_event_counters[event] = 0;
1011 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1013 assert(m_possible[state][event]);
1014 m_counters[state][event]++;
1015 m_event_counters[event]++;
1018 ${ident}_Profiler::possibleTransition(${ident}_State state,
1019 ${ident}_Event event)
1021 m_possible[state][event] = true;
1025 ${ident}_Profiler::dumpStats(std::ostream& out) const
1027 using namespace std;
1029 out << " --- ${ident} " << m_version << " ---" << endl;
1030 out << " - Event Counts -" << endl;
1031 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1032 int count = m_event_counters[event];
1033 out << (${ident}_Event) event << " " << count << endl;
1036 out << " - Transitions -" << endl;
1037 for (int state = 0; state < ${ident}_State_NUM; state++) {
1038 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1039 if (m_possible[state][event]) {
1040 int count = m_counters[state][event];
1041 out << (${ident}_State) state << " "
1042 << (${ident}_Event) event << " " << count;
1053 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1055 # **************************
1056 # ******* HTML Files *******
1057 # **************************
1058 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1059 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1060 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1061 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1062 parent.frames[$over_num].location='$over_href'
1064 ${{html.formatShorthand(text)}}
1068 def writeHTMLFiles(self
, path
):
1069 # Create table with no row hilighted
1070 self
.printHTMLTransitions(path
, None)
1072 # Generate transition tables
1073 for state
in self
.states
.itervalues():
1074 self
.printHTMLTransitions(path
, state
)
1076 # Generate action descriptions
1077 for action
in self
.actions
.itervalues():
1078 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1079 code
= html
.createSymbol(action
, "Action")
1080 code
.write(path
, name
)
1082 # Generate state descriptions
1083 for state
in self
.states
.itervalues():
1084 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1085 code
= html
.createSymbol(state
, "State")
1086 code
.write(path
, name
)
1088 # Generate event descriptions
1089 for event
in self
.events
.itervalues():
1090 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1091 code
= html
.createSymbol(event
, "Event")
1092 code
.write(path
, name
)
1094 def printHTMLTransitions(self
, path
, active_state
):
1095 code
= self
.symtab
.codeFormatter()
1099 <BODY link="blue" vlink="blue">
1101 <H1 align="center">${{html.formatShorthand(self.short)}}:
1104 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1113 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1124 for event
in self
.events
.itervalues():
1125 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1126 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1127 code('<TH bgcolor=white>$ref</TH>')
1131 for state
in self
.states
.itervalues():
1133 if state
== active_state
:
1138 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1139 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1140 text
= html
.formatShorthand(state
.short
)
1141 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1144 <TH bgcolor=$color>$ref</TH>
1147 # -- One column for each event
1148 for event
in self
.events
.itervalues():
1149 trans
= self
.table
.get((state
,event
), None)
1151 # This is the no transition case
1152 if state
== active_state
:
1157 code('<TD bgcolor=$color> </TD>')
1160 next
= trans
.nextState
1161 stall_action
= False
1163 # -- Get the actions
1164 for action
in trans
.actions
:
1165 if action
.ident
== "z_stall" or \
1166 action
.ident
== "zz_recycleMandatoryQueue":
1169 # -- Print out "actions/next-state"
1171 if state
== active_state
:
1176 elif active_state
and next
.ident
== active_state
.ident
:
1178 elif state
== active_state
:
1183 code('<TD bgcolor=$color>')
1184 for action
in trans
.actions
:
1185 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1186 ref
= self
.frameRef(href
, "Status", href
, "1",
1192 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1193 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1194 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1199 if state
== active_state
:
1204 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1205 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1206 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1208 <TH bgcolor=$color>$ref</TH>
1217 for event
in self
.events
.itervalues():
1218 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1219 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1220 code('<TH bgcolor=white>$ref</TH>')
1229 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1231 name
= "%s_table.html" % self
.ident
1232 code
.write(path
, name
)
1234 __all__
= [ "StateMachine" ]