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 m5::hash_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}}"
415 #include "base/compiler.hh"
416 #include "base/cprintf.hh"
417 #include "debug/RubyGenerated.hh"
418 #include "debug/RubySlicc.hh"
419 #include "mem/protocol/${ident}_Controller.hh"
420 #include "mem/protocol/${ident}_Event.hh"
421 #include "mem/protocol/${ident}_State.hh"
422 #include "mem/protocol/Types.hh"
423 #include "mem/ruby/common/Global.hh"
424 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
425 #include "mem/ruby/system/System.hh"
430 # include object classes
432 for var
in self
.objects
:
433 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
434 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
435 seen_types
.add(var
.type.ident
)
439 ${c_ident}Params::create()
441 return new $c_ident(this);
444 int $c_ident::m_num_controllers = 0;
445 ${ident}_ProfileDumper $c_ident::s_profileDumper;
447 // for adding information to the protocol debug trace
448 stringstream ${ident}_transitionComment;
449 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
451 /** \\brief constructor */
452 $c_ident::$c_ident(const Params *p)
453 : AbstractController(p)
455 m_version = p->version;
456 m_transitions_per_cycle = p->transitions_per_cycle;
457 m_buffer_size = p->buffer_size;
458 m_recycle_latency = p->recycle_latency;
459 m_number_of_TBEs = p->number_of_TBEs;
460 m_is_blocking = false;
464 # max_port_rank is used to size vectors and thus should be one plus the
467 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
468 code(' m_max_in_port_rank = $max_port_rank;')
472 # After initializing the universal machine parameters, initialize the
473 # this machines config parameters. Also detemine if these configuration
474 # params include a sequencer. This information will be used later for
475 # contecting the sequencer back to the L1 cache controller.
477 contains_dma_sequencer
= False
479 for param
in self
.config_parameters
:
480 if param
.name
== "dma_sequencer":
481 contains_dma_sequencer
= True
482 elif re
.compile("sequencer").search(param
.name
):
483 sequencers
.append(param
.name
)
485 code('m_${{param.name}}_ptr = p->${{param.name}};')
487 code('m_${{param.name}} = p->${{param.name}};')
490 # For the l1 cache controller, add the special atomic support which
491 # includes passing the sequencer a pointer to the controller.
493 if self
.ident
== "L1Cache":
495 self
.error("The L1Cache controller must include the sequencer " \
496 "configuration parameter")
498 for seq
in sequencers
:
500 m_${{seq}}_ptr->setController(this);
504 for seq
in sequencers
:
506 m_${{seq}}_ptr->setController(this);
510 # For the DMA controller, pass the sequencer a pointer to the
513 if self
.ident
== "DMA":
514 if not contains_dma_sequencer
:
515 self
.error("The DMA controller must include the sequencer " \
516 "configuration parameter")
519 m_dma_sequencer_ptr->setController(this);
522 code('m_num_controllers++;')
523 for var
in self
.objects
:
524 if var
.ident
.find("mandatoryQueue") >= 0:
525 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
534 MachineType machine_type;
537 m_machineID.type = MachineType_${ident};
538 m_machineID.num = m_version;
540 // initialize objects
541 m_profiler.setVersion(m_version);
542 s_profileDumper.registerProfiler(&m_profiler);
547 for var
in self
.objects
:
549 vid
= "m_%s_ptr" % var
.c_ident
550 if "network" not in var
:
551 # Not a network port object
552 if "primitive" in vtype
:
553 code('$vid = new ${{vtype.c_ident}};')
555 code('(*$vid) = ${{var["default"]}};')
560 code('$vid = ${{var["factory"]}};')
561 elif var
.ident
.find("mandatoryQueue") < 0:
562 th
= var
.get("template_hack", "")
563 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
566 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
567 if expr
.find("TBETable") >= 0:
568 args
= "m_number_of_TBEs"
570 args
= var
.get("constructor_hack", "")
572 code('$expr($args);')
574 code('assert($vid != NULL);')
577 code('*$vid = ${{var["default"]}}; // Object default')
578 elif "default" in vtype
:
579 comment
= "Type %s default" % vtype
.ident
580 code('*$vid = ${{vtype["default"]}}; // $comment')
583 if "ordered" in var
and "trigger_queue" not in var
:
585 code('$vid->setOrdering(${{var["ordered"]}});')
590 code('$vid->setRandomization(${{var["random"]}});')
593 if vtype
.isBuffer
and \
594 "rank" in var
and "trigger_queue" not in var
:
595 code('$vid->setPriority(${{var["rank"]}});')
598 # Network port object
599 network
= var
["network"]
600 ordered
= var
["ordered"]
601 vnet
= var
["virtual_network"]
602 vnet_type
= var
["vnet_type"]
604 assert var
.machine
is not None
606 machine_type = string_to_MachineType("${{var.machine.ident}}");
607 base = MachineType_base_number(machine_type);
608 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
611 code('assert($vid != NULL);')
616 code('$vid->setOrdering(${{var["ordered"]}});')
621 code('$vid->setRandomization(${{var["random"]}});')
625 code('$vid->setPriority(${{var["rank"]}})')
630 if (m_buffer_size > 0) {
631 $vid->resize(m_buffer_size);
635 # set description (may be overriden later by port def)
637 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
642 if "recycle_latency" in var
:
643 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
645 code('$vid->setRecycleLatency(m_recycle_latency);')
648 # Set the queue consumers
650 for port
in self
.in_ports
:
651 code('${{port.code}}.setConsumer(this);')
653 # Set the queue descriptions
655 for port
in self
.in_ports
:
656 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
658 # Initialize the transition profiling
660 for trans
in self
.transitions
:
661 # Figure out if we stall
663 for action
in trans
.actions
:
664 if action
.ident
== "z_stall":
667 # Only possible if it is not a 'z' case
669 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
670 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
671 code('m_profiler.possibleTransition($state, $event);')
676 has_mandatory_q
= False
677 for port
in self
.in_ports
:
678 if port
.code
.find("mandatoryQueue_ptr") >= 0:
679 has_mandatory_q
= True
682 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
687 for param
in self
.config_parameters
:
688 if param
.name
== "sequencer":
689 assert(param
.pointer
)
690 seq_ident
= "m_%s_ptr" % param
.name
694 $c_ident::getNumControllers()
696 return m_num_controllers;
700 $c_ident::getMandatoryQueue() const
706 $c_ident::getSequencer() const
712 $c_ident::getVersion() const
718 $c_ident::toString() const
724 $c_ident::getName() const
730 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
732 if (m_waiting_buffers.count(addr) == 0) {
733 MsgVecType* msgVec = new MsgVecType;
734 msgVec->resize(m_max_in_port_rank, NULL);
735 m_waiting_buffers[addr] = msgVec;
737 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
741 $c_ident::wakeUpBuffers(Address addr)
743 if (m_waiting_buffers.count(addr) > 0) {
745 // Wake up all possible lower rank (i.e. lower priority) buffers that could
746 // be waiting on this message.
748 for (int in_port_rank = m_cur_in_port_rank - 1;
751 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
752 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
755 delete m_waiting_buffers[addr];
756 m_waiting_buffers.erase(addr);
761 $c_ident::wakeUpAllBuffers()
764 // Wake up all possible buffers that could be waiting on any message.
767 std::vector<MsgVecType*> wokeUpMsgVecs;
769 if(m_waiting_buffers.size() > 0) {
770 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
771 buf_iter != m_waiting_buffers.end();
773 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
774 vec_iter != buf_iter->second->end();
776 if (*vec_iter != NULL) {
777 (*vec_iter)->reanalyzeAllMessages();
780 wokeUpMsgVecs.push_back(buf_iter->second);
783 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
784 wb_iter != wokeUpMsgVecs.end();
789 m_waiting_buffers.clear();
794 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
796 m_is_blocking = true;
797 m_block_map[addr] = port;
801 $c_ident::unblock(Address addr)
803 m_block_map.erase(addr);
804 if (m_block_map.size() == 0) {
805 m_is_blocking = false;
810 $c_ident::print(ostream& out) const
812 out << "[$c_ident " << m_version << "]";
816 $c_ident::printConfig(ostream& out) const
818 out << "$c_ident config: " << m_name << endl;
819 out << " version: " << m_version << endl;
820 map<string, string>::const_iterator it;
821 for (it = m_cfg.begin(); it != m_cfg.end(); it++)
822 out << " " << it->first << ": " << it->second << endl;
826 $c_ident::printStats(ostream& out) const
830 # Cache and Memory Controllers have specific profilers associated with
831 # them. Print out these stats before dumping state transition stats.
833 for param
in self
.config_parameters
:
834 if param
.type_ast
.type.ident
== "CacheMemory" or \
835 param
.type_ast
.type.ident
== "DirectoryMemory" or \
836 param
.type_ast
.type.ident
== "MemoryControl":
837 assert(param
.pointer
)
838 code(' m_${{param.ident}}_ptr->printStats(out);')
841 if (m_version == 0) {
842 s_profileDumper.dumpStats(out);
846 void $c_ident::clearStats() {
849 # Cache and Memory Controllers have specific profilers associated with
850 # them. These stats must be cleared too.
852 for param
in self
.config_parameters
:
853 if param
.type_ast
.type.ident
== "CacheMemory" or \
854 param
.type_ast
.type.ident
== "MemoryControl":
855 assert(param
.pointer
)
856 code(' m_${{param.ident}}_ptr->clearStats();')
859 m_profiler.clearStats();
863 if self
.EntryType
!= None:
866 // Set and Reset for cache_entry variable
868 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
870 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
874 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
876 m_cache_entry_ptr = 0;
880 if self
.TBEType
!= None:
883 // Set and Reset for tbe variable
885 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
887 m_tbe_ptr = m_new_tbe;
891 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
900 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
904 # Record cache contents for all associated caches.
907 for param
in self
.config_parameters
:
908 if param
.type_ast
.type.ident
== "CacheMemory":
909 assert(param
.pointer
)
910 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
918 if self
.TBEType
!= None and self
.EntryType
!= None:
919 for action
in self
.actions
.itervalues():
920 if "c_code" not in action
:
924 /** \\brief ${{action.desc}} */
926 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
929 ${{action["c_code"]}}
933 elif self
.TBEType
!= None:
934 for action
in self
.actions
.itervalues():
935 if "c_code" not in action
:
939 /** \\brief ${{action.desc}} */
941 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
944 ${{action["c_code"]}}
948 elif self
.EntryType
!= None:
949 for action
in self
.actions
.itervalues():
950 if "c_code" not in action
:
954 /** \\brief ${{action.desc}} */
956 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
958 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
959 ${{action["c_code"]}}
964 for action
in self
.actions
.itervalues():
965 if "c_code" not in action
:
969 /** \\brief ${{action.desc}} */
971 $c_ident::${{action.ident}}(const Address& addr)
973 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
974 ${{action["c_code"]}}
978 for func
in self
.functions
:
979 code(func
.generateCode())
981 code
.write(path
, "%s.cc" % c_ident
)
983 def printCWakeup(self
, path
):
984 '''Output the wakeup loop for the events'''
986 code
= self
.symtab
.codeFormatter()
990 // Auto generated C++ code started by $__file__:$__line__
991 // ${ident}: ${{self.short}}
995 #include "base/misc.hh"
996 #include "debug/RubySlicc.hh"
997 #include "mem/protocol/${ident}_Controller.hh"
998 #include "mem/protocol/${ident}_Event.hh"
999 #include "mem/protocol/${ident}_State.hh"
1000 #include "mem/protocol/Types.hh"
1001 #include "mem/ruby/common/Global.hh"
1002 #include "mem/ruby/slicc_interface/RubySlicc_includes.hh"
1003 #include "mem/ruby/system/System.hh"
1005 using namespace std;
1008 ${ident}_Controller::wakeup()
1012 // Some cases will put us into an infinite loop without this limit
1013 assert(counter <= m_transitions_per_cycle);
1014 if (counter == m_transitions_per_cycle) {
1015 // Count how often we are fully utilized
1016 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
1018 // Wakeup in another cycle and try again
1019 g_eventQueue_ptr->scheduleEvent(this, 1);
1029 for port
in self
.in_ports
:
1031 code('// ${ident}InPort $port')
1032 if port
.pairs
.has_key("rank"):
1033 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1035 code('m_cur_in_port_rank = 0;')
1036 code('${{port["c_code_in_port"]}}')
1044 break; // If we got this far, we have nothing left todo
1046 // g_eventQueue_ptr->scheduleEvent(this, 1);
1050 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1052 def printCSwitch(self
, path
):
1053 '''Output switch statement for transition table'''
1055 code
= self
.symtab
.codeFormatter()
1059 // Auto generated C++ code started by $__file__:$__line__
1060 // ${ident}: ${{self.short}}
1064 #include "base/misc.hh"
1065 #include "base/trace.hh"
1066 #include "debug/ProtocolTrace.hh"
1067 #include "debug/RubyGenerated.hh"
1068 #include "mem/protocol/${ident}_Controller.hh"
1069 #include "mem/protocol/${ident}_Event.hh"
1070 #include "mem/protocol/${ident}_State.hh"
1071 #include "mem/protocol/Types.hh"
1072 #include "mem/ruby/common/Global.hh"
1073 #include "mem/ruby/system/System.hh"
1075 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1077 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1078 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1081 ${ident}_Controller::doTransition(${ident}_Event event,
1083 if self
.EntryType
!= None:
1085 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1087 if self
.TBEType
!= None:
1089 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1092 const Address &addr)
1095 if self
.TBEType
!= None and self
.EntryType
!= None:
1096 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1097 elif self
.TBEType
!= None:
1098 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1099 elif self
.EntryType
!= None:
1100 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1102 code('${ident}_State state = getState(addr);')
1105 ${ident}_State next_state = state;
1107 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1109 g_eventQueue_ptr->getTime(),
1110 ${ident}_State_to_string(state),
1111 ${ident}_Event_to_string(event),
1114 TransitionResult result =
1116 if self
.TBEType
!= None and self
.EntryType
!= None:
1117 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1118 elif self
.TBEType
!= None:
1119 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1120 elif self
.EntryType
!= None:
1121 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1123 code('doTransitionWorker(event, state, next_state, addr);')
1126 if (result == TransitionResult_Valid) {
1127 DPRINTF(RubyGenerated, "next_state: %s\\n",
1128 ${ident}_State_to_string(next_state));
1129 m_profiler.countTransition(state, event);
1130 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1131 curTick(), m_version, "${ident}",
1132 ${ident}_Event_to_string(event),
1133 ${ident}_State_to_string(state),
1134 ${ident}_State_to_string(next_state),
1135 addr, GET_TRANSITION_COMMENT());
1137 CLEAR_TRANSITION_COMMENT();
1139 if self
.TBEType
!= None and self
.EntryType
!= None:
1140 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1141 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1142 elif self
.TBEType
!= None:
1143 code('setState(m_tbe_ptr, addr, next_state);')
1144 code('setAccessPermission(addr, next_state);')
1145 elif self
.EntryType
!= None:
1146 code('setState(m_cache_entry_ptr, addr, next_state);')
1147 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1149 code('setState(addr, next_state);')
1150 code('setAccessPermission(addr, next_state);')
1153 } else if (result == TransitionResult_ResourceStall) {
1154 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1155 curTick(), m_version, "${ident}",
1156 ${ident}_Event_to_string(event),
1157 ${ident}_State_to_string(state),
1158 ${ident}_State_to_string(next_state),
1159 addr, "Resource Stall");
1160 } else if (result == TransitionResult_ProtocolStall) {
1161 DPRINTF(RubyGenerated, "stalling\\n");
1162 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1163 curTick(), m_version, "${ident}",
1164 ${ident}_Event_to_string(event),
1165 ${ident}_State_to_string(state),
1166 ${ident}_State_to_string(next_state),
1167 addr, "Protocol Stall");
1174 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1175 ${ident}_State state,
1176 ${ident}_State& next_state,
1179 if self
.TBEType
!= None:
1181 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1183 if self
.EntryType
!= None:
1185 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1188 const Address& addr)
1190 switch(HASH_FUN(state, event)) {
1193 # This map will allow suppress generating duplicate code
1196 for trans
in self
.transitions
:
1197 case_string
= "%s_State_%s, %s_Event_%s" % \
1198 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1200 case
= self
.symtab
.codeFormatter()
1201 # Only set next_state if it changes
1202 if trans
.state
!= trans
.nextState
:
1203 ns_ident
= trans
.nextState
.ident
1204 case('next_state = ${ident}_State_${ns_ident};')
1206 actions
= trans
.actions
1208 # Check for resources
1210 res
= trans
.resources
1211 for key
,val
in res
.iteritems():
1212 if key
.type.ident
!= "DNUCAStopTable":
1214 if (!%s.areNSlotsAvailable(%s))
1215 return TransitionResult_ResourceStall;
1216 ''' % (key
.code
, val
)
1217 case_sorter
.append(val
)
1220 # Emit the code sequences in a sorted order. This makes the
1221 # output deterministic (without this the output order can vary
1222 # since Map's keys() on a vector of pointers is not deterministic
1223 for c
in sorted(case_sorter
):
1226 # Figure out if we stall
1228 for action
in actions
:
1229 if action
.ident
== "z_stall":
1234 case('return TransitionResult_ProtocolStall;')
1236 if self
.TBEType
!= None and self
.EntryType
!= None:
1237 for action
in actions
:
1238 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1239 elif self
.TBEType
!= None:
1240 for action
in actions
:
1241 case('${{action.ident}}(m_tbe_ptr, addr);')
1242 elif self
.EntryType
!= None:
1243 for action
in actions
:
1244 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1246 for action
in actions
:
1247 case('${{action.ident}}(addr);')
1248 case('return TransitionResult_Valid;')
1252 # Look to see if this transition code is unique.
1253 if case
not in cases
:
1256 cases
[case
].append(case_string
)
1258 # Walk through all of the unique code blocks and spit out the
1259 # corresponding case statement elements
1260 for case
,transitions
in cases
.iteritems():
1261 # Iterative over all the multiple transitions that share
1263 for trans
in transitions
:
1264 code(' case HASH_FUN($trans):')
1269 fatal("Invalid transition\\n"
1270 "%s time: %d addr: %s event: %s state: %s\\n",
1271 name(), g_eventQueue_ptr->getTime(), addr, event, state);
1273 return TransitionResult_Valid;
1276 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1278 def printProfileDumperHH(self
, path
):
1279 code
= self
.symtab
.codeFormatter()
1283 // Auto generated C++ code started by $__file__:$__line__
1284 // ${ident}: ${{self.short}}
1286 #ifndef __${ident}_PROFILE_DUMPER_HH__
1287 #define __${ident}_PROFILE_DUMPER_HH__
1293 #include "${ident}_Event.hh"
1294 #include "${ident}_Profiler.hh"
1296 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1298 class ${ident}_ProfileDumper
1301 ${ident}_ProfileDumper();
1302 void registerProfiler(${ident}_Profiler* profiler);
1303 void dumpStats(std::ostream& out) const;
1306 ${ident}_profilers m_profilers;
1309 #endif // __${ident}_PROFILE_DUMPER_HH__
1311 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1313 def printProfileDumperCC(self
, path
):
1314 code
= self
.symtab
.codeFormatter()
1318 // Auto generated C++ code started by $__file__:$__line__
1319 // ${ident}: ${{self.short}}
1321 #include "mem/protocol/${ident}_ProfileDumper.hh"
1323 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1328 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1330 m_profilers.push_back(profiler);
1334 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1336 out << " --- ${ident} ---\\n";
1337 out << " - Event Counts -\\n";
1338 for (${ident}_Event event = ${ident}_Event_FIRST;
1339 event < ${ident}_Event_NUM;
1341 out << (${ident}_Event) event << " [";
1343 for (int i = 0; i < m_profilers.size(); i++) {
1344 out << m_profilers[i]->getEventCount(event) << " ";
1345 total += m_profilers[i]->getEventCount(event);
1347 out << "] " << total << "\\n";
1350 out << " - Transitions -\\n";
1351 for (${ident}_State state = ${ident}_State_FIRST;
1352 state < ${ident}_State_NUM;
1354 for (${ident}_Event event = ${ident}_Event_FIRST;
1355 event < ${ident}_Event_NUM;
1357 if (m_profilers[0]->isPossible(state, event)) {
1358 out << (${ident}_State) state << " "
1359 << (${ident}_Event) event << " [";
1361 for (int i = 0; i < m_profilers.size(); i++) {
1362 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1363 total += m_profilers[i]->getTransitionCount(state, event);
1365 out << "] " << total << "\\n";
1372 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1374 def printProfilerHH(self
, path
):
1375 code
= self
.symtab
.codeFormatter()
1379 // Auto generated C++ code started by $__file__:$__line__
1380 // ${ident}: ${{self.short}}
1382 #ifndef __${ident}_PROFILER_HH__
1383 #define __${ident}_PROFILER_HH__
1388 #include "mem/protocol/${ident}_Event.hh"
1389 #include "mem/protocol/${ident}_State.hh"
1390 #include "mem/ruby/common/TypeDefines.hh"
1392 class ${ident}_Profiler
1395 ${ident}_Profiler();
1396 void setVersion(int version);
1397 void countTransition(${ident}_State state, ${ident}_Event event);
1398 void possibleTransition(${ident}_State state, ${ident}_Event event);
1399 uint64 getEventCount(${ident}_Event event);
1400 bool isPossible(${ident}_State state, ${ident}_Event event);
1401 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1405 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1406 int m_event_counters[${ident}_Event_NUM];
1407 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1411 #endif // __${ident}_PROFILER_HH__
1413 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1415 def printProfilerCC(self
, path
):
1416 code
= self
.symtab
.codeFormatter()
1420 // Auto generated C++ code started by $__file__:$__line__
1421 // ${ident}: ${{self.short}}
1425 #include "mem/protocol/${ident}_Profiler.hh"
1427 ${ident}_Profiler::${ident}_Profiler()
1429 for (int state = 0; state < ${ident}_State_NUM; state++) {
1430 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1431 m_possible[state][event] = false;
1432 m_counters[state][event] = 0;
1435 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1436 m_event_counters[event] = 0;
1441 ${ident}_Profiler::setVersion(int version)
1443 m_version = version;
1447 ${ident}_Profiler::clearStats()
1449 for (int state = 0; state < ${ident}_State_NUM; state++) {
1450 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1451 m_counters[state][event] = 0;
1455 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1456 m_event_counters[event] = 0;
1460 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1462 assert(m_possible[state][event]);
1463 m_counters[state][event]++;
1464 m_event_counters[event]++;
1467 ${ident}_Profiler::possibleTransition(${ident}_State state,
1468 ${ident}_Event event)
1470 m_possible[state][event] = true;
1474 ${ident}_Profiler::getEventCount(${ident}_Event event)
1476 return m_event_counters[event];
1480 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1482 return m_possible[state][event];
1486 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1487 ${ident}_Event event)
1489 return m_counters[state][event];
1493 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1495 # **************************
1496 # ******* HTML Files *******
1497 # **************************
1498 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1499 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1500 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1501 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1502 parent.frames[$over_num].location='$over_href'
1504 ${{html.formatShorthand(text)}}
1508 def writeHTMLFiles(self
, path
):
1509 # Create table with no row hilighted
1510 self
.printHTMLTransitions(path
, None)
1512 # Generate transition tables
1513 for state
in self
.states
.itervalues():
1514 self
.printHTMLTransitions(path
, state
)
1516 # Generate action descriptions
1517 for action
in self
.actions
.itervalues():
1518 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1519 code
= html
.createSymbol(action
, "Action")
1520 code
.write(path
, name
)
1522 # Generate state descriptions
1523 for state
in self
.states
.itervalues():
1524 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1525 code
= html
.createSymbol(state
, "State")
1526 code
.write(path
, name
)
1528 # Generate event descriptions
1529 for event
in self
.events
.itervalues():
1530 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1531 code
= html
.createSymbol(event
, "Event")
1532 code
.write(path
, name
)
1534 def printHTMLTransitions(self
, path
, active_state
):
1535 code
= self
.symtab
.codeFormatter()
1539 <BODY link="blue" vlink="blue">
1541 <H1 align="center">${{html.formatShorthand(self.short)}}:
1544 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1553 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1564 for event
in self
.events
.itervalues():
1565 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1566 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1567 code('<TH bgcolor=white>$ref</TH>')
1571 for state
in self
.states
.itervalues():
1573 if state
== active_state
:
1578 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1579 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1580 text
= html
.formatShorthand(state
.short
)
1581 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1584 <TH bgcolor=$color>$ref</TH>
1587 # -- One column for each event
1588 for event
in self
.events
.itervalues():
1589 trans
= self
.table
.get((state
,event
), None)
1591 # This is the no transition case
1592 if state
== active_state
:
1597 code('<TD bgcolor=$color> </TD>')
1600 next
= trans
.nextState
1601 stall_action
= False
1603 # -- Get the actions
1604 for action
in trans
.actions
:
1605 if action
.ident
== "z_stall" or \
1606 action
.ident
== "zz_recycleMandatoryQueue":
1609 # -- Print out "actions/next-state"
1611 if state
== active_state
:
1616 elif active_state
and next
.ident
== active_state
.ident
:
1618 elif state
== active_state
:
1623 code('<TD bgcolor=$color>')
1624 for action
in trans
.actions
:
1625 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1626 ref
= self
.frameRef(href
, "Status", href
, "1",
1632 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1633 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1634 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1639 if state
== active_state
:
1644 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1645 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1646 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1648 <TH bgcolor=$color>$ref</TH>
1657 for event
in self
.events
.itervalues():
1658 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1659 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1660 code('<TH bgcolor=white>$ref</TH>')
1669 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1671 name
= "%s_table.html" % self
.ident
1672 code
.write(path
, name
)
1674 __all__
= [ "StateMachine" ]