1 # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
2 # Copyright (c) 2009 The Hewlett-Packard Development Company
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 from m5
.util
import orderdict
30 from slicc
.symbols
.Symbol
import Symbol
31 from slicc
.symbols
.Var
import Var
32 import slicc
.generate
.html
as html
35 python_class_map
= {"int": "Int",
36 "std::string": "String",
38 "CacheMemory": "RubyCache",
39 "WireBuffer": "RubyWireBuffer",
40 "Sequencer": "RubySequencer",
41 "DirectoryMemory": "RubyDirectoryMemory",
42 "MemoryControl": "RubyMemoryControl",
43 "DMASequencer": "DMASequencer"
46 class StateMachine(Symbol
):
47 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
48 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
50 self
.config_parameters
= config_parameters
52 for param
in config_parameters
:
54 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
55 "(*m_%s_ptr)" % param
.name
, {}, self
)
57 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
58 "m_%s" % param
.name
, {}, self
)
59 self
.symtab
.registerSym(param
.name
, var
)
61 self
.states
= orderdict()
62 self
.events
= orderdict()
63 self
.actions
= orderdict()
71 self
.message_buffer_names
= []
74 return "[StateMachine: %s]" % self
.ident
76 def addState(self
, state
):
77 assert self
.table
is None
78 self
.states
[state
.ident
] = state
80 def addEvent(self
, event
):
81 assert self
.table
is None
82 self
.events
[event
.ident
] = event
84 def addAction(self
, action
):
85 assert self
.table
is None
87 # Check for duplicate action
88 for other
in self
.actions
.itervalues():
89 if action
.ident
== other
.ident
:
90 action
.warning("Duplicate action definition: %s" % action
.ident
)
91 action
.error("Duplicate action definition: %s" % action
.ident
)
92 if action
.short
== other
.short
:
93 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
94 other
.warning(" shorthand = %s" % other
.short
)
95 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
96 action
.error(" shorthand = %s" % action
.short
)
98 self
.actions
[action
.ident
] = action
100 def addTransition(self
, trans
):
101 assert self
.table
is None
102 self
.transitions
.append(trans
)
104 def addInPort(self
, var
):
105 self
.in_ports
.append(var
)
107 def addFunc(self
, func
):
108 # register func in the symbol table
109 self
.symtab
.registerSym(str(func
), func
)
110 self
.functions
.append(func
)
112 def addObject(self
, obj
):
113 self
.objects
.append(obj
)
115 def addType(self
, type):
116 type_ident
= '%s' % type.c_ident
118 if type_ident
== "%s_TBE" %self
.ident
:
119 if self
.TBEType
!= None:
120 self
.error("Multiple Transaction Buffer types in a " \
124 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
125 if self
.EntryType
!= None:
126 self
.error("Multiple AbstractCacheEntry types in a " \
128 self
.EntryType
= type
130 # Needs to be called before accessing the table
131 def buildTable(self
):
132 assert self
.table
is None
136 for trans
in self
.transitions
:
137 # Track which actions we touch so we know if we use them
138 # all -- really this should be done for all symbols as
139 # part of the symbol table, then only trigger it for
140 # Actions, States, Events, etc.
142 for action
in trans
.actions
:
145 index
= (trans
.state
, trans
.event
)
147 table
[index
].warning("Duplicate transition: %s" % table
[index
])
148 trans
.error("Duplicate transition: %s" % trans
)
151 # Look at all actions to make sure we used them all
152 for action
in self
.actions
.itervalues():
154 error_msg
= "Unused action: %s" % action
.ident
156 error_msg
+= ", " + action
.desc
157 action
.warning(error_msg
)
160 def writeCodeFiles(self
, path
):
161 self
.printControllerPython(path
)
162 self
.printControllerHH(path
)
163 self
.printControllerCC(path
)
164 self
.printCSwitch(path
)
165 self
.printCWakeup(path
)
166 self
.printProfilerCC(path
)
167 self
.printProfilerHH(path
)
168 self
.printProfileDumperCC(path
)
169 self
.printProfileDumperHH(path
)
171 def printControllerPython(self
, path
):
172 code
= self
.symtab
.codeFormatter()
174 py_ident
= "%s_Controller" % ident
175 c_ident
= "%s_Controller" % self
.ident
177 from m5.params import *
178 from m5.SimObject import SimObject
179 from Controller import RubyController
181 class $py_ident(RubyController):
185 for param
in self
.config_parameters
:
187 if param
.default
is not None:
188 dflt_str
= str(param
.default
) + ', '
189 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
190 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
191 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
193 self
.error("Unknown c++ to python class conversion for c++ " \
194 "type: '%s'. Please update the python_class_map " \
195 "in StateMachine.py", param
.type_ast
.type.c_ident
)
197 code
.write(path
, '%s.py' % py_ident
)
200 def printControllerHH(self
, path
):
201 '''Output the method declarations for the class declaration'''
202 code
= self
.symtab
.codeFormatter()
204 c_ident
= "%s_Controller" % self
.ident
206 self
.message_buffer_names
= []
209 /** \\file $c_ident.hh
211 * Auto generated C++ code started by $__file__:$__line__
212 * Created by slicc definition of Module "${{self.short}}"
215 #ifndef __${ident}_CONTROLLER_HH__
216 #define __${ident}_CONTROLLER_HH__
222 #include "mem/protocol/${ident}_ProfileDumper.hh"
223 #include "mem/protocol/${ident}_Profiler.hh"
224 #include "mem/protocol/TransitionResult.hh"
225 #include "mem/protocol/Types.hh"
226 #include "mem/ruby/common/Consumer.hh"
227 #include "mem/ruby/common/Global.hh"
228 #include "mem/ruby/slicc_interface/AbstractController.hh"
229 #include "params/$c_ident.hh"
233 for var
in self
.objects
:
234 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
235 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
236 seen_types
.add(var
.type.ident
)
238 # for adding information to the protocol debug trace
240 extern std::stringstream ${ident}_transitionComment;
242 class $c_ident : public AbstractController
244 // the coherence checker needs to call isBlockExclusive() and isBlockShared()
245 // making the Chip a friend class is an easy way to do this for now
248 typedef ${c_ident}Params Params;
249 $c_ident(const Params *p);
250 static int getNumControllers();
252 MessageBuffer* getMandatoryQueue() const;
253 const int & getVersion() const;
254 const std::string toString() const;
255 const std::string getName() const;
256 void stallBuffer(MessageBuffer* buf, Address addr);
257 void wakeUpBuffers(Address addr);
258 void wakeUpAllBuffers();
259 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
260 void print(std::ostream& out) const;
261 void printConfig(std::ostream& out) const;
263 void printStats(std::ostream& out) const;
265 void blockOnQueue(Address addr, MessageBuffer* port);
266 void unblock(Address addr);
267 void recordCacheTrace(int cntrl, CacheRecorder* tr);
268 Sequencer* getSequencer() const;
275 for param
in self
.config_parameters
:
277 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
279 code('${{param.type_ast.type}} m_${{param.ident}};')
282 int m_number_of_TBEs;
284 TransitionResult doTransition(${ident}_Event event,
287 if self
.EntryType
!= None:
289 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
291 if self
.TBEType
!= None:
293 ${{self.TBEType.c_ident}}* m_tbe_ptr,
297 const Address& addr);
299 TransitionResult doTransitionWorker(${ident}_Event event,
300 ${ident}_State state,
301 ${ident}_State& next_state,
304 if self
.TBEType
!= None:
306 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
308 if self
.EntryType
!= None:
310 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
314 const Address& addr);
317 int m_transitions_per_cycle;
319 int m_recycle_latency;
320 std::map<std::string, std::string> m_cfg;
323 MachineID m_machineID;
325 std::map<Address, MessageBuffer*> m_block_map;
326 typedef std::vector<MessageBuffer*> MsgVecType;
327 typedef std::map< Address, MsgVecType* > WaitingBufType;
328 WaitingBufType m_waiting_buffers;
329 int m_max_in_port_rank;
330 int m_cur_in_port_rank;
331 static ${ident}_ProfileDumper s_profileDumper;
332 ${ident}_Profiler m_profiler;
333 static int m_num_controllers;
335 // Internal functions
338 for func
in self
.functions
:
339 proto
= func
.prototype
343 if self
.EntryType
!= None:
346 // Set and Reset for cache_entry variable
347 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
348 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
351 if self
.TBEType
!= None:
354 // Set and Reset for tbe variable
355 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
356 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
363 if self
.TBEType
!= None and self
.EntryType
!= None:
364 for action
in self
.actions
.itervalues():
365 code('/** \\brief ${{action.desc}} */')
366 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
367 elif self
.TBEType
!= None:
368 for action
in self
.actions
.itervalues():
369 code('/** \\brief ${{action.desc}} */')
370 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
371 elif self
.EntryType
!= None:
372 for action
in self
.actions
.itervalues():
373 code('/** \\brief ${{action.desc}} */')
374 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
376 for action
in self
.actions
.itervalues():
377 code('/** \\brief ${{action.desc}} */')
378 code('void ${{action.ident}}(const Address& addr);')
380 # the controller internal variables
385 for var
in self
.objects
:
386 th
= var
.get("template_hack", "")
387 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
389 if var
.type.ident
== "MessageBuffer":
390 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
394 code('#endif // __${ident}_CONTROLLER_H__')
395 code
.write(path
, '%s.hh' % c_ident
)
397 def printControllerCC(self
, path
):
398 '''Output the actions for performing the actions'''
400 code
= self
.symtab
.codeFormatter()
402 c_ident
= "%s_Controller" % self
.ident
405 /** \\file $c_ident.cc
407 * Auto generated C++ code started by $__file__:$__line__
408 * Created by slicc definition of Module "${{self.short}}"
411 #include <sys/types.h>
418 #include "base/compiler.hh"
419 #include "base/cprintf.hh"
420 #include "debug/RubyGenerated.hh"
421 #include "debug/RubySlicc.hh"
422 #include "mem/protocol/${ident}_Controller.hh"
423 #include "mem/protocol/${ident}_Event.hh"
424 #include "mem/protocol/${ident}_State.hh"
425 #include "mem/protocol/Types.hh"
426 #include "mem/ruby/common/Global.hh"
427 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
428 #include "mem/ruby/system/System.hh"
433 # include object classes
435 for var
in self
.objects
:
436 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
437 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
438 seen_types
.add(var
.type.ident
)
442 ${c_ident}Params::create()
444 return new $c_ident(this);
447 int $c_ident::m_num_controllers = 0;
448 ${ident}_ProfileDumper $c_ident::s_profileDumper;
450 // for adding information to the protocol debug trace
451 stringstream ${ident}_transitionComment;
452 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
454 /** \\brief constructor */
455 $c_ident::$c_ident(const Params *p)
456 : AbstractController(p)
458 m_version = p->version;
459 m_transitions_per_cycle = p->transitions_per_cycle;
460 m_buffer_size = p->buffer_size;
461 m_recycle_latency = p->recycle_latency;
462 m_number_of_TBEs = p->number_of_TBEs;
463 m_is_blocking = false;
467 # max_port_rank is used to size vectors and thus should be one plus the
470 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
471 code(' m_max_in_port_rank = $max_port_rank;')
475 # After initializing the universal machine parameters, initialize the
476 # this machines config parameters. Also detemine if these configuration
477 # params include a sequencer. This information will be used later for
478 # contecting the sequencer back to the L1 cache controller.
480 contains_dma_sequencer
= False
482 for param
in self
.config_parameters
:
483 if param
.name
== "dma_sequencer":
484 contains_dma_sequencer
= True
485 elif re
.compile("sequencer").search(param
.name
):
486 sequencers
.append(param
.name
)
488 code('m_${{param.name}}_ptr = p->${{param.name}};')
490 code('m_${{param.name}} = p->${{param.name}};')
493 # For the l1 cache controller, add the special atomic support which
494 # includes passing the sequencer a pointer to the controller.
496 if self
.ident
== "L1Cache":
498 self
.error("The L1Cache controller must include the sequencer " \
499 "configuration parameter")
501 for seq
in sequencers
:
503 m_${{seq}}_ptr->setController(this);
507 for seq
in sequencers
:
509 m_${{seq}}_ptr->setController(this);
513 # For the DMA controller, pass the sequencer a pointer to the
516 if self
.ident
== "DMA":
517 if not contains_dma_sequencer
:
518 self
.error("The DMA controller must include the sequencer " \
519 "configuration parameter")
522 m_dma_sequencer_ptr->setController(this);
525 code('m_num_controllers++;')
526 for var
in self
.objects
:
527 if var
.ident
.find("mandatoryQueue") >= 0:
528 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
537 MachineType machine_type;
540 m_machineID.type = MachineType_${ident};
541 m_machineID.num = m_version;
543 // initialize objects
544 m_profiler.setVersion(m_version);
545 s_profileDumper.registerProfiler(&m_profiler);
550 for var
in self
.objects
:
552 vid
= "m_%s_ptr" % var
.c_ident
553 if "network" not in var
:
554 # Not a network port object
555 if "primitive" in vtype
:
556 code('$vid = new ${{vtype.c_ident}};')
558 code('(*$vid) = ${{var["default"]}};')
563 code('$vid = ${{var["factory"]}};')
564 elif var
.ident
.find("mandatoryQueue") < 0:
565 th
= var
.get("template_hack", "")
566 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
569 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
570 if expr
.find("TBETable") >= 0:
571 args
= "m_number_of_TBEs"
573 args
= var
.get("constructor_hack", "")
575 code('$expr($args);')
577 code('assert($vid != NULL);')
580 code('*$vid = ${{var["default"]}}; // Object default')
581 elif "default" in vtype
:
582 comment
= "Type %s default" % vtype
.ident
583 code('*$vid = ${{vtype["default"]}}; // $comment')
586 if "ordered" in var
and "trigger_queue" not in var
:
588 code('$vid->setOrdering(${{var["ordered"]}});')
593 code('$vid->setRandomization(${{var["random"]}});')
596 if vtype
.isBuffer
and \
597 "rank" in var
and "trigger_queue" not in var
:
598 code('$vid->setPriority(${{var["rank"]}});')
601 # Network port object
602 network
= var
["network"]
603 ordered
= var
["ordered"]
604 vnet
= var
["virtual_network"]
605 vnet_type
= var
["vnet_type"]
607 assert var
.machine
is not None
609 machine_type = string_to_MachineType("${{var.machine.ident}}");
610 base = MachineType_base_number(machine_type);
611 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
614 code('assert($vid != NULL);')
619 code('$vid->setOrdering(${{var["ordered"]}});')
624 code('$vid->setRandomization(${{var["random"]}});')
628 code('$vid->setPriority(${{var["rank"]}})')
633 if (m_buffer_size > 0) {
634 $vid->resize(m_buffer_size);
638 # set description (may be overriden later by port def)
640 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
645 if "recycle_latency" in var
:
646 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
648 code('$vid->setRecycleLatency(m_recycle_latency);')
651 # Set the queue consumers
653 for port
in self
.in_ports
:
654 code('${{port.code}}.setConsumer(this);')
656 # Set the queue descriptions
658 for port
in self
.in_ports
:
659 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
661 # Initialize the transition profiling
663 for trans
in self
.transitions
:
664 # Figure out if we stall
666 for action
in trans
.actions
:
667 if action
.ident
== "z_stall":
670 # Only possible if it is not a 'z' case
672 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
673 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
674 code('m_profiler.possibleTransition($state, $event);')
679 has_mandatory_q
= False
680 for port
in self
.in_ports
:
681 if port
.code
.find("mandatoryQueue_ptr") >= 0:
682 has_mandatory_q
= True
685 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
690 for param
in self
.config_parameters
:
691 if param
.name
== "sequencer":
692 assert(param
.pointer
)
693 seq_ident
= "m_%s_ptr" % param
.name
697 $c_ident::getNumControllers()
699 return m_num_controllers;
703 $c_ident::getMandatoryQueue() const
709 $c_ident::getSequencer() const
715 $c_ident::getVersion() const
721 $c_ident::toString() const
727 $c_ident::getName() const
733 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
735 if (m_waiting_buffers.count(addr) == 0) {
736 MsgVecType* msgVec = new MsgVecType;
737 msgVec->resize(m_max_in_port_rank, NULL);
738 m_waiting_buffers[addr] = msgVec;
740 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
744 $c_ident::wakeUpBuffers(Address addr)
746 if (m_waiting_buffers.count(addr) > 0) {
748 // Wake up all possible lower rank (i.e. lower priority) buffers that could
749 // be waiting on this message.
751 for (int in_port_rank = m_cur_in_port_rank - 1;
754 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
755 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
758 delete m_waiting_buffers[addr];
759 m_waiting_buffers.erase(addr);
764 $c_ident::wakeUpAllBuffers()
767 // Wake up all possible buffers that could be waiting on any message.
770 std::vector<MsgVecType*> wokeUpMsgVecs;
772 if(m_waiting_buffers.size() > 0) {
773 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
774 buf_iter != m_waiting_buffers.end();
776 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
777 vec_iter != buf_iter->second->end();
779 if (*vec_iter != NULL) {
780 (*vec_iter)->reanalyzeAllMessages();
783 wokeUpMsgVecs.push_back(buf_iter->second);
786 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
787 wb_iter != wokeUpMsgVecs.end();
792 m_waiting_buffers.clear();
797 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
799 m_is_blocking = true;
800 m_block_map[addr] = port;
804 $c_ident::unblock(Address addr)
806 m_block_map.erase(addr);
807 if (m_block_map.size() == 0) {
808 m_is_blocking = false;
813 $c_ident::print(ostream& out) const
815 out << "[$c_ident " << m_version << "]";
819 $c_ident::printConfig(ostream& out) const
821 out << "$c_ident config: " << m_name << endl;
822 out << " version: " << m_version << endl;
823 map<string, string>::const_iterator it;
824 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
825 out << " " << it->first << ": " << it->second << endl;
829 $c_ident::printStats(ostream& out) const
833 # Cache and Memory Controllers have specific profilers associated with
834 # them. Print out these stats before dumping state transition stats.
836 for param
in self
.config_parameters
:
837 if param
.type_ast
.type.ident
== "CacheMemory" or \
838 param
.type_ast
.type.ident
== "DirectoryMemory" or \
839 param
.type_ast
.type.ident
== "MemoryControl":
840 assert(param
.pointer
)
841 code(' m_${{param.ident}}_ptr->printStats(out);')
844 if (m_version == 0) {
845 s_profileDumper.dumpStats(out);
849 void $c_ident::clearStats() {
852 # Cache and Memory Controllers have specific profilers associated with
853 # them. These stats must be cleared too.
855 for param
in self
.config_parameters
:
856 if param
.type_ast
.type.ident
== "CacheMemory" or \
857 param
.type_ast
.type.ident
== "MemoryControl":
858 assert(param
.pointer
)
859 code(' m_${{param.ident}}_ptr->clearStats();')
862 m_profiler.clearStats();
866 if self
.EntryType
!= None:
869 // Set and Reset for cache_entry variable
871 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
873 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
877 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
879 m_cache_entry_ptr = 0;
883 if self
.TBEType
!= None:
886 // Set and Reset for tbe variable
888 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
890 m_tbe_ptr = m_new_tbe;
894 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
903 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
907 # Record cache contents for all associated caches.
910 for param
in self
.config_parameters
:
911 if param
.type_ast
.type.ident
== "CacheMemory":
912 assert(param
.pointer
)
913 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
921 if self
.TBEType
!= None and self
.EntryType
!= None:
922 for action
in self
.actions
.itervalues():
923 if "c_code" not in action
:
927 /** \\brief ${{action.desc}} */
929 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
931 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
932 ${{action["c_code"]}}
936 elif self
.TBEType
!= None:
937 for action
in self
.actions
.itervalues():
938 if "c_code" not in action
:
942 /** \\brief ${{action.desc}} */
944 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
946 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
947 ${{action["c_code"]}}
951 elif self
.EntryType
!= None:
952 for action
in self
.actions
.itervalues():
953 if "c_code" not in action
:
957 /** \\brief ${{action.desc}} */
959 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
961 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
962 ${{action["c_code"]}}
967 for action
in self
.actions
.itervalues():
968 if "c_code" not in action
:
972 /** \\brief ${{action.desc}} */
974 $c_ident::${{action.ident}}(const Address& addr)
976 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
977 ${{action["c_code"]}}
981 for func
in self
.functions
:
982 code(func
.generateCode())
984 code
.write(path
, "%s.cc" % c_ident
)
986 def printCWakeup(self
, path
):
987 '''Output the wakeup loop for the events'''
989 code
= self
.symtab
.codeFormatter()
993 // Auto generated C++ code started by $__file__:$__line__
994 // ${ident}: ${{self.short}}
996 #include <sys/types.h>
1001 #include "base/misc.hh"
1002 #include "debug/RubySlicc.hh"
1003 #include "mem/protocol/${ident}_Controller.hh"
1004 #include "mem/protocol/${ident}_Event.hh"
1005 #include "mem/protocol/${ident}_State.hh"
1006 #include "mem/protocol/Types.hh"
1007 #include "mem/ruby/common/Global.hh"
1008 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
1009 #include "mem/ruby/system/System.hh"
1011 using namespace std;
1014 ${ident}_Controller::wakeup()
1018 // Some cases will put us into an infinite loop without this limit
1019 assert(counter <= m_transitions_per_cycle);
1020 if (counter == m_transitions_per_cycle) {
1021 // Count how often we are fully utilized
1022 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
1024 // Wakeup in another cycle and try again
1025 g_eventQueue_ptr->scheduleEvent(this, 1);
1035 for port
in self
.in_ports
:
1037 code('// ${ident}InPort $port')
1038 if port
.pairs
.has_key("rank"):
1039 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1041 code('m_cur_in_port_rank = 0;')
1042 code('${{port["c_code_in_port"]}}')
1050 break; // If we got this far, we have nothing left todo
1052 // g_eventQueue_ptr->scheduleEvent(this, 1);
1056 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1058 def printCSwitch(self
, path
):
1059 '''Output switch statement for transition table'''
1061 code
= self
.symtab
.codeFormatter()
1065 // Auto generated C++ code started by $__file__:$__line__
1066 // ${ident}: ${{self.short}}
1070 #include "base/misc.hh"
1071 #include "base/trace.hh"
1072 #include "debug/ProtocolTrace.hh"
1073 #include "debug/RubyGenerated.hh"
1074 #include "mem/protocol/${ident}_Controller.hh"
1075 #include "mem/protocol/${ident}_Event.hh"
1076 #include "mem/protocol/${ident}_State.hh"
1077 #include "mem/protocol/Types.hh"
1078 #include "mem/ruby/common/Global.hh"
1079 #include "mem/ruby/system/System.hh"
1081 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1083 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1084 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1087 ${ident}_Controller::doTransition(${ident}_Event event,
1089 if self
.EntryType
!= None:
1091 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1093 if self
.TBEType
!= None:
1095 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1098 const Address &addr)
1101 if self
.TBEType
!= None and self
.EntryType
!= None:
1102 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1103 elif self
.TBEType
!= None:
1104 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1105 elif self
.EntryType
!= None:
1106 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1108 code('${ident}_State state = getState(addr);')
1111 ${ident}_State next_state = state;
1113 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1115 g_eventQueue_ptr->getTime(),
1116 ${ident}_State_to_string(state),
1117 ${ident}_Event_to_string(event),
1120 TransitionResult result =
1122 if self
.TBEType
!= None and self
.EntryType
!= None:
1123 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1124 elif self
.TBEType
!= None:
1125 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1126 elif self
.EntryType
!= None:
1127 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1129 code('doTransitionWorker(event, state, next_state, addr);')
1132 if (result == TransitionResult_Valid) {
1133 DPRINTF(RubyGenerated, "next_state: %s\\n",
1134 ${ident}_State_to_string(next_state));
1135 m_profiler.countTransition(state, event);
1136 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1137 curTick(), m_version, "${ident}",
1138 ${ident}_Event_to_string(event),
1139 ${ident}_State_to_string(state),
1140 ${ident}_State_to_string(next_state),
1141 addr, GET_TRANSITION_COMMENT());
1143 CLEAR_TRANSITION_COMMENT();
1145 if self
.TBEType
!= None and self
.EntryType
!= None:
1146 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1147 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1148 elif self
.TBEType
!= None:
1149 code('setState(m_tbe_ptr, addr, next_state);')
1150 code('setAccessPermission(addr, next_state);')
1151 elif self
.EntryType
!= None:
1152 code('setState(m_cache_entry_ptr, addr, next_state);')
1153 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1155 code('setState(addr, next_state);')
1156 code('setAccessPermission(addr, next_state);')
1159 } else if (result == TransitionResult_ResourceStall) {
1160 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1161 curTick(), m_version, "${ident}",
1162 ${ident}_Event_to_string(event),
1163 ${ident}_State_to_string(state),
1164 ${ident}_State_to_string(next_state),
1165 addr, "Resource Stall");
1166 } else if (result == TransitionResult_ProtocolStall) {
1167 DPRINTF(RubyGenerated, "stalling\\n");
1168 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1169 curTick(), m_version, "${ident}",
1170 ${ident}_Event_to_string(event),
1171 ${ident}_State_to_string(state),
1172 ${ident}_State_to_string(next_state),
1173 addr, "Protocol Stall");
1180 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1181 ${ident}_State state,
1182 ${ident}_State& next_state,
1185 if self
.TBEType
!= None:
1187 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1189 if self
.EntryType
!= None:
1191 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1194 const Address& addr)
1196 switch(HASH_FUN(state, event)) {
1199 # This map will allow suppress generating duplicate code
1202 for trans
in self
.transitions
:
1203 case_string
= "%s_State_%s, %s_Event_%s" % \
1204 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1206 case
= self
.symtab
.codeFormatter()
1207 # Only set next_state if it changes
1208 if trans
.state
!= trans
.nextState
:
1209 ns_ident
= trans
.nextState
.ident
1210 case('next_state = ${ident}_State_${ns_ident};')
1212 actions
= trans
.actions
1214 # Check for resources
1216 res
= trans
.resources
1217 for key
,val
in res
.iteritems():
1218 if key
.type.ident
!= "DNUCAStopTable":
1220 if (!%s.areNSlotsAvailable(%s))
1221 return TransitionResult_ResourceStall;
1222 ''' % (key
.code
, val
)
1223 case_sorter
.append(val
)
1226 # Emit the code sequences in a sorted order. This makes the
1227 # output deterministic (without this the output order can vary
1228 # since Map's keys() on a vector of pointers is not deterministic
1229 for c
in sorted(case_sorter
):
1232 # Figure out if we stall
1234 for action
in actions
:
1235 if action
.ident
== "z_stall":
1240 case('return TransitionResult_ProtocolStall;')
1242 if self
.TBEType
!= None and self
.EntryType
!= None:
1243 for action
in actions
:
1244 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1245 elif self
.TBEType
!= None:
1246 for action
in actions
:
1247 case('${{action.ident}}(m_tbe_ptr, addr);')
1248 elif self
.EntryType
!= None:
1249 for action
in actions
:
1250 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1252 for action
in actions
:
1253 case('${{action.ident}}(addr);')
1254 case('return TransitionResult_Valid;')
1258 # Look to see if this transition code is unique.
1259 if case
not in cases
:
1262 cases
[case
].append(case_string
)
1264 # Walk through all of the unique code blocks and spit out the
1265 # corresponding case statement elements
1266 for case
,transitions
in cases
.iteritems():
1267 # Iterative over all the multiple transitions that share
1269 for trans
in transitions
:
1270 code(' case HASH_FUN($trans):')
1275 fatal("Invalid transition\\n"
1276 "%s time: %d addr: %s event: %s state: %s\\n",
1277 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1279 return TransitionResult_Valid;
1282 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1284 def printProfileDumperHH(self
, path
):
1285 code
= self
.symtab
.codeFormatter()
1289 // Auto generated C++ code started by $__file__:$__line__
1290 // ${ident}: ${{self.short}}
1292 #ifndef __${ident}_PROFILE_DUMPER_HH__
1293 #define __${ident}_PROFILE_DUMPER_HH__
1299 #include "${ident}_Event.hh"
1300 #include "${ident}_Profiler.hh"
1302 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1304 class ${ident}_ProfileDumper
1307 ${ident}_ProfileDumper();
1308 void registerProfiler(${ident}_Profiler* profiler);
1309 void dumpStats(std::ostream& out) const;
1312 ${ident}_profilers m_profilers;
1315 #endif // __${ident}_PROFILE_DUMPER_HH__
1317 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1319 def printProfileDumperCC(self
, path
):
1320 code
= self
.symtab
.codeFormatter()
1324 // Auto generated C++ code started by $__file__:$__line__
1325 // ${ident}: ${{self.short}}
1327 #include "mem/protocol/${ident}_ProfileDumper.hh"
1329 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1334 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1336 m_profilers.push_back(profiler);
1340 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1342 out << " --- ${ident} ---\\n";
1343 out << " - Event Counts -\\n";
1344 for (${ident}_Event event = ${ident}_Event_FIRST;
1345 event < ${ident}_Event_NUM;
1347 out << (${ident}_Event) event << " [";
1349 for (int i = 0; i < m_profilers.size(); i++) {
1350 out << m_profilers[i]->getEventCount(event) << " ";
1351 total += m_profilers[i]->getEventCount(event);
1353 out << "] " << total << "\\n";
1356 out << " - Transitions -\\n";
1357 for (${ident}_State state = ${ident}_State_FIRST;
1358 state < ${ident}_State_NUM;
1360 for (${ident}_Event event = ${ident}_Event_FIRST;
1361 event < ${ident}_Event_NUM;
1363 if (m_profilers[0]->isPossible(state, event)) {
1364 out << (${ident}_State) state << " "
1365 << (${ident}_Event) event << " [";
1367 for (int i = 0; i < m_profilers.size(); i++) {
1368 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1369 total += m_profilers[i]->getTransitionCount(state, event);
1371 out << "] " << total << "\\n";
1378 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1380 def printProfilerHH(self
, path
):
1381 code
= self
.symtab
.codeFormatter()
1385 // Auto generated C++ code started by $__file__:$__line__
1386 // ${ident}: ${{self.short}}
1388 #ifndef __${ident}_PROFILER_HH__
1389 #define __${ident}_PROFILER_HH__
1394 #include "mem/protocol/${ident}_Event.hh"
1395 #include "mem/protocol/${ident}_State.hh"
1396 #include "mem/ruby/common/TypeDefines.hh"
1398 class ${ident}_Profiler
1401 ${ident}_Profiler();
1402 void setVersion(int version);
1403 void countTransition(${ident}_State state, ${ident}_Event event);
1404 void possibleTransition(${ident}_State state, ${ident}_Event event);
1405 uint64 getEventCount(${ident}_Event event);
1406 bool isPossible(${ident}_State state, ${ident}_Event event);
1407 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1411 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1412 int m_event_counters[${ident}_Event_NUM];
1413 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1417 #endif // __${ident}_PROFILER_HH__
1419 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1421 def printProfilerCC(self
, path
):
1422 code
= self
.symtab
.codeFormatter()
1426 // Auto generated C++ code started by $__file__:$__line__
1427 // ${ident}: ${{self.short}}
1431 #include "mem/protocol/${ident}_Profiler.hh"
1433 ${ident}_Profiler::${ident}_Profiler()
1435 for (int state = 0; state < ${ident}_State_NUM; state++) {
1436 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1437 m_possible[state][event] = false;
1438 m_counters[state][event] = 0;
1441 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1442 m_event_counters[event] = 0;
1447 ${ident}_Profiler::setVersion(int version)
1449 m_version = version;
1453 ${ident}_Profiler::clearStats()
1455 for (int state = 0; state < ${ident}_State_NUM; state++) {
1456 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1457 m_counters[state][event] = 0;
1461 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1462 m_event_counters[event] = 0;
1466 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1468 assert(m_possible[state][event]);
1469 m_counters[state][event]++;
1470 m_event_counters[event]++;
1473 ${ident}_Profiler::possibleTransition(${ident}_State state,
1474 ${ident}_Event event)
1476 m_possible[state][event] = true;
1480 ${ident}_Profiler::getEventCount(${ident}_Event event)
1482 return m_event_counters[event];
1486 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1488 return m_possible[state][event];
1492 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1493 ${ident}_Event event)
1495 return m_counters[state][event];
1499 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1501 # **************************
1502 # ******* HTML Files *******
1503 # **************************
1504 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1505 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1506 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1507 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1508 parent.frames[$over_num].location='$over_href'
1510 ${{html.formatShorthand(text)}}
1514 def writeHTMLFiles(self
, path
):
1515 # Create table with no row hilighted
1516 self
.printHTMLTransitions(path
, None)
1518 # Generate transition tables
1519 for state
in self
.states
.itervalues():
1520 self
.printHTMLTransitions(path
, state
)
1522 # Generate action descriptions
1523 for action
in self
.actions
.itervalues():
1524 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1525 code
= html
.createSymbol(action
, "Action")
1526 code
.write(path
, name
)
1528 # Generate state descriptions
1529 for state
in self
.states
.itervalues():
1530 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1531 code
= html
.createSymbol(state
, "State")
1532 code
.write(path
, name
)
1534 # Generate event descriptions
1535 for event
in self
.events
.itervalues():
1536 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1537 code
= html
.createSymbol(event
, "Event")
1538 code
.write(path
, name
)
1540 def printHTMLTransitions(self
, path
, active_state
):
1541 code
= self
.symtab
.codeFormatter()
1545 <BODY link="blue" vlink="blue">
1547 <H1 align="center">${{html.formatShorthand(self.short)}}:
1550 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1559 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1570 for event
in self
.events
.itervalues():
1571 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1572 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1573 code('<TH bgcolor=white>$ref</TH>')
1577 for state
in self
.states
.itervalues():
1579 if state
== active_state
:
1584 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1585 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1586 text
= html
.formatShorthand(state
.short
)
1587 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1590 <TH bgcolor=$color>$ref</TH>
1593 # -- One column for each event
1594 for event
in self
.events
.itervalues():
1595 trans
= self
.table
.get((state
,event
), None)
1597 # This is the no transition case
1598 if state
== active_state
:
1603 code('<TD bgcolor=$color> </TD>')
1606 next
= trans
.nextState
1607 stall_action
= False
1609 # -- Get the actions
1610 for action
in trans
.actions
:
1611 if action
.ident
== "z_stall" or \
1612 action
.ident
== "zz_recycleMandatoryQueue":
1615 # -- Print out "actions/next-state"
1617 if state
== active_state
:
1622 elif active_state
and next
.ident
== active_state
.ident
:
1624 elif state
== active_state
:
1629 code('<TD bgcolor=$color>')
1630 for action
in trans
.actions
:
1631 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1632 ref
= self
.frameRef(href
, "Status", href
, "1",
1638 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1639 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1640 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1645 if state
== active_state
:
1650 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1651 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1652 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1654 <TH bgcolor=$color>$ref</TH>
1663 for event
in self
.events
.itervalues():
1664 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1665 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1666 code('<TH bgcolor=white>$ref</TH>')
1675 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1677 name
= "%s_table.html" % self
.ident
1678 code
.write(path
, name
)
1680 __all__
= [ "StateMachine" ]