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
37 "uint32_t" : "UInt32",
38 "std::string": "String",
40 "CacheMemory": "RubyCache",
41 "WireBuffer": "RubyWireBuffer",
42 "Sequencer": "RubySequencer",
43 "DirectoryMemory": "RubyDirectoryMemory",
44 "MemoryControl": "MemoryControl",
45 "DMASequencer": "DMASequencer",
46 "Prefetcher":"Prefetcher",
50 class StateMachine(Symbol
):
51 def __init__(self
, symtab
, ident
, location
, pairs
, config_parameters
):
52 super(StateMachine
, self
).__init
__(symtab
, ident
, location
, pairs
)
54 self
.config_parameters
= config_parameters
57 for param
in config_parameters
:
59 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
60 "(*m_%s_ptr)" % param
.name
, {}, self
)
62 var
= Var(symtab
, param
.name
, location
, param
.type_ast
.type,
63 "m_%s" % param
.name
, {}, self
)
64 self
.symtab
.registerSym(param
.name
, var
)
65 if str(param
.type_ast
.type) == "Prefetcher":
66 self
.prefetchers
.append(var
)
68 self
.states
= orderdict()
69 self
.events
= orderdict()
70 self
.actions
= orderdict()
71 self
.request_types
= orderdict()
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
218 /** \\file $c_ident.hh
220 * Auto generated C++ code started by $__file__:$__line__
221 * Created by slicc definition of Module "${{self.short}}"
224 #ifndef __${ident}_CONTROLLER_HH__
225 #define __${ident}_CONTROLLER_HH__
231 #include "mem/protocol/${ident}_ProfileDumper.hh"
232 #include "mem/protocol/${ident}_Profiler.hh"
233 #include "mem/protocol/TransitionResult.hh"
234 #include "mem/protocol/Types.hh"
235 #include "mem/ruby/common/Consumer.hh"
236 #include "mem/ruby/common/Global.hh"
237 #include "mem/ruby/slicc_interface/AbstractController.hh"
238 #include "params/$c_ident.hh"
243 for var
in self
.objects
:
244 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
245 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
246 if "network" in var
and "physical_network" in var
:
248 seen_types
.add(var
.type.ident
)
250 # for adding information to the protocol debug trace
252 extern std::stringstream ${ident}_transitionComment;
254 class $c_ident : public AbstractController
257 typedef ${c_ident}Params Params;
258 $c_ident(const Params *p);
259 static int getNumControllers();
261 MessageBuffer* getMandatoryQueue() const;
262 const int & getVersion() const;
263 const std::string toString() const;
264 const std::string getName() const;
265 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }
266 void print(std::ostream& out) const;
268 void printStats(std::ostream& out) const;
270 void blockOnQueue(Address addr, MessageBuffer* port);
271 void unblock(Address addr);
272 void recordCacheTrace(int cntrl, CacheRecorder* tr);
273 Sequencer* getSequencer() const;
275 bool functionalReadBuffers(PacketPtr&);
276 uint32_t functionalWriteBuffers(PacketPtr&);
283 for param
in self
.config_parameters
:
285 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;')
287 code('${{param.type_ast.type}} m_${{param.ident}};')
290 TransitionResult doTransition(${ident}_Event event,
293 if self
.EntryType
!= None:
295 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
297 if self
.TBEType
!= None:
299 ${{self.TBEType.c_ident}}* m_tbe_ptr,
303 const Address& addr);
305 TransitionResult doTransitionWorker(${ident}_Event event,
306 ${ident}_State state,
307 ${ident}_State& next_state,
310 if self
.TBEType
!= None:
312 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
314 if self
.EntryType
!= None:
316 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
320 const Address& addr);
322 static ${ident}_ProfileDumper s_profileDumper;
323 ${ident}_Profiler m_profiler;
324 static int m_num_controllers;
326 // Internal functions
329 for func
in self
.functions
:
330 proto
= func
.prototype
335 code('void getQueuesFromPeer(AbstractController *);')
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;')
384 code('#endif // __${ident}_CONTROLLER_H__')
385 code
.write(path
, '%s.hh' % c_ident
)
387 def printControllerCC(self
, path
, includes
):
388 '''Output the actions for performing the actions'''
390 code
= self
.symtab
.codeFormatter()
392 c_ident
= "%s_Controller" % self
.ident
396 /** \\file $c_ident.cc
398 * Auto generated C++ code started by $__file__:$__line__
399 * Created by slicc definition of Module "${{self.short}}"
402 #include <sys/types.h>
409 #include "base/compiler.hh"
410 #include "base/cprintf.hh"
411 #include "debug/RubyGenerated.hh"
412 #include "debug/RubySlicc.hh"
413 #include "mem/protocol/${ident}_Controller.hh"
414 #include "mem/protocol/${ident}_Event.hh"
415 #include "mem/protocol/${ident}_State.hh"
416 #include "mem/protocol/Types.hh"
417 #include "mem/ruby/common/Global.hh"
418 #include "mem/ruby/system/System.hh"
420 for include_path
in includes
:
421 code('#include "${{include_path}}"')
428 # include object classes
430 for var
in self
.objects
:
431 if var
.type.ident
not in seen_types
and not var
.type.isPrimitive
:
432 code('#include "mem/protocol/${{var.type.c_ident}}.hh"')
433 seen_types
.add(var
.type.ident
)
437 ${c_ident}Params::create()
439 return new $c_ident(this);
442 int $c_ident::m_num_controllers = 0;
443 ${ident}_ProfileDumper $c_ident::s_profileDumper;
445 // for adding information to the protocol debug trace
446 stringstream ${ident}_transitionComment;
447 #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str)
449 /** \\brief constructor */
450 $c_ident::$c_ident(const Params *p)
451 : AbstractController(p)
456 # max_port_rank is used to size vectors and thus should be one plus the
459 max_port_rank
= self
.in_ports
[0].pairs
["max_port_rank"] + 1
460 code(' m_max_in_port_rank = $max_port_rank;')
464 # After initializing the universal machine parameters, initialize the
465 # this machines config parameters. Also detemine if these configuration
466 # params include a sequencer. This information will be used later for
467 # contecting the sequencer back to the L1 cache controller.
469 contains_dma_sequencer
= False
471 for param
in self
.config_parameters
:
472 if param
.name
== "dma_sequencer":
473 contains_dma_sequencer
= True
474 elif re
.compile("sequencer").search(param
.name
):
475 sequencers
.append(param
.name
)
477 code('m_${{param.name}}_ptr = p->${{param.name}};')
479 code('m_${{param.name}} = p->${{param.name}};')
482 # For the l1 cache controller, add the special atomic support which
483 # includes passing the sequencer a pointer to the controller.
485 if self
.ident
== "L1Cache":
487 self
.error("The L1Cache controller must include the sequencer " \
488 "configuration parameter")
490 for seq
in sequencers
:
492 m_${{seq}}_ptr->setController(this);
496 for seq
in sequencers
:
498 m_${{seq}}_ptr->setController(this);
502 # For the DMA controller, pass the sequencer a pointer to the
505 if self
.ident
== "DMA":
506 if not contains_dma_sequencer
:
507 self
.error("The DMA controller must include the sequencer " \
508 "configuration parameter")
511 m_dma_sequencer_ptr->setController(this);
514 code('m_num_controllers++;')
515 for var
in self
.objects
:
516 if var
.ident
.find("mandatoryQueue") >= 0:
518 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
519 m_${{var.c_ident}}_ptr->setReceiver(this);
522 if "network" in var
and "physical_network" in var
and \
523 var
["network"] == "To":
526 m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();
527 peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr;
528 m_${{var.c_ident}}_ptr->setSender(this);
533 connectWithPeer(p->peer);
542 MachineType machine_type;
544 machine_type = string_to_MachineType("${{var.machine.ident}}");
545 base = MachineType_base_number(machine_type);
547 m_machineID.type = MachineType_${ident};
548 m_machineID.num = m_version;
550 // initialize objects
551 m_profiler.setVersion(m_version);
552 s_profileDumper.registerProfiler(&m_profiler);
557 for var
in self
.objects
:
559 vid
= "m_%s_ptr" % var
.c_ident
560 if "network" not in var
:
561 # Not a network port object
562 if "primitive" in vtype
:
563 code('$vid = new ${{vtype.c_ident}};')
565 code('(*$vid) = ${{var["default"]}};')
568 if var
.ident
.find("mandatoryQueue") < 0:
569 th
= var
.get("template", "")
570 expr
= "%s = new %s%s" % (vid
, vtype
.c_ident
, th
)
572 if "non_obj" not in vtype
and not vtype
.isEnumeration
:
573 args
= var
.get("constructor", "")
574 code('$expr($args);')
576 code('assert($vid != NULL);')
579 code('*$vid = ${{var["default"]}}; // Object default')
580 elif "default" in vtype
:
581 comment
= "Type %s default" % vtype
.ident
582 code('*$vid = ${{vtype["default"]}}; // $comment')
587 code('$vid->setOrdering(${{var["ordered"]}});')
592 code('$vid->setRandomization(${{var["random"]}});')
595 if vtype
.isBuffer
and "rank" in var
:
596 code('$vid->setPriority(${{var["rank"]}});')
598 # Set sender and receiver for trigger queue
599 if var
.ident
.find("triggerQueue") >= 0:
600 code('$vid->setSender(this);')
601 code('$vid->setReceiver(this);')
602 elif vtype
.c_ident
== "TimerTable":
603 code('$vid->setClockObj(this);')
606 # Network port object
607 network
= var
["network"]
608 ordered
= var
["ordered"]
610 if "virtual_network" in var
:
611 vnet
= var
["virtual_network"]
612 vnet_type
= var
["vnet_type"]
614 assert var
.machine
is not None
616 $vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type");
617 assert($vid != NULL);
622 code('$vid->setSender(this);')
624 code('$vid->setReceiver(this);')
629 code('$vid->setOrdering(${{var["ordered"]}});')
634 code('$vid->setRandomization(${{var["random"]}});')
638 code('$vid->setPriority(${{var["rank"]}})')
643 if (m_buffer_size > 0) {
644 $vid->resize(m_buffer_size);
648 # set description (may be overriden later by port def)
650 $vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");
655 if "recycle_latency" in var
:
656 code('$vid->setRecycleLatency( ' \
657 'Cycles(${{var["recycle_latency"]}}));')
659 code('$vid->setRecycleLatency(m_recycle_latency);')
661 # Set the prefetchers
663 for prefetcher
in self
.prefetchers
:
664 code('${{prefetcher.code}}.setController(this);')
667 for port
in self
.in_ports
:
668 # Set the queue consumers
669 code('${{port.code}}.setConsumer(this);')
670 # Set the queue descriptions
671 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");')
673 # Initialize the transition profiling
675 for trans
in self
.transitions
:
676 # Figure out if we stall
678 for action
in trans
.actions
:
679 if action
.ident
== "z_stall":
682 # Only possible if it is not a 'z' case
684 state
= "%s_State_%s" % (self
.ident
, trans
.state
.ident
)
685 event
= "%s_Event_%s" % (self
.ident
, trans
.event
.ident
)
686 code('m_profiler.possibleTransition($state, $event);')
690 AbstractController::init();
695 has_mandatory_q
= False
696 for port
in self
.in_ports
:
697 if port
.code
.find("mandatoryQueue_ptr") >= 0:
698 has_mandatory_q
= True
701 mq_ident
= "m_%s_mandatoryQueue_ptr" % self
.ident
706 for param
in self
.config_parameters
:
707 if param
.name
== "sequencer":
708 assert(param
.pointer
)
709 seq_ident
= "m_%s_ptr" % param
.name
713 $c_ident::getNumControllers()
715 return m_num_controllers;
719 $c_ident::getMandatoryQueue() const
725 $c_ident::getSequencer() const
731 $c_ident::getVersion() const
737 $c_ident::toString() const
743 $c_ident::getName() const
749 $c_ident::blockOnQueue(Address addr, MessageBuffer* port)
751 m_is_blocking = true;
752 m_block_map[addr] = port;
756 $c_ident::unblock(Address addr)
758 m_block_map.erase(addr);
759 if (m_block_map.size() == 0) {
760 m_is_blocking = false;
765 $c_ident::print(ostream& out) const
767 out << "[$c_ident " << m_version << "]";
771 $c_ident::printStats(ostream& out) const
775 # Cache and Memory Controllers have specific profilers associated with
776 # them. Print out these stats before dumping state transition stats.
778 for param
in self
.config_parameters
:
779 if param
.type_ast
.type.ident
== "CacheMemory" or \
780 param
.type_ast
.type.ident
== "DirectoryMemory" or \
781 param
.type_ast
.type.ident
== "MemoryControl":
782 assert(param
.pointer
)
783 code(' m_${{param.ident}}_ptr->printStats(out);')
786 if (m_version == 0) {
787 s_profileDumper.dumpStats(out);
791 void $c_ident::clearStats() {
794 # Cache and Memory Controllers have specific profilers associated with
795 # them. These stats must be cleared too.
797 for param
in self
.config_parameters
:
798 if param
.type_ast
.type.ident
== "CacheMemory" or \
799 param
.type_ast
.type.ident
== "MemoryControl":
800 assert(param
.pointer
)
801 code(' m_${{param.ident}}_ptr->clearStats();')
804 m_profiler.clearStats();
805 AbstractController::clearStats();
809 if self
.EntryType
!= None:
812 // Set and Reset for cache_entry variable
814 $c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry)
816 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry;
820 $c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr)
822 m_cache_entry_ptr = 0;
826 if self
.TBEType
!= None:
829 // Set and Reset for tbe variable
831 $c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe)
833 m_tbe_ptr = m_new_tbe;
837 $c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr)
846 $c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr)
850 # Record cache contents for all associated caches.
853 for param
in self
.config_parameters
:
854 if param
.type_ast
.type.ident
== "CacheMemory":
855 assert(param
.pointer
)
856 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);')
864 if self
.TBEType
!= None and self
.EntryType
!= None:
865 for action
in self
.actions
.itervalues():
866 if "c_code" not in action
:
870 /** \\brief ${{action.desc}} */
872 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
874 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
875 ${{action["c_code"]}}
879 elif self
.TBEType
!= None:
880 for action
in self
.actions
.itervalues():
881 if "c_code" not in action
:
885 /** \\brief ${{action.desc}} */
887 $c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr)
889 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
890 ${{action["c_code"]}}
894 elif self
.EntryType
!= None:
895 for action
in self
.actions
.itervalues():
896 if "c_code" not in action
:
900 /** \\brief ${{action.desc}} */
902 $c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr)
904 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
905 ${{action["c_code"]}}
910 for action
in self
.actions
.itervalues():
911 if "c_code" not in action
:
915 /** \\brief ${{action.desc}} */
917 $c_ident::${{action.ident}}(const Address& addr)
919 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n");
920 ${{action["c_code"]}}
924 for func
in self
.functions
:
925 code(func
.generateCode())
927 # Function for functional reads from messages buffered in the controller
930 $c_ident::functionalReadBuffers(PacketPtr& pkt)
933 for var
in self
.objects
:
936 vid
= "m_%s_ptr" % var
.c_ident
937 code('if ($vid->functionalRead(pkt)) { return true; }')
943 # Function for functional writes to messages buffered in the controller
946 $c_ident::functionalWriteBuffers(PacketPtr& pkt)
948 uint32_t num_functional_writes = 0;
950 for var
in self
.objects
:
953 vid
= "m_%s_ptr" % var
.c_ident
954 code('num_functional_writes += $vid->functionalWrite(pkt);')
956 return num_functional_writes;
960 # Check if this controller has a peer, if yes then write the
961 # function for connecting to the peer.
966 $c_ident::getQueuesFromPeer(AbstractController *peer)
969 for var
in self
.objects
:
970 if "network" in var
and "physical_network" in var
and \
971 var
["network"] == "From":
973 m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}});
974 assert(m_${{var.c_ident}}_ptr != NULL);
975 m_${{var.c_ident}}_ptr->setReceiver(this);
980 code
.write(path
, "%s.cc" % c_ident
)
982 def printCWakeup(self
, path
, includes
):
983 '''Output the wakeup loop for the events'''
985 code
= self
.symtab
.codeFormatter()
988 outputRequest_types
= True
989 if len(self
.request_types
) == 0:
990 outputRequest_types
= False
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"
1008 if outputRequest_types
:
1009 code('''#include "mem/protocol/${ident}_RequestType.hh"''')
1012 #include "mem/protocol/Types.hh"
1013 #include "mem/ruby/common/Global.hh"
1014 #include "mem/ruby/system/System.hh"
1018 for include_path
in includes
:
1019 code('#include "${{include_path}}"')
1023 using namespace std;
1026 ${ident}_Controller::wakeup()
1030 // Some cases will put us into an infinite loop without this limit
1031 assert(counter <= m_transitions_per_cycle);
1032 if (counter == m_transitions_per_cycle) {
1033 // Count how often we are fully utilized
1034 m_fully_busy_cycles++;
1036 // Wakeup in another cycle and try again
1037 scheduleEvent(Cycles(1));
1047 for port
in self
.in_ports
:
1049 code('// ${ident}InPort $port')
1050 if port
.pairs
.has_key("rank"):
1051 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};')
1053 code('m_cur_in_port_rank = 0;')
1054 code('${{port["c_code_in_port"]}}')
1062 break; // If we got this far, we have nothing left todo
1067 code
.write(path
, "%s_Wakeup.cc" % self
.ident
)
1069 def printCSwitch(self
, path
):
1070 '''Output switch statement for transition table'''
1072 code
= self
.symtab
.codeFormatter()
1076 // Auto generated C++ code started by $__file__:$__line__
1077 // ${ident}: ${{self.short}}
1081 #include "base/misc.hh"
1082 #include "base/trace.hh"
1083 #include "debug/ProtocolTrace.hh"
1084 #include "debug/RubyGenerated.hh"
1085 #include "mem/protocol/${ident}_Controller.hh"
1086 #include "mem/protocol/${ident}_Event.hh"
1087 #include "mem/protocol/${ident}_State.hh"
1088 #include "mem/protocol/Types.hh"
1089 #include "mem/ruby/common/Global.hh"
1090 #include "mem/ruby/system/System.hh"
1092 #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event))
1094 #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str())
1095 #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str(""))
1098 ${ident}_Controller::doTransition(${ident}_Event event,
1100 if self
.EntryType
!= None:
1102 ${{self.EntryType.c_ident}}* m_cache_entry_ptr,
1104 if self
.TBEType
!= None:
1106 ${{self.TBEType.c_ident}}* m_tbe_ptr,
1109 const Address &addr)
1112 if self
.TBEType
!= None and self
.EntryType
!= None:
1113 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);')
1114 elif self
.TBEType
!= None:
1115 code('${ident}_State state = getState(m_tbe_ptr, addr);')
1116 elif self
.EntryType
!= None:
1117 code('${ident}_State state = getState(m_cache_entry_ptr, addr);')
1119 code('${ident}_State state = getState(addr);')
1122 ${ident}_State next_state = state;
1124 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n",
1125 *this, curCycle(), ${ident}_State_to_string(state),
1126 ${ident}_Event_to_string(event), addr);
1128 TransitionResult result =
1130 if self
.TBEType
!= None and self
.EntryType
!= None:
1131 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);')
1132 elif self
.TBEType
!= None:
1133 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);')
1134 elif self
.EntryType
!= None:
1135 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);')
1137 code('doTransitionWorker(event, state, next_state, addr);')
1140 if (result == TransitionResult_Valid) {
1141 DPRINTF(RubyGenerated, "next_state: %s\\n",
1142 ${ident}_State_to_string(next_state));
1143 m_profiler.countTransition(state, event);
1144 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n",
1145 curTick(), m_version, "${ident}",
1146 ${ident}_Event_to_string(event),
1147 ${ident}_State_to_string(state),
1148 ${ident}_State_to_string(next_state),
1149 addr, GET_TRANSITION_COMMENT());
1151 CLEAR_TRANSITION_COMMENT();
1153 if self
.TBEType
!= None and self
.EntryType
!= None:
1154 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);')
1155 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1156 elif self
.TBEType
!= None:
1157 code('setState(m_tbe_ptr, addr, next_state);')
1158 code('setAccessPermission(addr, next_state);')
1159 elif self
.EntryType
!= None:
1160 code('setState(m_cache_entry_ptr, addr, next_state);')
1161 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);')
1163 code('setState(addr, next_state);')
1164 code('setAccessPermission(addr, next_state);')
1167 } else if (result == TransitionResult_ResourceStall) {
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, "Resource Stall");
1174 } else if (result == TransitionResult_ProtocolStall) {
1175 DPRINTF(RubyGenerated, "stalling\\n");
1176 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n",
1177 curTick(), m_version, "${ident}",
1178 ${ident}_Event_to_string(event),
1179 ${ident}_State_to_string(state),
1180 ${ident}_State_to_string(next_state),
1181 addr, "Protocol Stall");
1188 ${ident}_Controller::doTransitionWorker(${ident}_Event event,
1189 ${ident}_State state,
1190 ${ident}_State& next_state,
1193 if self
.TBEType
!= None:
1195 ${{self.TBEType.c_ident}}*& m_tbe_ptr,
1197 if self
.EntryType
!= None:
1199 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr,
1202 const Address& addr)
1204 switch(HASH_FUN(state, event)) {
1207 # This map will allow suppress generating duplicate code
1210 for trans
in self
.transitions
:
1211 case_string
= "%s_State_%s, %s_Event_%s" % \
1212 (self
.ident
, trans
.state
.ident
, self
.ident
, trans
.event
.ident
)
1214 case
= self
.symtab
.codeFormatter()
1215 # Only set next_state if it changes
1216 if trans
.state
!= trans
.nextState
:
1217 ns_ident
= trans
.nextState
.ident
1218 case('next_state = ${ident}_State_${ns_ident};')
1220 actions
= trans
.actions
1221 request_types
= trans
.request_types
1223 # Check for resources
1225 res
= trans
.resources
1226 for key
,val
in res
.iteritems():
1227 if key
.type.ident
!= "DNUCAStopTable":
1229 if (!%s.areNSlotsAvailable(%s))
1230 return TransitionResult_ResourceStall;
1231 ''' % (key
.code
, val
)
1232 case_sorter
.append(val
)
1234 # Check all of the request_types for resource constraints
1235 for request_type
in request_types
:
1237 if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
1238 return TransitionResult_ResourceStall;
1240 ''' % (self
.ident
, request_type
.ident
)
1241 case_sorter
.append(val
)
1243 # Emit the code sequences in a sorted order. This makes the
1244 # output deterministic (without this the output order can vary
1245 # since Map's keys() on a vector of pointers is not deterministic
1246 for c
in sorted(case_sorter
):
1249 # Record access types for this transition
1250 for request_type
in request_types
:
1251 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);')
1253 # Figure out if we stall
1255 for action
in actions
:
1256 if action
.ident
== "z_stall":
1261 case('return TransitionResult_ProtocolStall;')
1263 if self
.TBEType
!= None and self
.EntryType
!= None:
1264 for action
in actions
:
1265 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);')
1266 elif self
.TBEType
!= None:
1267 for action
in actions
:
1268 case('${{action.ident}}(m_tbe_ptr, addr);')
1269 elif self
.EntryType
!= None:
1270 for action
in actions
:
1271 case('${{action.ident}}(m_cache_entry_ptr, addr);')
1273 for action
in actions
:
1274 case('${{action.ident}}(addr);')
1275 case('return TransitionResult_Valid;')
1279 # Look to see if this transition code is unique.
1280 if case
not in cases
:
1283 cases
[case
].append(case_string
)
1285 # Walk through all of the unique code blocks and spit out the
1286 # corresponding case statement elements
1287 for case
,transitions
in cases
.iteritems():
1288 # Iterative over all the multiple transitions that share
1290 for trans
in transitions
:
1291 code(' case HASH_FUN($trans):')
1296 fatal("Invalid transition\\n"
1297 "%s time: %d addr: %s event: %s state: %s\\n",
1298 name(), curCycle(), addr, event, state);
1300 return TransitionResult_Valid;
1303 code
.write(path
, "%s_Transitions.cc" % self
.ident
)
1305 def printProfileDumperHH(self
, path
):
1306 code
= self
.symtab
.codeFormatter()
1310 // Auto generated C++ code started by $__file__:$__line__
1311 // ${ident}: ${{self.short}}
1313 #ifndef __${ident}_PROFILE_DUMPER_HH__
1314 #define __${ident}_PROFILE_DUMPER_HH__
1320 #include "${ident}_Event.hh"
1321 #include "${ident}_Profiler.hh"
1323 typedef std::vector<${ident}_Profiler *> ${ident}_profilers;
1325 class ${ident}_ProfileDumper
1328 ${ident}_ProfileDumper();
1329 void registerProfiler(${ident}_Profiler* profiler);
1330 void dumpStats(std::ostream& out) const;
1333 ${ident}_profilers m_profilers;
1336 #endif // __${ident}_PROFILE_DUMPER_HH__
1338 code
.write(path
, "%s_ProfileDumper.hh" % self
.ident
)
1340 def printProfileDumperCC(self
, path
):
1341 code
= self
.symtab
.codeFormatter()
1345 // Auto generated C++ code started by $__file__:$__line__
1346 // ${ident}: ${{self.short}}
1348 #include "mem/protocol/${ident}_ProfileDumper.hh"
1350 ${ident}_ProfileDumper::${ident}_ProfileDumper()
1355 ${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler)
1357 m_profilers.push_back(profiler);
1361 ${ident}_ProfileDumper::dumpStats(std::ostream& out) const
1363 out << " --- ${ident} ---\\n";
1364 out << " - Event Counts -\\n";
1365 for (${ident}_Event event = ${ident}_Event_FIRST;
1366 event < ${ident}_Event_NUM;
1368 out << (${ident}_Event) event << " [";
1370 for (int i = 0; i < m_profilers.size(); i++) {
1371 out << m_profilers[i]->getEventCount(event) << " ";
1372 total += m_profilers[i]->getEventCount(event);
1374 out << "] " << total << "\\n";
1377 out << " - Transitions -\\n";
1378 for (${ident}_State state = ${ident}_State_FIRST;
1379 state < ${ident}_State_NUM;
1381 for (${ident}_Event event = ${ident}_Event_FIRST;
1382 event < ${ident}_Event_NUM;
1384 if (m_profilers[0]->isPossible(state, event)) {
1385 out << (${ident}_State) state << " "
1386 << (${ident}_Event) event << " [";
1388 for (int i = 0; i < m_profilers.size(); i++) {
1389 out << m_profilers[i]->getTransitionCount(state, event) << " ";
1390 total += m_profilers[i]->getTransitionCount(state, event);
1392 out << "] " << total << "\\n";
1399 code
.write(path
, "%s_ProfileDumper.cc" % self
.ident
)
1401 def printProfilerHH(self
, path
):
1402 code
= self
.symtab
.codeFormatter()
1406 // Auto generated C++ code started by $__file__:$__line__
1407 // ${ident}: ${{self.short}}
1409 #ifndef __${ident}_PROFILER_HH__
1410 #define __${ident}_PROFILER_HH__
1415 #include "mem/protocol/${ident}_Event.hh"
1416 #include "mem/protocol/${ident}_State.hh"
1417 #include "mem/ruby/common/TypeDefines.hh"
1419 class ${ident}_Profiler
1422 ${ident}_Profiler();
1423 void setVersion(int version);
1424 void countTransition(${ident}_State state, ${ident}_Event event);
1425 void possibleTransition(${ident}_State state, ${ident}_Event event);
1426 uint64 getEventCount(${ident}_Event event);
1427 bool isPossible(${ident}_State state, ${ident}_Event event);
1428 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event);
1432 int m_counters[${ident}_State_NUM][${ident}_Event_NUM];
1433 int m_event_counters[${ident}_Event_NUM];
1434 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM];
1438 #endif // __${ident}_PROFILER_HH__
1440 code
.write(path
, "%s_Profiler.hh" % self
.ident
)
1442 def printProfilerCC(self
, path
):
1443 code
= self
.symtab
.codeFormatter()
1447 // Auto generated C++ code started by $__file__:$__line__
1448 // ${ident}: ${{self.short}}
1452 #include "mem/protocol/${ident}_Profiler.hh"
1454 ${ident}_Profiler::${ident}_Profiler()
1456 for (int state = 0; state < ${ident}_State_NUM; state++) {
1457 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1458 m_possible[state][event] = false;
1459 m_counters[state][event] = 0;
1462 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1463 m_event_counters[event] = 0;
1468 ${ident}_Profiler::setVersion(int version)
1470 m_version = version;
1474 ${ident}_Profiler::clearStats()
1476 for (int state = 0; state < ${ident}_State_NUM; state++) {
1477 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1478 m_counters[state][event] = 0;
1482 for (int event = 0; event < ${ident}_Event_NUM; event++) {
1483 m_event_counters[event] = 0;
1487 ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event)
1489 assert(m_possible[state][event]);
1490 m_counters[state][event]++;
1491 m_event_counters[event]++;
1494 ${ident}_Profiler::possibleTransition(${ident}_State state,
1495 ${ident}_Event event)
1497 m_possible[state][event] = true;
1501 ${ident}_Profiler::getEventCount(${ident}_Event event)
1503 return m_event_counters[event];
1507 ${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event)
1509 return m_possible[state][event];
1513 ${ident}_Profiler::getTransitionCount(${ident}_State state,
1514 ${ident}_Event event)
1516 return m_counters[state][event];
1520 code
.write(path
, "%s_Profiler.cc" % self
.ident
)
1522 # **************************
1523 # ******* HTML Files *******
1524 # **************************
1525 def frameRef(self
, click_href
, click_target
, over_href
, over_num
, text
):
1526 code
= self
.symtab
.codeFormatter(fix_newlines
=False)
1527 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\"
1528 if (parent.frames[$over_num].location != parent.location + '$over_href') {
1529 parent.frames[$over_num].location='$over_href'
1531 ${{html.formatShorthand(text)}}
1535 def writeHTMLFiles(self
, path
):
1536 # Create table with no row hilighted
1537 self
.printHTMLTransitions(path
, None)
1539 # Generate transition tables
1540 for state
in self
.states
.itervalues():
1541 self
.printHTMLTransitions(path
, state
)
1543 # Generate action descriptions
1544 for action
in self
.actions
.itervalues():
1545 name
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1546 code
= html
.createSymbol(action
, "Action")
1547 code
.write(path
, name
)
1549 # Generate state descriptions
1550 for state
in self
.states
.itervalues():
1551 name
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1552 code
= html
.createSymbol(state
, "State")
1553 code
.write(path
, name
)
1555 # Generate event descriptions
1556 for event
in self
.events
.itervalues():
1557 name
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1558 code
= html
.createSymbol(event
, "Event")
1559 code
.write(path
, name
)
1561 def printHTMLTransitions(self
, path
, active_state
):
1562 code
= self
.symtab
.codeFormatter()
1566 <BODY link="blue" vlink="blue">
1568 <H1 align="center">${{html.formatShorthand(self.short)}}:
1571 for i
,machine
in enumerate(self
.symtab
.getAllType(StateMachine
)):
1580 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>')
1591 for event
in self
.events
.itervalues():
1592 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1593 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1594 code('<TH bgcolor=white>$ref</TH>')
1598 for state
in self
.states
.itervalues():
1600 if state
== active_state
:
1605 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1606 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1607 text
= html
.formatShorthand(state
.short
)
1608 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1611 <TH bgcolor=$color>$ref</TH>
1614 # -- One column for each event
1615 for event
in self
.events
.itervalues():
1616 trans
= self
.table
.get((state
,event
), None)
1618 # This is the no transition case
1619 if state
== active_state
:
1624 code('<TD bgcolor=$color> </TD>')
1627 next
= trans
.nextState
1628 stall_action
= False
1630 # -- Get the actions
1631 for action
in trans
.actions
:
1632 if action
.ident
== "z_stall" or \
1633 action
.ident
== "zz_recycleMandatoryQueue":
1636 # -- Print out "actions/next-state"
1638 if state
== active_state
:
1643 elif active_state
and next
.ident
== active_state
.ident
:
1645 elif state
== active_state
:
1650 code('<TD bgcolor=$color>')
1651 for action
in trans
.actions
:
1652 href
= "%s_action_%s.html" % (self
.ident
, action
.ident
)
1653 ref
= self
.frameRef(href
, "Status", href
, "1",
1659 click
= "%s_table_%s.html" % (self
.ident
, next
.ident
)
1660 over
= "%s_State_%s.html" % (self
.ident
, next
.ident
)
1661 ref
= self
.frameRef(click
, "Table", over
, "1", next
.short
)
1666 if state
== active_state
:
1671 click
= "%s_table_%s.html" % (self
.ident
, state
.ident
)
1672 over
= "%s_State_%s.html" % (self
.ident
, state
.ident
)
1673 ref
= self
.frameRef(click
, "Table", over
, "1", state
.short
)
1675 <TH bgcolor=$color>$ref</TH>
1684 for event
in self
.events
.itervalues():
1685 href
= "%s_Event_%s.html" % (self
.ident
, event
.ident
)
1686 ref
= self
.frameRef(href
, "Status", href
, "1", event
.short
)
1687 code('<TH bgcolor=white>$ref</TH>')
1696 name
= "%s_table_%s.html" % (self
.ident
, active_state
.ident
)
1698 name
= "%s_table.html" % self
.ident
1699 code
.write(path
, name
)
1701 __all__
= [ "StateMachine" ]