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",
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
= []
192 * Auto generated C++ code started by $__file__:$__line__
193 * Created by slicc definition of Module "${{self.short}}"
196 #ifndef ${ident}_CONTROLLER_H
197 #define ${ident}_CONTROLLER_H
199 #include "params/$c_ident.hh"
201 #include "mem/ruby/common/Global.hh"
202 #include "mem/ruby/common/Consumer.hh"
203 #include "mem/ruby/slicc_interface/AbstractController.hh"
204 #include "mem/protocol/TransitionResult.hh"
205 #include "mem/protocol/Types.hh"
206 #include "mem/protocol/${ident}_Profiler.hh"
210 for var
in self
.objects
:
211 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
212 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
213 seen_types
.add(var
.type.ident
)
215 # for adding information to the protocol debug trace
217 extern stringstream ${ident}_transitionComment;
219 class $c_ident : public AbstractController {
220 #ifdef CHECK_COHERENCE
221 #endif /* CHECK_COHERENCE */
223 typedef ${c_ident}Params Params;
224 $c_ident(const Params *p);
225 static int getNumControllers();
227 MessageBuffer* getMandatoryQueue() const;
228 const int & getVersion() const;
229 const string toString() const;
230 const string getName() const;
231 const MachineType getMachineType() const;
232 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
233 void print(ostream& out) const;
234 void printConfig(ostream& out) const;
236 void printStats(ostream& out) const;
238 void blockOnQueue(Address addr, MessageBuffer* port);
239 void unblock(Address addr);
245 for param
in self
.config_parameters
:
247 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
249 code('${{param.type_ast.type}} m_${{param.ident}};')
252 int m_number_of_TBEs;
254 TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc
255 TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc
257 int m_transitions_per_cycle;
259 int m_recycle_latency;
260 map< string, string > m_cfg;
263 MachineID m_machineID;
265 map< Address, MessageBuffer* > m_block_map;
266 ${ident}_Profiler s_profiler;
267 static int m_num_controllers;
268 // Internal functions
271 for func
in self
.functions
:
272 proto
= func
.prototype
280 for action
in self
.actions
.itervalues():
281 code('/** \\brief ${{action.desc}} */')
282 code('void ${{action.ident}}(const Address& addr);')
284 # the controller internal variables
289 for var
in self
.objects
:
290 th
= var
.get("template_hack", "")
291 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
293 if var
.type.ident
== "MessageBuffer":
294 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
298 code('#endif // ${ident}_CONTROLLER_H')
299 code
.write(path
, '%s.hh' % c_ident
)
301 def printControllerCC(self
, path
):
302 '''Output the actions for performing the actions'''
304 code
= self
.symtab
.codeFormatter()
306 c_ident
= "%s_Controller" % self
.ident
311 * Auto generated C++ code started by $__file__:$__line__
312 * Created by slicc definition of Module "${{self.short}}"
315 #include "mem/ruby/common/Global.hh"
316 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
317 #include "mem/protocol/${ident}_Controller.hh"
318 #include "mem/protocol/${ident}_State.hh"
319 #include "mem/protocol/${ident}_Event.hh"
320 #include "mem/protocol/Types.hh"
321 #include "mem/ruby/system/System.hh"
324 # include object classes
326 for var
in self
.objects
:
327 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
328 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
329 seen_types
.add(var
.type.ident
)
333 ${c_ident}Params::create()
335 return new $c_ident(this);
339 int $c_ident::m_num_controllers = 0;
341 stringstream ${ident}_transitionComment;
342 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
343 /** \\brief constructor */
344 $c_ident::$c_ident(const Params *p)
345 : AbstractController(p)
347 m_version = p->version;
348 m_transitions_per_cycle = p->transitions_per_cycle;
349 m_buffer_size = p->buffer_size;
350 m_recycle_latency = p->recycle_latency;
351 m_number_of_TBEs = p->number_of_TBEs;
352 m_is_blocking = false;
357 # After initializing the universal machine parameters, initialize the
358 # this machines config parameters. Also detemine if these configuration
359 # params include a sequencer. This information will be used later for
360 # contecting the sequencer back to the L1 cache controller.
362 contains_sequencer
= False
363 for param
in self
.config_parameters
:
364 if param
.name
== "sequencer" or param
.name
== "dma_sequencer":
365 contains_sequencer
= True
367 code('m_${{param.name}}_ptr = p->${{param.name}};')
369 code('m_${{param.name}} = p->${{param.name}};')
372 # For the l1 cache controller, add the special atomic support which
373 # includes passing the sequencer a pointer to the controller.
375 if self
.ident
== "L1Cache":
376 if not contains_sequencer
:
377 self
.error("The L1Cache controller must include the sequencer " \
378 "configuration parameter")
381 m_sequencer_ptr->setController(this);
384 # For the DMA controller, pass the sequencer a pointer to the
387 if self
.ident
== "DMA":
388 if not contains_sequencer
:
389 self
.error("The DMA controller must include the sequencer " \
390 "configuration parameter")
393 m_dma_sequencer_ptr->setController(this);
396 code('m_num_controllers++;')
397 for var
in self
.objects
:
398 if var
.ident
.find("mandatoryQueue") >= 0:
399 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
405 void $c_ident::init()
407 m_machineID.type = MachineType_${ident};
408 m_machineID.num = m_version;
411 s_profiler.setVersion(m_version);
415 for var
in self
.objects
:
417 vid
= "m_%s_ptr" % var
.c_ident
418 if "network" not in var
:
419 # Not a network port object
420 if "primitive" in vtype
:
421 code('$vid = new ${{vtype.c_ident}};')
423 code('(*$vid) = ${{var["default"]}};')
428 code('$vid = ${{var["factory"]}};')
429 elif var
.ident
.find("mandatoryQueue") < 0:
430 th
= var
.get("template_hack", "")
431 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
434 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
435 if expr
.find("TBETable") >= 0:
436 args
= "m_number_of_TBEs"
438 args
= var
.get("constructor_hack", "")
445 code('assert($vid != NULL);')
448 code('(*$vid) = ${{var["default"]}}; // Object default')
449 elif "default" in vtype
:
450 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default')
453 if "ordered" in var
and "trigger_queue" not in var
:
455 code('$vid->setOrdering(${{var["ordered"]}});')
460 code('$vid->setRandomization(${{var["random"]}});')
463 if vtype
.isBuffer
and \
464 "rank" in var
and "trigger_queue" not in var
:
465 code('$vid->setPriority(${{var["rank"]}});')
467 # Network port object
468 network
= var
["network"]
469 ordered
= var
["ordered"]
470 vnet
= var
["virtual_network"]
472 assert var
.machine
is not None
474 $vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet);
477 code('assert($vid != NULL);')
482 code('$vid->setOrdering(${{var["ordered"]}});')
487 code('$vid->setRandomization(${{var["random"]}})')
491 code('$vid->setPriority(${{var["rank"]}})')
496 if (m_buffer_size > 0) {
497 $vid->setSize(m_buffer_size);
501 # set description (may be overriden later by port def)
502 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");')
504 # Set the queue consumers
505 code
.insert_newline()
506 for port
in self
.in_ports
:
507 code('${{port.code}}.setConsumer(this);')
509 # Set the queue descriptions
510 code
.insert_newline()
511 for port
in self
.in_ports
:
512 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");')
514 # Initialize the transition profiling
515 code
.insert_newline()
516 for trans
in self
.transitions
:
517 # Figure out if we stall
519 for action
in trans
.actions
:
520 if action
.ident
== "z_stall":
523 # Only possible if it is not a 'z' case
525 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
526 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
527 code('s_profiler.possibleTransition($state, $event);')
529 # added by SS to initialize recycle_latency of message buffers
530 for buf
in self
.message_buffer_names
:
531 code("$buf->setRecycleLatency(m_recycle_latency);")
536 has_mandatory_q
= False
537 for port
in self
.in_ports
:
538 if port
.code
.find("mandatoryQueue_ptr") >= 0:
539 has_mandatory_q
= True
542 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
547 int $c_ident::getNumControllers() {
548 return m_num_controllers;
551 MessageBuffer* $c_ident::getMandatoryQueue() const {
555 const int & $c_ident::getVersion() const{
559 const string $c_ident::toString() const{
563 const string $c_ident::getName() const{
566 const MachineType $c_ident::getMachineType() const{
567 return MachineType_${ident};
570 void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) {
571 m_is_blocking = true;
572 m_block_map[addr] = port;
574 void $c_ident::unblock(Address addr) {
575 m_block_map.erase(addr);
576 if (m_block_map.size() == 0) {
577 m_is_blocking = false;
581 void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; }
583 void $c_ident::printConfig(ostream& out) const {
584 out << "$c_ident config: " << m_name << endl;
585 out << " version: " << m_version << endl;
586 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) {
587 out << " " << (*it).first << ": " << (*it).second << endl;
591 void $c_ident::printStats(ostream& out) const {
594 # Cache and Memory Controllers have specific profilers associated with
595 # them. Print out these stats before dumping state transition stats.
597 for param
in self
.config_parameters
:
598 if param
.type_ast
.type.ident
== "CacheMemory" or \
599 param
.type_ast
.type.ident
== "MemoryControl":
600 assert(param
.pointer
)
601 code(' m_${{param.ident}}_ptr->printStats(out);')
604 s_profiler.dumpStats(out);
607 void $c_ident::clearStats() {
610 # Cache and Memory Controllers have specific profilers associated with
611 # them. These stats must be cleared too.
613 for param
in self
.config_parameters
:
614 if param
.type_ast
.type.ident
== "CacheMemory" or \
615 param
.type_ast
.type.ident
== "MemoryControl":
616 assert(param
.pointer
)
617 code(' m_${{param.ident}}_ptr->clearStats();')
620 s_profiler.clearStats();
626 for action
in self
.actions
.itervalues():
627 if "c_code" not in action
:
631 /** \\brief ${{action.desc}} */
632 void $c_ident::${{action.ident}}(const Address& addr)
634 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing");
635 ${{action["c_code"]}}
639 code
.write(path
, "%s.cc" % c_ident
)
641 def printCWakeup(self
, path
):
642 '''Output the wakeup loop for the events'''
644 code
= self
.symtab
.codeFormatter()
648 // Auto generated C++ code started by $__file__:$__line__
649 // ${ident}: ${{self.short}}
651 #include "mem/ruby/common/Global.hh"
652 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
653 #include "mem/protocol/${ident}_Controller.hh"
654 #include "mem/protocol/${ident}_State.hh"
655 #include "mem/protocol/${ident}_Event.hh"
656 #include "mem/protocol/Types.hh"
657 #include "mem/ruby/system/System.hh"
659 void ${ident}_Controller::wakeup()
664 // Some cases will put us into an infinite loop without this limit
665 assert(counter <= m_transitions_per_cycle);
666 if (counter == m_transitions_per_cycle) {
667 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized
668 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again
678 for port
in self
.in_ports
:
680 code('// ${ident}InPort $port')
681 code('${{port["c_code_in_port"]}}')
689 break; // If we got this far, we have nothing left todo
694 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
696 def printCSwitch(self
, path
):
697 '''Output switch statement for transition table'''
699 code
= self
.symtab
.codeFormatter()
703 // Auto generated C++ code started by $__file__:$__line__
704 // ${ident}: ${{self.short}}
706 #include "mem/ruby/common/Global.hh"
707 #include "mem/protocol/${ident}_Controller.hh"
708 #include "mem/protocol/${ident}_State.hh"
709 #include "mem/protocol/${ident}_Event.hh"
710 #include "mem/protocol/Types.hh"
711 #include "mem/ruby/system/System.hh"
713 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
715 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
716 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
718 TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr
721 ${ident}_State next_state = state;
723 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
724 DEBUG_MSG(GENERATED_COMP, MedPrio, *this);
725 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime());
726 DEBUG_EXPR(GENERATED_COMP, MedPrio,state);
727 DEBUG_EXPR(GENERATED_COMP, MedPrio,event);
728 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr);
730 TransitionResult result = doTransitionWorker(event, state, next_state, addr);
732 if (result == TransitionResult_Valid) {
733 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state);
734 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
735 s_profiler.countTransition(state, event);
736 if (Debug::getProtocolTrace()) {
737 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
738 ${ident}_State_to_string(state),
739 ${ident}_Event_to_string(event),
740 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT());
742 CLEAR_TRANSITION_COMMENT();
743 ${ident}_setState(addr, next_state);
745 } else if (result == TransitionResult_ResourceStall) {
746 if (Debug::getProtocolTrace()) {
747 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
748 ${ident}_State_to_string(state),
749 ${ident}_Event_to_string(event),
750 ${ident}_State_to_string(next_state),
753 } else if (result == TransitionResult_ProtocolStall) {
754 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling");
755 DEBUG_NEWLINE(GENERATED_COMP, MedPrio);
756 if (Debug::getProtocolTrace()) {
757 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr,
758 ${ident}_State_to_string(state),
759 ${ident}_Event_to_string(event),
760 ${ident}_State_to_string(next_state),
768 TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr
771 switch(HASH_FUN(state, event)) {
774 # This map will allow suppress generating duplicate code
777 for trans
in self
.transitions
:
778 case_string
= "%s_State_%s, %s_Event_%s" % \
779 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
781 case
= self
.symtab
.codeFormatter()
782 # Only set next_state if it changes
783 if trans
.state
!= trans
.nextState
:
784 ns_ident
= trans
.nextState
.ident
785 case('next_state = ${ident}_State_${ns_ident};')
787 actions
= trans
.actions
789 # Check for resources
791 res
= trans
.resources
792 for key
,val
in res
.iteritems():
793 if key
.type.ident
!= "DNUCAStopTable":
795 if (!%s.areNSlotsAvailable(%s)) {
796 return TransitionResult_ResourceStall;
798 ''' % (key
.code
, val
)
799 case_sorter
.append(val
)
802 # Emit the code sequences in a sorted order. This makes the
803 # output deterministic (without this the output order can vary
804 # since Map's keys() on a vector of pointers is not deterministic
805 for c
in sorted(case_sorter
):
808 # Figure out if we stall
810 for action
in actions
:
811 if action
.ident
== "z_stall":
816 case('return TransitionResult_ProtocolStall;')
818 for action
in actions
:
819 case('${{action.ident}}(addr);')
820 case('return TransitionResult_Valid;')
824 # Look to see if this transition code is unique.
825 if case
not in cases
:
828 cases
[case
].append(case_string
)
830 # Walk through all of the unique code blocks and spit out the
831 # corresponding case statement elements
832 for case
,transitions
in cases
.iteritems():
833 # Iterative over all the multiple transitions that share
835 for trans
in transitions
:
836 code(' case HASH_FUN($trans):')
843 WARN_EXPR(m_version);
844 WARN_EXPR(g_eventQueue_ptr->getTime());
848 ERROR_MSG(\"Invalid transition\");
850 return TransitionResult_Valid;
853 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
855 def printProfilerHH(self
, path
):
856 code
= self
.symtab
.codeFormatter()
860 // Auto generated C++ code started by $__file__:$__line__
861 // ${ident}: ${{self.short}}
863 #ifndef ${ident}_PROFILER_H
864 #define ${ident}_PROFILER_H
866 #include "mem/ruby/common/Global.hh"
867 #include "mem/protocol/${ident}_State.hh"
868 #include "mem/protocol/${ident}_Event.hh"
870 class ${ident}_Profiler {
873 void setVersion(int version);
874 void countTransition(${ident}_State state, ${ident}_Event event);
875 void possibleTransition(${ident}_State state, ${ident}_Event event);
876 void dumpStats(ostream& out) const;
880 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
881 int m_event_counters[${ident}_Event_NUM];
882 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
886 #endif // ${ident}_PROFILER_H
888 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
890 def printProfilerCC(self
, path
):
891 code
= self
.symtab
.codeFormatter()
895 // Auto generated C++ code started by $__file__:$__line__
896 // ${ident}: ${{self.short}}
898 #include "mem/protocol/${ident}_Profiler.hh"
900 ${ident}_Profiler::${ident}_Profiler()
902 for (int state = 0; state < ${ident}_State_NUM; state++) {
903 for (int event = 0; event < ${ident}_Event_NUM; event++) {
904 m_possible[state][event] = false;
905 m_counters[state][event] = 0;
908 for (int event = 0; event < ${ident}_Event_NUM; event++) {
909 m_event_counters[event] = 0;
912 void ${ident}_Profiler::setVersion(int version)
916 void ${ident}_Profiler::clearStats()
918 for (int state = 0; state < ${ident}_State_NUM; state++) {
919 for (int event = 0; event < ${ident}_Event_NUM; event++) {
920 m_counters[state][event] = 0;
924 for (int event = 0; event < ${ident}_Event_NUM; event++) {
925 m_event_counters[event] = 0;
928 void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
930 assert(m_possible[state][event]);
931 m_counters[state][event]++;
932 m_event_counters[event]++;
934 void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event)
936 m_possible[state][event] = true;
938 void ${ident}_Profiler::dumpStats(ostream& out) const
940 out << " --- ${ident} " << m_version << " ---" << endl;
941 out << " - Event Counts -" << endl;
942 for (int event = 0; event < ${ident}_Event_NUM; event++) {
943 int count = m_event_counters[event];
944 out << (${ident}_Event) event << " " << count << endl;
947 out << " - Transitions -" << endl;
948 for (int state = 0; state < ${ident}_State_NUM; state++) {
949 for (int event = 0; event < ${ident}_Event_NUM; event++) {
950 if (m_possible[state][event]) {
951 int count = m_counters[state][event];
952 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count;
963 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
965 # **************************
966 # ******* HTML Files *******
967 # **************************
968 def frameRef(self
, click_href
, click_target
, over_href
, over_target_num
,
970 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
971 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""")
974 def writeHTMLFiles(self
, path
):
975 # Create table with no row hilighted
976 self
.printHTMLTransitions(path
, None)
978 # Generate transition tables
979 for state
in self
.states
.itervalues():
980 self
.printHTMLTransitions(path
, state
)
982 # Generate action descriptions
983 for action
in self
.actions
.itervalues():
984 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
985 code
= html
.createSymbol(action
, "Action")
986 code
.write(path
, name
)
988 # Generate state descriptions
989 for state
in self
.states
.itervalues():
990 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
991 code
= html
.createSymbol(state
, "State")
992 code
.write(path
, name
)
994 # Generate event descriptions
995 for event
in self
.events
.itervalues():
996 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
997 code
= html
.createSymbol(event
, "Event")
998 code
.write(path
, name
)
1000 def printHTMLTransitions(self
, path
, active_state
):
1001 code
= self
.symtab
.codeFormatter()
1004 <HTML><BODY link="blue" vlink="blue">
1006 <H1 align="center">${{html.formatShorthand(self.short)}}:
1009 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1018 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1029 for event
in self
.events
.itervalues():
1030 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1031 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1032 code('<TH bgcolor=white>$ref</TH>')
1036 for state
in self
.states
.itervalues():
1038 if state
== active_state
:
1043 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1044 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1045 text
= html
.formatShorthand(state
.short
)
1046 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1049 <TH bgcolor=$color>$ref</TH>
1052 # -- One column for each event
1053 for event
in self
.events
.itervalues():
1054 trans
= self
.table
.get((state
,event
), None)
1056 # This is the no transition case
1057 if state
== active_state
:
1062 code('<TD bgcolor=$color> </TD>')
1065 next
= trans
.nextState
1066 stall_action
= False
1068 # -- Get the actions
1069 for action
in trans
.actions
:
1070 if action
.ident
== "z_stall" or \
1071 action
.ident
== "zz_recycleMandatoryQueue":
1074 # -- Print out "actions/next-state"
1076 if state
== active_state
:
1081 elif active_state
and next
.ident
== active_state
.ident
:
1083 elif state
== active_state
:
1089 code('<TD bgcolor=$color>')
1090 for action
in trans
.actions
:
1091 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1092 ref
= self
.frameRef(href
, "Status", href
, "1",
1098 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1099 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1100 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1106 if state
== active_state
:
1111 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1112 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1113 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1115 <TH bgcolor=$color>$ref</TH>
1123 for event
in self
.events
.itervalues():
1124 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1125 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1126 code('<TH bgcolor=white>$ref</TH>')
1135 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1137 name
= "%s_table.html" % self
.ident
1138 code
.write(path
, name
)
1140 __all__
= [ "StateMachine" ]