c676574cc78e4011fc4f0c641ed66fe3e5a29fb0
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 "uint32_t" : "UInt32",
37 "std::string": "String",
39 "CacheMemory": "RubyCache",
40 "WireBuffer": "RubyWireBuffer",
41 "Sequencer": "RubySequencer",
42 "DirectoryMemory": "RubyDirectoryMemory",
43 "MemoryControl": "MemoryControl",
44 "DMASequencer": "DMASequencer",
45 "Prefetcher":"Prefetcher"
48 class StateMachine(Symbol
):
49 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
50 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
52 self
.config_parameters
= config_parameters
55 for param
in config_parameters
:
57 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
58 "(*m_%s_ptr)" % param
.name
, {}, self
)
60 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
61 "m_%s" % param
.name
, {}, self
)
62 self
.symtab
.registerSym(param
.name
, var
)
63 if str(param
.type_ast
.type) == "Prefetcher":
64 self
.prefetchers
.append(var
)
66 self
.states
= orderdict()
67 self
.events
= orderdict()
68 self
.actions
= orderdict()
69 self
.request_types
= orderdict()
76 self
.message_buffer_names
= []
80 return "[StateMachine: %s]" % self
.ident
82 def addState(self
, state
):
83 assert self
.table
is None
84 self
.states
[state
.ident
] = state
86 def addEvent(self
, event
):
87 assert self
.table
is None
88 self
.events
[event
.ident
] = event
90 def addAction(self
, action
):
91 assert self
.table
is None
93 # Check for duplicate action
94 for other
in self
.actions
.itervalues():
95 if action
.ident
== other
.ident
:
96 action
.warning("Duplicate action definition: %s" % action
.ident
)
97 action
.error("Duplicate action definition: %s" % action
.ident
)
98 if action
.short
== other
.short
:
99 other
.warning("Duplicate action shorthand: %s" % other
.ident
)
100 other
.warning(" shorthand = %s" % other
.short
)
101 action
.warning("Duplicate action shorthand: %s" % action
.ident
)
102 action
.error(" shorthand = %s" % action
.short
)
104 self
.actions
[action
.ident
] = action
106 def addRequestType(self
, request_type
):
107 assert self
.table
is None
108 self
.request_types
[request_type
.ident
] = request_type
110 def addTransition(self
, trans
):
111 assert self
.table
is None
112 self
.transitions
.append(trans
)
114 def addInPort(self
, var
):
115 self
.in_ports
.append(var
)
117 def addFunc(self
, func
):
118 # register func in the symbol table
119 self
.symtab
.registerSym(str(func
), func
)
120 self
.functions
.append(func
)
122 def addObject(self
, obj
):
123 self
.objects
.append(obj
)
125 def addType(self
, type):
126 type_ident
= '%s' % type.c_ident
128 if type_ident
== "%s_TBE" %self
.ident
:
129 if self
.TBEType
!= None:
130 self
.error("Multiple Transaction Buffer types in a " \
134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]:
135 if self
.EntryType
!= None:
136 self
.error("Multiple AbstractCacheEntry types in a " \
138 self
.EntryType
= type
140 # Needs to be called before accessing the table
141 def buildTable(self
):
142 assert self
.table
is None
146 for trans
in self
.transitions
:
147 # Track which actions we touch so we know if we use them
148 # all -- really this should be done for all symbols as
149 # part of the symbol table, then only trigger it for
150 # Actions, States, Events, etc.
152 for action
in trans
.actions
:
155 index
= (trans
.state
, trans
.event
)
157 table
[index
].warning("Duplicate transition: %s" % table
[index
])
158 trans
.error("Duplicate transition: %s" % trans
)
161 # Look at all actions to make sure we used them all
162 for action
in self
.actions
.itervalues():
164 error_msg
= "Unused action: %s" % action
.ident
166 error_msg
+= ", " + action
.desc
167 action
.warning(error_msg
)
170 def writeCodeFiles(self
, path
, includes
):
171 self
.printControllerPython(path
)
172 self
.printControllerHH(path
)
173 self
.printControllerCC(path
, includes
)
174 self
.printCSwitch(path
)
175 self
.printCWakeup(path
, includes
)
176 self
.printProfilerCC(path
)
177 self
.printProfilerHH(path
)
178 self
.printProfileDumperCC(path
)
179 self
.printProfileDumperHH(path
)
181 def printControllerPython(self
, path
):
182 code
= self
.symtab
.codeFormatter()
184 py_ident
= "%s_Controller" % ident
185 c_ident
= "%s_Controller" % self
.ident
187 from m5.params import *
188 from m5.SimObject import SimObject
189 from Controller import RubyController
191 class $py_ident(RubyController):
193 cxx_header = 'mem/protocol/${c_ident}.hh'
196 for param
in self
.config_parameters
:
198 if param
.default
is not None:
199 dflt_str
= str(param
.default
) + ', '
200 if python_class_map
.has_key(param
.type_ast
.type.c_ident
):
201 python_type
= python_class_map
[param
.type_ast
.type.c_ident
]
202 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")')
204 self
.error("Unknown c++ to python class conversion for c++ " \
205 "type: '%s'. Please update the python_class_map " \
206 "in StateMachine.py", param
.type_ast
.type.c_ident
)
208 code
.write(path
, '%s.py' % py_ident
)
211 def printControllerHH(self
, path
):
212 '''Output the method declarations for the class declaration'''
213 code
= self
.symtab
.codeFormatter()
215 c_ident
= "%s_Controller" % self
.ident
217 self
.message_buffer_names
= []
220 /** \\file $c_ident.hh
222 * Auto generated C++ code started by $__file__:$__line__
223 * Created by slicc definition of Module "${{self.short}}"
226 #ifndef __${ident}_CONTROLLER_HH__
227 #define __${ident}_CONTROLLER_HH__
233 #include "mem/protocol/${ident}_ProfileDumper.hh"
234 #include "mem/protocol/${ident}_Profiler.hh"
235 #include "mem/protocol/TransitionResult.hh"
236 #include "mem/protocol/Types.hh"
237 #include "mem/ruby/common/Consumer.hh"
238 #include "mem/ruby/common/Global.hh"
239 #include "mem/ruby/slicc_interface/AbstractController.hh"
240 #include "params/$c_ident.hh"
244 for var
in self
.objects
:
245 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
246 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
247 seen_types
.add(var
.type.ident
)
249 # for adding information to the protocol debug trace
251 extern std::stringstream ${ident}_transitionComment;
253 class $c_ident : public AbstractController
256 typedef ${c_ident}Params Params;
257 $c_ident(const Params *p);
258 static int getNumControllers();
260 MessageBuffer* getMandatoryQueue() const;
261 const int & getVersion() const;
262 const std::string toString() const;
263 const std::string getName() const;
264 void stallBuffer(MessageBuffer* buf, Address addr);
265 void wakeUpBuffers(Address addr);
266 void wakeUpAllBuffers();
267 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
268 void print(std::ostream& out) const;
270 void printStats(std::ostream& out) const;
272 void blockOnQueue(Address addr, MessageBuffer* port);
273 void unblock(Address addr);
274 void recordCacheTrace(int cntrl, CacheRecorder* tr);
275 Sequencer* getSequencer() const;
277 bool functionalReadBuffers(PacketPtr&);
278 uint32_t functionalWriteBuffers(PacketPtr&);
285 for param
in self
.config_parameters
:
287 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
289 code('${{param.type_ast.type}} m_${{param.ident}};')
292 TransitionResult doTransition(${ident}_Event event,
295 if self
.EntryType
!= None:
297 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
299 if self
.TBEType
!= None:
301 ${{self.TBEType.c_ident}}* m_tbe_ptr,
305 const Address& addr);
307 TransitionResult doTransitionWorker(${ident}_Event event,
308 ${ident}_State state,
309 ${ident}_State& next_state,
312 if self
.TBEType
!= None:
314 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
316 if self
.EntryType
!= None:
318 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
322 const Address& addr);
324 static ${ident}_ProfileDumper s_profileDumper;
325 ${ident}_Profiler m_profiler;
326 static int m_num_controllers;
328 // Internal functions
331 for func
in self
.functions
:
332 proto
= func
.prototype
336 if self
.EntryType
!= None:
339 // Set and Reset for cache_entry variable
340 void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry);
341 void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr);
344 if self
.TBEType
!= None:
347 // Set and Reset for tbe variable
348 void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe);
349 void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr);
356 if self
.TBEType
!= None and self
.EntryType
!= None:
357 for action
in self
.actions
.itervalues():
358 code('/** \\brief ${{action.desc}} */')
359 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
360 elif self
.TBEType
!= None:
361 for action
in self
.actions
.itervalues():
362 code('/** \\brief ${{action.desc}} */')
363 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);')
364 elif self
.EntryType
!= None:
365 for action
in self
.actions
.itervalues():
366 code('/** \\brief ${{action.desc}} */')
367 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);')
369 for action
in self
.actions
.itervalues():
370 code('/** \\brief ${{action.desc}} */')
371 code('void ${{action.ident}}(const Address& addr);')
373 # the controller internal variables
378 for var
in self
.objects
:
379 th
= var
.get("template", "")
380 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;')
382 if var
.type.ident
== "MessageBuffer":
383 self
.message_buffer_names
.append("m_%s_ptr" % var
.c_ident
)
387 code('#endif // __${ident}_CONTROLLER_H__')
388 code
.write(path
, '%s.hh' % c_ident
)
390 def printControllerCC(self
, path
, includes
):
391 '''Output the actions for performing the actions'''
393 code
= self
.symtab
.codeFormatter()
395 c_ident
= "%s_Controller" % self
.ident
398 /** \\file $c_ident.cc
400 * Auto generated C++ code started by $__file__:$__line__
401 * Created by slicc definition of Module "${{self.short}}"
404 #include <sys/types.h>
411 #include "base/compiler.hh"
412 #include "base/cprintf.hh"
413 #include "debug/RubyGenerated.hh"
414 #include "debug/RubySlicc.hh"
415 #include "mem/protocol/${ident}_Controller.hh"
416 #include "mem/protocol/${ident}_Event.hh"
417 #include "mem/protocol/${ident}_State.hh"
418 #include "mem/protocol/Types.hh"
419 #include "mem/ruby/common/Global.hh"
420 #include "mem/ruby/system/System.hh"
422 for include_path
in includes
:
423 code('#include "${{include_path}}"')
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)
458 # max_port_rank is used to size vectors and thus should be one plus the
461 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
462 code(' m_max_in_port_rank = $max_port_rank;')
466 # After initializing the universal machine parameters, initialize the
467 # this machines config parameters. Also detemine if these configuration
468 # params include a sequencer. This information will be used later for
469 # contecting the sequencer back to the L1 cache controller.
471 contains_dma_sequencer
= False
473 for param
in self
.config_parameters
:
474 if param
.name
== "dma_sequencer":
475 contains_dma_sequencer
= True
476 elif re
.compile("sequencer").search(param
.name
):
477 sequencers
.append(param
.name
)
479 code('m_${{param.name}}_ptr = p->${{param.name}};')
481 code('m_${{param.name}} = p->${{param.name}};')
484 # For the l1 cache controller, add the special atomic support which
485 # includes passing the sequencer a pointer to the controller.
487 if self
.ident
== "L1Cache":
489 self
.error("The L1Cache controller must include the sequencer " \
490 "configuration parameter")
492 for seq
in sequencers
:
494 m_${{seq}}_ptr->setController(this);
498 for seq
in sequencers
:
500 m_${{seq}}_ptr->setController(this);
504 # For the DMA controller, pass the sequencer a pointer to the
507 if self
.ident
== "DMA":
508 if not contains_dma_sequencer
:
509 self
.error("The DMA controller must include the sequencer " \
510 "configuration parameter")
513 m_dma_sequencer_ptr->setController(this);
516 code('m_num_controllers++;')
517 for var
in self
.objects
:
518 if var
.ident
.find("mandatoryQueue") >= 0:
519 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();')
528 MachineType machine_type;
530 machine_type = string_to_MachineType("${{var.machine.ident}}");
531 base = MachineType_base_number(machine_type);
533 m_machineID.type = MachineType_${ident};
534 m_machineID.num = m_version;
536 // initialize objects
537 m_profiler.setVersion(m_version);
538 s_profileDumper.registerProfiler(&m_profiler);
543 for var
in self
.objects
:
545 vid
= "m_%s_ptr" % var
.c_ident
546 if "network" not in var
:
547 # Not a network port object
548 if "primitive" in vtype
:
549 code('$vid = new ${{vtype.c_ident}};')
551 code('(*$vid) = ${{var["default"]}};')
556 code('$vid = ${{var["factory"]}};')
557 elif var
.ident
.find("mandatoryQueue") < 0:
558 th
= var
.get("template", "")
559 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
561 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
562 args
= var
.get("constructor", "")
563 code('$expr($args);')
565 code('assert($vid != NULL);')
568 code('*$vid = ${{var["default"]}}; // Object default')
569 elif "default" in vtype
:
570 comment
= "Type %s default" % vtype
.ident
571 code('*$vid = ${{vtype["default"]}}; // $comment')
574 if "ordered" in var
and "trigger_queue" not in var
:
576 code('$vid->setOrdering(${{var["ordered"]}});')
581 code('$vid->setRandomization(${{var["random"]}});')
584 if vtype
.isBuffer
and \
585 "rank" in var
and "trigger_queue" not in var
:
586 code('$vid->setPriority(${{var["rank"]}});')
589 # Network port object
590 network
= var
["network"]
591 ordered
= var
["ordered"]
592 vnet
= var
["virtual_network"]
593 vnet_type
= var
["vnet_type"]
595 assert var
.machine
is not None
597 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
600 code('assert($vid != NULL);')
605 code('$vid->setOrdering(${{var["ordered"]}});')
610 code('$vid->setRandomization(${{var["random"]}});')
614 code('$vid->setPriority(${{var["rank"]}})')
619 if (m_buffer_size > 0) {
620 $vid->resize(m_buffer_size);
624 # set description (may be overriden later by port def)
626 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
631 if "recycle_latency" in var
:
632 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});')
634 code('$vid->setRecycleLatency(m_recycle_latency);')
636 # Set the prefetchers
638 for prefetcher
in self
.prefetchers
:
639 code('${{prefetcher.code}}.setController(this);')
642 for port
in self
.in_ports
:
643 # Set the queue consumers
644 code('${{port.code}}.setConsumer(this);')
645 # Set the queue descriptions
646 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
647 # Set the clock object
648 code('${{port.code}}.setClockObj(this);')
650 # Initialize the transition profiling
652 for trans
in self
.transitions
:
653 # Figure out if we stall
655 for action
in trans
.actions
:
656 if action
.ident
== "z_stall":
659 # Only possible if it is not a 'z' case
661 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
662 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
663 code('m_profiler.possibleTransition($state, $event);')
668 has_mandatory_q
= False
669 for port
in self
.in_ports
:
670 if port
.code
.find("mandatoryQueue_ptr") >= 0:
671 has_mandatory_q
= True
674 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
679 for param
in self
.config_parameters
:
680 if param
.name
== "sequencer":
681 assert(param
.pointer
)
682 seq_ident
= "m_%s_ptr" % param
.name
686 $c_ident::getNumControllers()
688 return m_num_controllers;
692 $c_ident::getMandatoryQueue() const
698 $c_ident::getSequencer() const
704 $c_ident::getVersion() const
710 $c_ident::toString() const
716 $c_ident::getName() const
722 $c_ident::stallBuffer(MessageBuffer* buf, Address addr)
724 if (m_waiting_buffers.count(addr) == 0) {
725 MsgVecType* msgVec = new MsgVecType;
726 msgVec->resize(m_max_in_port_rank, NULL);
727 m_waiting_buffers[addr] = msgVec;
729 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf;
733 $c_ident::wakeUpBuffers(Address addr)
735 if (m_waiting_buffers.count(addr) > 0) {
737 // Wake up all possible lower rank (i.e. lower priority) buffers that could
738 // be waiting on this message.
740 for (int in_port_rank = m_cur_in_port_rank - 1;
743 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) {
744 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr);
747 delete m_waiting_buffers[addr];
748 m_waiting_buffers.erase(addr);
753 $c_ident::wakeUpAllBuffers()
756 // Wake up all possible buffers that could be waiting on any message.
759 std::vector<MsgVecType*> wokeUpMsgVecs;
761 if(m_waiting_buffers.size() > 0) {
762 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin();
763 buf_iter != m_waiting_buffers.end();
765 for (MsgVecType::iterator vec_iter = buf_iter->second->begin();
766 vec_iter != buf_iter->second->end();
768 if (*vec_iter != NULL) {
769 (*vec_iter)->reanalyzeAllMessages();
772 wokeUpMsgVecs.push_back(buf_iter->second);
775 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin();
776 wb_iter != wokeUpMsgVecs.end();
781 m_waiting_buffers.clear();
786 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
788 m_is_blocking = true;
789 m_block_map[addr] = port;
793 $c_ident::unblock(Address addr)
795 m_block_map.erase(addr);
796 if (m_block_map.size() == 0) {
797 m_is_blocking = false;
802 $c_ident::print(ostream& out) const
804 out << "[$c_ident " << m_version << "]";
808 $c_ident::printStats(ostream& out) const
812 # Cache and Memory Controllers have specific profilers associated with
813 # them. Print out these stats before dumping state transition stats.
815 for param
in self
.config_parameters
:
816 if param
.type_ast
.type.ident
== "CacheMemory" or \
817 param
.type_ast
.type.ident
== "DirectoryMemory" or \
818 param
.type_ast
.type.ident
== "MemoryControl":
819 assert(param
.pointer
)
820 code(' m_${{param.ident}}_ptr->printStats(out);')
823 if (m_version == 0) {
824 s_profileDumper.dumpStats(out);
828 void $c_ident::clearStats() {
831 # Cache and Memory Controllers have specific profilers associated with
832 # them. These stats must be cleared too.
834 for param
in self
.config_parameters
:
835 if param
.type_ast
.type.ident
== "CacheMemory" or \
836 param
.type_ast
.type.ident
== "MemoryControl":
837 assert(param
.pointer
)
838 code(' m_${{param.ident}}_ptr->clearStats();')
841 m_profiler.clearStats();
845 if self
.EntryType
!= None:
848 // Set and Reset for cache_entry variable
850 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
852 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
856 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
858 m_cache_entry_ptr = 0;
862 if self
.TBEType
!= None:
865 // Set and Reset for tbe variable
867 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
869 m_tbe_ptr = m_new_tbe;
873 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
882 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
886 # Record cache contents for all associated caches.
889 for param
in self
.config_parameters
:
890 if param
.type_ast
.type.ident
== "CacheMemory":
891 assert(param
.pointer
)
892 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
900 if self
.TBEType
!= None and self
.EntryType
!= None:
901 for action
in self
.actions
.itervalues():
902 if "c_code" not in action
:
906 /** \\brief ${{action.desc}} */
908 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
910 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
911 ${{action["c_code"]}}
915 elif self
.TBEType
!= None:
916 for action
in self
.actions
.itervalues():
917 if "c_code" not in action
:
921 /** \\brief ${{action.desc}} */
923 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
925 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
926 ${{action["c_code"]}}
930 elif self
.EntryType
!= None:
931 for action
in self
.actions
.itervalues():
932 if "c_code" not in action
:
936 /** \\brief ${{action.desc}} */
938 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
940 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
941 ${{action["c_code"]}}
946 for action
in self
.actions
.itervalues():
947 if "c_code" not in action
:
951 /** \\brief ${{action.desc}} */
953 $c_ident::${{action.ident}}(const Address& addr)
955 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
956 ${{action["c_code"]}}
960 for func
in self
.functions
:
961 code(func
.generateCode())
963 # Function for functional reads from messages buffered in the controller
966 $c_ident::functionalReadBuffers(PacketPtr& pkt)
969 for var
in self
.objects
:
972 vid
= "m_%s_ptr" % var
.c_ident
973 code('if ($vid->functionalRead(pkt)) { return true; }')
979 # Function for functional writes to messages buffered in the controller
982 $c_ident::functionalWriteBuffers(PacketPtr& pkt)
984 uint32_t num_functional_writes = 0;
986 for var
in self
.objects
:
989 vid
= "m_%s_ptr" % var
.c_ident
990 code('num_functional_writes += $vid->functionalWrite(pkt);')
992 return num_functional_writes;
996 code
.write(path
, "%s.cc" % c_ident
)
998 def printCWakeup(self
, path
, includes
):
999 '''Output the wakeup loop for the events'''
1001 code
= self
.symtab
.codeFormatter()
1004 outputRequest_types
= True
1005 if len(self
.request_types
) == 0:
1006 outputRequest_types
= False
1009 // Auto generated C++ code started by $__file__:$__line__
1010 // ${ident}: ${{self.short}}
1012 #include <sys/types.h>
1017 #include "base/misc.hh"
1018 #include "debug/RubySlicc.hh"
1019 #include "mem/protocol/${ident}_Controller.hh"
1020 #include "mem/protocol/${ident}_Event.hh"
1021 #include "mem/protocol/${ident}_State.hh"
1024 if outputRequest_types
:
1025 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1028 #include "mem/protocol/Types.hh"
1029 #include "mem/ruby/common/Global.hh"
1030 #include "mem/ruby/system/System.hh"
1034 for include_path
in includes
:
1035 code('#include "${{include_path}}"')
1039 using namespace std;
1042 ${ident}_Controller::wakeup()
1046 // Some cases will put us into an infinite loop without this limit
1047 assert(counter <= m_transitions_per_cycle);
1048 if (counter == m_transitions_per_cycle) {
1049 // Count how often we are fully utilized
1050 g_system_ptr->getProfiler()->controllerBusy(m_machineID);
1052 // Wakeup in another cycle and try again
1063 for port
in self
.in_ports
:
1065 code('// ${ident}InPort $port')
1066 if port
.pairs
.has_key("rank"):
1067 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1069 code('m_cur_in_port_rank = 0;')
1070 code('${{port["c_code_in_port"]}}')
1078 break; // If we got this far, we have nothing left todo
1083 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1085 def printCSwitch(self
, path
):
1086 '''Output switch statement for transition table'''
1088 code
= self
.symtab
.codeFormatter()
1092 // Auto generated C++ code started by $__file__:$__line__
1093 // ${ident}: ${{self.short}}
1097 #include "base/misc.hh"
1098 #include "base/trace.hh"
1099 #include "debug/ProtocolTrace.hh"
1100 #include "debug/RubyGenerated.hh"
1101 #include "mem/protocol/${ident}_Controller.hh"
1102 #include "mem/protocol/${ident}_Event.hh"
1103 #include "mem/protocol/${ident}_State.hh"
1104 #include "mem/protocol/Types.hh"
1105 #include "mem/ruby/common/Global.hh"
1106 #include "mem/ruby/system/System.hh"
1108 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1110 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1111 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1114 ${ident}_Controller::doTransition(${ident}_Event event,
1116 if self
.EntryType
!= None:
1118 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1120 if self
.TBEType
!= None:
1122 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1125 const Address &addr)
1128 if self
.TBEType
!= None and self
.EntryType
!= None:
1129 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1130 elif self
.TBEType
!= None:
1131 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1132 elif self
.EntryType
!= None:
1133 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1135 code('${ident}_State state = getState(addr);')
1138 ${ident}_State next_state = state;
1140 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1141 *this, curCycle(), ${ident}_State_to_string(state),
1142 ${ident}_Event_to_string(event), addr);
1144 TransitionResult result =
1146 if self
.TBEType
!= None and self
.EntryType
!= None:
1147 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1148 elif self
.TBEType
!= None:
1149 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1150 elif self
.EntryType
!= None:
1151 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1153 code('doTransitionWorker(event, state, next_state, addr);')
1156 if (result == TransitionResult_Valid) {
1157 DPRINTF(RubyGenerated, "next_state: %s\\n",
1158 ${ident}_State_to_string(next_state));
1159 m_profiler.countTransition(state, event);
1160 DPRINTFR(ProtocolTrace, "%15d %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, GET_TRANSITION_COMMENT());
1167 CLEAR_TRANSITION_COMMENT();
1169 if self
.TBEType
!= None and self
.EntryType
!= None:
1170 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1171 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1172 elif self
.TBEType
!= None:
1173 code('setState(m_tbe_ptr, addr, next_state);')
1174 code('setAccessPermission(addr, next_state);')
1175 elif self
.EntryType
!= None:
1176 code('setState(m_cache_entry_ptr, addr, next_state);')
1177 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1179 code('setState(addr, next_state);')
1180 code('setAccessPermission(addr, next_state);')
1183 } else if (result == TransitionResult_ResourceStall) {
1184 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1185 curTick(), m_version, "${ident}",
1186 ${ident}_Event_to_string(event),
1187 ${ident}_State_to_string(state),
1188 ${ident}_State_to_string(next_state),
1189 addr, "Resource Stall");
1190 } else if (result == TransitionResult_ProtocolStall) {
1191 DPRINTF(RubyGenerated, "stalling\\n");
1192 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1193 curTick(), m_version, "${ident}",
1194 ${ident}_Event_to_string(event),
1195 ${ident}_State_to_string(state),
1196 ${ident}_State_to_string(next_state),
1197 addr, "Protocol Stall");
1204 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1205 ${ident}_State state,
1206 ${ident}_State& next_state,
1209 if self
.TBEType
!= None:
1211 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1213 if self
.EntryType
!= None:
1215 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1218 const Address& addr)
1220 switch(HASH_FUN(state, event)) {
1223 # This map will allow suppress generating duplicate code
1226 for trans
in self
.transitions
:
1227 case_string
= "%s_State_%s, %s_Event_%s" % \
1228 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1230 case
= self
.symtab
.codeFormatter()
1231 # Only set next_state if it changes
1232 if trans
.state
!= trans
.nextState
:
1233 ns_ident
= trans
.nextState
.ident
1234 case('next_state = ${ident}_State_${ns_ident};')
1236 actions
= trans
.actions
1237 request_types
= trans
.request_types
1239 # Check for resources
1241 res
= trans
.resources
1242 for key
,val
in res
.iteritems():
1243 if key
.type.ident
!= "DNUCAStopTable":
1245 if (!%s.areNSlotsAvailable(%s))
1246 return TransitionResult_ResourceStall;
1247 ''' % (key
.code
, val
)
1248 case_sorter
.append(val
)
1250 # Check all of the request_types for resource constraints
1251 for request_type
in request_types
:
1253 if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1254 return TransitionResult_ResourceStall;
1256 ''' % (self
.ident
, request_type
.ident
)
1257 case_sorter
.append(val
)
1259 # Emit the code sequences in a sorted order. This makes the
1260 # output deterministic (without this the output order can vary
1261 # since Map's keys() on a vector of pointers is not deterministic
1262 for c
in sorted(case_sorter
):
1265 # Record access types for this transition
1266 for request_type
in request_types
:
1267 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1269 # Figure out if we stall
1271 for action
in actions
:
1272 if action
.ident
== "z_stall":
1277 case('return TransitionResult_ProtocolStall;')
1279 if self
.TBEType
!= None and self
.EntryType
!= None:
1280 for action
in actions
:
1281 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1282 elif self
.TBEType
!= None:
1283 for action
in actions
:
1284 case('${{action.ident}}(m_tbe_ptr, addr);')
1285 elif self
.EntryType
!= None:
1286 for action
in actions
:
1287 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1289 for action
in actions
:
1290 case('${{action.ident}}(addr);')
1291 case('return TransitionResult_Valid;')
1295 # Look to see if this transition code is unique.
1296 if case
not in cases
:
1299 cases
[case
].append(case_string
)
1301 # Walk through all of the unique code blocks and spit out the
1302 # corresponding case statement elements
1303 for case
,transitions
in cases
.iteritems():
1304 # Iterative over all the multiple transitions that share
1306 for trans
in transitions
:
1307 code(' case HASH_FUN($trans):')
1312 fatal("Invalid transition\\n"
1313 "%s time: %d addr: %s event: %s state: %s\\n",
1314 name(), curCycle(), addr, event, state);
1316 return TransitionResult_Valid;
1319 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1321 def printProfileDumperHH(self
, path
):
1322 code
= self
.symtab
.codeFormatter()
1326 // Auto generated C++ code started by $__file__:$__line__
1327 // ${ident}: ${{self.short}}
1329 #ifndef __${ident}_PROFILE_DUMPER_HH__
1330 #define __${ident}_PROFILE_DUMPER_HH__
1336 #include "${ident}_Event.hh"
1337 #include "${ident}_Profiler.hh"
1339 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1341 class ${ident}_ProfileDumper
1344 ${ident}_ProfileDumper();
1345 void registerProfiler(${ident}_Profiler* profiler);
1346 void dumpStats(std::ostream& out) const;
1349 ${ident}_profilers m_profilers;
1352 #endif // __${ident}_PROFILE_DUMPER_HH__
1354 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1356 def printProfileDumperCC(self
, path
):
1357 code
= self
.symtab
.codeFormatter()
1361 // Auto generated C++ code started by $__file__:$__line__
1362 // ${ident}: ${{self.short}}
1364 #include "mem/protocol/${ident}_ProfileDumper.hh"
1366 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1371 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1373 m_profilers.push_back(profiler);
1377 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1379 out << " --- ${ident} ---\\n";
1380 out << " - Event Counts -\\n";
1381 for (${ident}_Event event = ${ident}_Event_FIRST;
1382 event < ${ident}_Event_NUM;
1384 out << (${ident}_Event) event << " [";
1386 for (int i = 0; i < m_profilers.size(); i++) {
1387 out << m_profilers[i]->getEventCount(event) << " ";
1388 total += m_profilers[i]->getEventCount(event);
1390 out << "] " << total << "\\n";
1393 out << " - Transitions -\\n";
1394 for (${ident}_State state = ${ident}_State_FIRST;
1395 state < ${ident}_State_NUM;
1397 for (${ident}_Event event = ${ident}_Event_FIRST;
1398 event < ${ident}_Event_NUM;
1400 if (m_profilers[0]->isPossible(state, event)) {
1401 out << (${ident}_State) state << " "
1402 << (${ident}_Event) event << " [";
1404 for (int i = 0; i < m_profilers.size(); i++) {
1405 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1406 total += m_profilers[i]->getTransitionCount(state, event);
1408 out << "] " << total << "\\n";
1415 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1417 def printProfilerHH(self
, path
):
1418 code
= self
.symtab
.codeFormatter()
1422 // Auto generated C++ code started by $__file__:$__line__
1423 // ${ident}: ${{self.short}}
1425 #ifndef __${ident}_PROFILER_HH__
1426 #define __${ident}_PROFILER_HH__
1431 #include "mem/protocol/${ident}_Event.hh"
1432 #include "mem/protocol/${ident}_State.hh"
1433 #include "mem/ruby/common/TypeDefines.hh"
1435 class ${ident}_Profiler
1438 ${ident}_Profiler();
1439 void setVersion(int version);
1440 void countTransition(${ident}_State state, ${ident}_Event event);
1441 void possibleTransition(${ident}_State state, ${ident}_Event event);
1442 uint64 getEventCount(${ident}_Event event);
1443 bool isPossible(${ident}_State state, ${ident}_Event event);
1444 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1448 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1449 int m_event_counters[${ident}_Event_NUM];
1450 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1454 #endif // __${ident}_PROFILER_HH__
1456 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1458 def printProfilerCC(self
, path
):
1459 code
= self
.symtab
.codeFormatter()
1463 // Auto generated C++ code started by $__file__:$__line__
1464 // ${ident}: ${{self.short}}
1468 #include "mem/protocol/${ident}_Profiler.hh"
1470 ${ident}_Profiler::${ident}_Profiler()
1472 for (int state = 0; state < ${ident}_State_NUM; state++) {
1473 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1474 m_possible[state][event] = false;
1475 m_counters[state][event] = 0;
1478 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1479 m_event_counters[event] = 0;
1484 ${ident}_Profiler::setVersion(int version)
1486 m_version = version;
1490 ${ident}_Profiler::clearStats()
1492 for (int state = 0; state < ${ident}_State_NUM; state++) {
1493 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1494 m_counters[state][event] = 0;
1498 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1499 m_event_counters[event] = 0;
1503 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1505 assert(m_possible[state][event]);
1506 m_counters[state][event]++;
1507 m_event_counters[event]++;
1510 ${ident}_Profiler::possibleTransition(${ident}_State state,
1511 ${ident}_Event event)
1513 m_possible[state][event] = true;
1517 ${ident}_Profiler::getEventCount(${ident}_Event event)
1519 return m_event_counters[event];
1523 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1525 return m_possible[state][event];
1529 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1530 ${ident}_Event event)
1532 return m_counters[state][event];
1536 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1538 # **************************
1539 # ******* HTML Files *******
1540 # **************************
1541 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1542 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1543 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1544 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1545 parent.frames[$over_num].location='$over_href'
1547 ${{html.formatShorthand(text)}}
1551 def writeHTMLFiles(self
, path
):
1552 # Create table with no row hilighted
1553 self
.printHTMLTransitions(path
, None)
1555 # Generate transition tables
1556 for state
in self
.states
.itervalues():
1557 self
.printHTMLTransitions(path
, state
)
1559 # Generate action descriptions
1560 for action
in self
.actions
.itervalues():
1561 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1562 code
= html
.createSymbol(action
, "Action")
1563 code
.write(path
, name
)
1565 # Generate state descriptions
1566 for state
in self
.states
.itervalues():
1567 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1568 code
= html
.createSymbol(state
, "State")
1569 code
.write(path
, name
)
1571 # Generate event descriptions
1572 for event
in self
.events
.itervalues():
1573 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1574 code
= html
.createSymbol(event
, "Event")
1575 code
.write(path
, name
)
1577 def printHTMLTransitions(self
, path
, active_state
):
1578 code
= self
.symtab
.codeFormatter()
1582 <BODY link="blue" vlink="blue">
1584 <H1 align="center">${{html.formatShorthand(self.short)}}:
1587 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1596 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1607 for event
in self
.events
.itervalues():
1608 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1609 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1610 code('<TH bgcolor=white>$ref</TH>')
1614 for state
in self
.states
.itervalues():
1616 if state
== active_state
:
1621 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1622 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1623 text
= html
.formatShorthand(state
.short
)
1624 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1627 <TH bgcolor=$color>$ref</TH>
1630 # -- One column for each event
1631 for event
in self
.events
.itervalues():
1632 trans
= self
.table
.get((state
,event
), None)
1634 # This is the no transition case
1635 if state
== active_state
:
1640 code('<TD bgcolor=$color> </TD>')
1643 next
= trans
.nextState
1644 stall_action
= False
1646 # -- Get the actions
1647 for action
in trans
.actions
:
1648 if action
.ident
== "z_stall" or \
1649 action
.ident
== "zz_recycleMandatoryQueue":
1652 # -- Print out "actions/next-state"
1654 if state
== active_state
:
1659 elif active_state
and next
.ident
== active_state
.ident
:
1661 elif state
== active_state
:
1666 code('<TD bgcolor=$color>')
1667 for action
in trans
.actions
:
1668 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1669 ref
= self
.frameRef(href
, "Status", href
, "1",
1675 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1676 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1677 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1682 if state
== active_state
:
1687 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1688 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1689 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1691 <TH bgcolor=$color>$ref</TH>
1700 for event
in self
.events
.itervalues():
1701 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1702 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1703 code('<TH bgcolor=white>$ref</TH>')
1712 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1714 name
= "%s_table.html" % self
.ident
1715 code
.write(path
, name
)
1717 __all__
= [ "StateMachine" ]