1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 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. 15# 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. 27 28from m5.util import orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33import re 34 35python_class_map = { 36 "int": "Int", 37 "uint32_t" : "UInt32", 38 "std::string": "String", 39 "bool": "Bool", 40 "CacheMemory": "RubyCache", 41 "WireBuffer": "RubyWireBuffer", 42 "Sequencer": "RubySequencer", 43 "DirectoryMemory": "RubyDirectoryMemory", 44 "MemoryControl": "MemoryControl", 45 "DMASequencer": "DMASequencer", 46 "Prefetcher":"Prefetcher", 47 "Cycles":"Cycles", 48 } 49 50class StateMachine(Symbol): 51 def __init__(self, symtab, ident, location, pairs, config_parameters): 52 super(StateMachine, self).__init__(symtab, ident, location, pairs) 53 self.table = None 54 self.config_parameters = config_parameters 55 self.prefetchers = [] 56 57 for param in config_parameters: 58 if param.pointer: 59 var = Var(symtab, param.name, location, param.type_ast.type, 60 "(*m_%s_ptr)" % param.name, {}, self) 61 else: 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) 67 68 self.states = orderdict() 69 self.events = orderdict() 70 self.actions = orderdict() 71 self.request_types = orderdict() 72 self.transitions = [] 73 self.in_ports = [] 74 self.functions = [] 75 self.objects = [] 76 self.TBEType = None 77 self.EntryType = None 78 79 def __repr__(self): 80 return "[StateMachine: %s]" % self.ident 81 82 def addState(self, state): 83 assert self.table is None 84 self.states[state.ident] = state 85 86 def addEvent(self, event): 87 assert self.table is None 88 self.events[event.ident] = event 89 90 def addAction(self, action): 91 assert self.table is None 92 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) 103 104 self.actions[action.ident] = action 105 106 def addRequestType(self, request_type): 107 assert self.table is None 108 self.request_types[request_type.ident] = request_type 109 110 def addTransition(self, trans): 111 assert self.table is None 112 self.transitions.append(trans) 113 114 def addInPort(self, var): 115 self.in_ports.append(var) 116 117 def addFunc(self, func): 118 # register func in the symbol table 119 self.symtab.registerSym(str(func), func) 120 self.functions.append(func) 121 122 def addObject(self, obj): 123 self.objects.append(obj) 124 125 def addType(self, type): 126 type_ident = '%s' % type.c_ident 127 128 if type_ident == "%s_TBE" %self.ident: 129 if self.TBEType != None: 130 self.error("Multiple Transaction Buffer types in a " \ 131 "single machine."); 132 self.TBEType = type 133 134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 135 if self.EntryType != None: 136 self.error("Multiple AbstractCacheEntry types in a " \ 137 "single machine."); 138 self.EntryType = type 139 140 # Needs to be called before accessing the table 141 def buildTable(self): 142 assert self.table is None 143 144 table = {} 145 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. 151 152 for action in trans.actions: 153 action.used = True 154 155 index = (trans.state, trans.event) 156 if index in table: 157 table[index].warning("Duplicate transition: %s" % table[index]) 158 trans.error("Duplicate transition: %s" % trans) 159 table[index] = trans 160 161 # Look at all actions to make sure we used them all 162 for action in self.actions.itervalues(): 163 if not action.used: 164 error_msg = "Unused action: %s" % action.ident 165 if "desc" in action: 166 error_msg += ", " + action.desc 167 action.warning(error_msg) 168 self.table = table 169 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) 180 181 def printControllerPython(self, path): 182 code = self.symtab.codeFormatter() 183 ident = self.ident 184 py_ident = "%s_Controller" % ident 185 c_ident = "%s_Controller" % self.ident 186 code(''' 187from m5.params import * 188from m5.SimObject import SimObject 189from Controller import RubyController 190 191class $py_ident(RubyController): 192 type = '$py_ident' 193 cxx_header = 'mem/protocol/${c_ident}.hh' 194''') 195 code.indent() 196 for param in self.config_parameters: 197 dflt_str = '' 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}"")') 203 else: 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) 207 code.dedent() 208 code.write(path, '%s.py' % py_ident) 209 210 211 def printControllerHH(self, path): 212 '''Output the method declarations for the class declaration''' 213 code = self.symtab.codeFormatter() 214 ident = self.ident 215 c_ident = "%s_Controller" % self.ident 216 217 code(''' 218/** \\file $c_ident.hh 219 * 220 * Auto generated C++ code started by $__file__:$__line__ 221 * Created by slicc definition of Module "${{self.short}}" 222 */ 223 224#ifndef __${ident}_CONTROLLER_HH__ 225#define __${ident}_CONTROLLER_HH__ 226 227#include <iostream> 228#include <sstream> 229#include <string> 230 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" 239''') 240 241 seen_types = set() 242 has_peer = False 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: 247 has_peer = True 248 seen_types.add(var.type.ident) 249 250 # for adding information to the protocol debug trace 251 code(''' 252extern std::stringstream ${ident}_transitionComment; 253 254class $c_ident : public AbstractController 255{ 256 public: 257 typedef ${c_ident}Params Params; 258 $c_ident(const Params *p); 259 static int getNumControllers(); 260 void init(); 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; 267 void wakeup(); 268 void printStats(std::ostream& out) const; 269 void clearStats(); 270 void blockOnQueue(Address addr, MessageBuffer* port); 271 void unblock(Address addr); 272 void recordCacheTrace(int cntrl, CacheRecorder* tr); 273 Sequencer* getSequencer() const; 274 275 bool functionalReadBuffers(PacketPtr&); 276 uint32_t functionalWriteBuffers(PacketPtr&); 277 278private: 279''') 280 281 code.indent() 282 # added by SS 283 for param in self.config_parameters: 284 if param.pointer: 285 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 286 else: 287 code('${{param.type_ast.type}} m_${{param.ident}};') 288 289 code(''' 290TransitionResult doTransition(${ident}_Event event, 291''') 292 293 if self.EntryType != None: 294 code(''' 295 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 296''') 297 if self.TBEType != None: 298 code(''' 299 ${{self.TBEType.c_ident}}* m_tbe_ptr, 300''') 301 302 code(''' 303 const Address& addr); 304 305TransitionResult doTransitionWorker(${ident}_Event event, 306 ${ident}_State state, 307 ${ident}_State& next_state, 308''') 309 310 if self.TBEType != None: 311 code(''' 312 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 313''') 314 if self.EntryType != None: 315 code(''' 316 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 317''') 318 319 code(''' 320 const Address& addr); 321 322static ${ident}_ProfileDumper s_profileDumper; 323${ident}_Profiler m_profiler; 324static int m_num_controllers; 325 326// Internal functions 327''') 328 329 for func in self.functions: 330 proto = func.prototype 331 if proto: 332 code('$proto') 333 334 if has_peer: 335 code('void getQueuesFromPeer(AbstractController *);') 336 if self.EntryType != None: 337 code(''' 338 339// Set and Reset for cache_entry variable 340void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 341void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 342''') 343 344 if self.TBEType != None: 345 code(''' 346 347// Set and Reset for tbe variable 348void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 349void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 350''') 351 352 code(''' 353 354// Actions 355''') 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);') 368 else: 369 for action in self.actions.itervalues(): 370 code('/** \\brief ${{action.desc}} */') 371 code('void ${{action.ident}}(const Address& addr);') 372 373 # the controller internal variables 374 code(''' 375 376// Objects 377''') 378 for var in self.objects: 379 th = var.get("template", "") 380 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 381 382 code.dedent() 383 code('};') 384 code('#endif // __${ident}_CONTROLLER_H__') 385 code.write(path, '%s.hh' % c_ident) 386 387 def printControllerCC(self, path, includes): 388 '''Output the actions for performing the actions''' 389 390 code = self.symtab.codeFormatter() 391 ident = self.ident 392 c_ident = "%s_Controller" % self.ident 393 has_peer = False 394 395 code(''' 396/** \\file $c_ident.cc 397 * 398 * Auto generated C++ code started by $__file__:$__line__ 399 * Created by slicc definition of Module "${{self.short}}" 400 */ 401 402#include <sys/types.h> 403#include <unistd.h> 404 405#include <cassert> 406#include <sstream> 407#include <string> 408 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" 419''') 420 for include_path in includes: 421 code('#include "${{include_path}}"') 422 423 code(''' 424 425using namespace std; 426''') 427 428 # include object classes 429 seen_types = set() 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) 434 435 code(''' 436$c_ident * 437${c_ident}Params::create() 438{ 439 return new $c_ident(this); 440} 441 442int $c_ident::m_num_controllers = 0; 443${ident}_ProfileDumper $c_ident::s_profileDumper; 444 445// for adding information to the protocol debug trace 446stringstream ${ident}_transitionComment; 447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 448 449/** \\brief constructor */ 450$c_ident::$c_ident(const Params *p) 451 : AbstractController(p) 452{ 453 m_name = "${ident}"; 454''') 455 # 456 # max_port_rank is used to size vectors and thus should be one plus the 457 # largest port rank 458 # 459 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 460 code(' m_max_in_port_rank = $max_port_rank;') 461 code.indent() 462 463 # 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. 468 # 469 contains_dma_sequencer = False 470 sequencers = [] 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) 476 if param.pointer: 477 code('m_${{param.name}}_ptr = p->${{param.name}};') 478 else: 479 code('m_${{param.name}} = p->${{param.name}};') 480 481 # 482 # For the l1 cache controller, add the special atomic support which 483 # includes passing the sequencer a pointer to the controller. 484 #
| 1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 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. 15# 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. 27 28from m5.util import orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33import re 34 35python_class_map = { 36 "int": "Int", 37 "uint32_t" : "UInt32", 38 "std::string": "String", 39 "bool": "Bool", 40 "CacheMemory": "RubyCache", 41 "WireBuffer": "RubyWireBuffer", 42 "Sequencer": "RubySequencer", 43 "DirectoryMemory": "RubyDirectoryMemory", 44 "MemoryControl": "MemoryControl", 45 "DMASequencer": "DMASequencer", 46 "Prefetcher":"Prefetcher", 47 "Cycles":"Cycles", 48 } 49 50class StateMachine(Symbol): 51 def __init__(self, symtab, ident, location, pairs, config_parameters): 52 super(StateMachine, self).__init__(symtab, ident, location, pairs) 53 self.table = None 54 self.config_parameters = config_parameters 55 self.prefetchers = [] 56 57 for param in config_parameters: 58 if param.pointer: 59 var = Var(symtab, param.name, location, param.type_ast.type, 60 "(*m_%s_ptr)" % param.name, {}, self) 61 else: 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) 67 68 self.states = orderdict() 69 self.events = orderdict() 70 self.actions = orderdict() 71 self.request_types = orderdict() 72 self.transitions = [] 73 self.in_ports = [] 74 self.functions = [] 75 self.objects = [] 76 self.TBEType = None 77 self.EntryType = None 78 79 def __repr__(self): 80 return "[StateMachine: %s]" % self.ident 81 82 def addState(self, state): 83 assert self.table is None 84 self.states[state.ident] = state 85 86 def addEvent(self, event): 87 assert self.table is None 88 self.events[event.ident] = event 89 90 def addAction(self, action): 91 assert self.table is None 92 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) 103 104 self.actions[action.ident] = action 105 106 def addRequestType(self, request_type): 107 assert self.table is None 108 self.request_types[request_type.ident] = request_type 109 110 def addTransition(self, trans): 111 assert self.table is None 112 self.transitions.append(trans) 113 114 def addInPort(self, var): 115 self.in_ports.append(var) 116 117 def addFunc(self, func): 118 # register func in the symbol table 119 self.symtab.registerSym(str(func), func) 120 self.functions.append(func) 121 122 def addObject(self, obj): 123 self.objects.append(obj) 124 125 def addType(self, type): 126 type_ident = '%s' % type.c_ident 127 128 if type_ident == "%s_TBE" %self.ident: 129 if self.TBEType != None: 130 self.error("Multiple Transaction Buffer types in a " \ 131 "single machine."); 132 self.TBEType = type 133 134 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 135 if self.EntryType != None: 136 self.error("Multiple AbstractCacheEntry types in a " \ 137 "single machine."); 138 self.EntryType = type 139 140 # Needs to be called before accessing the table 141 def buildTable(self): 142 assert self.table is None 143 144 table = {} 145 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. 151 152 for action in trans.actions: 153 action.used = True 154 155 index = (trans.state, trans.event) 156 if index in table: 157 table[index].warning("Duplicate transition: %s" % table[index]) 158 trans.error("Duplicate transition: %s" % trans) 159 table[index] = trans 160 161 # Look at all actions to make sure we used them all 162 for action in self.actions.itervalues(): 163 if not action.used: 164 error_msg = "Unused action: %s" % action.ident 165 if "desc" in action: 166 error_msg += ", " + action.desc 167 action.warning(error_msg) 168 self.table = table 169 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) 180 181 def printControllerPython(self, path): 182 code = self.symtab.codeFormatter() 183 ident = self.ident 184 py_ident = "%s_Controller" % ident 185 c_ident = "%s_Controller" % self.ident 186 code(''' 187from m5.params import * 188from m5.SimObject import SimObject 189from Controller import RubyController 190 191class $py_ident(RubyController): 192 type = '$py_ident' 193 cxx_header = 'mem/protocol/${c_ident}.hh' 194''') 195 code.indent() 196 for param in self.config_parameters: 197 dflt_str = '' 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}"")') 203 else: 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) 207 code.dedent() 208 code.write(path, '%s.py' % py_ident) 209 210 211 def printControllerHH(self, path): 212 '''Output the method declarations for the class declaration''' 213 code = self.symtab.codeFormatter() 214 ident = self.ident 215 c_ident = "%s_Controller" % self.ident 216 217 code(''' 218/** \\file $c_ident.hh 219 * 220 * Auto generated C++ code started by $__file__:$__line__ 221 * Created by slicc definition of Module "${{self.short}}" 222 */ 223 224#ifndef __${ident}_CONTROLLER_HH__ 225#define __${ident}_CONTROLLER_HH__ 226 227#include <iostream> 228#include <sstream> 229#include <string> 230 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" 239''') 240 241 seen_types = set() 242 has_peer = False 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: 247 has_peer = True 248 seen_types.add(var.type.ident) 249 250 # for adding information to the protocol debug trace 251 code(''' 252extern std::stringstream ${ident}_transitionComment; 253 254class $c_ident : public AbstractController 255{ 256 public: 257 typedef ${c_ident}Params Params; 258 $c_ident(const Params *p); 259 static int getNumControllers(); 260 void init(); 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; 267 void wakeup(); 268 void printStats(std::ostream& out) const; 269 void clearStats(); 270 void blockOnQueue(Address addr, MessageBuffer* port); 271 void unblock(Address addr); 272 void recordCacheTrace(int cntrl, CacheRecorder* tr); 273 Sequencer* getSequencer() const; 274 275 bool functionalReadBuffers(PacketPtr&); 276 uint32_t functionalWriteBuffers(PacketPtr&); 277 278private: 279''') 280 281 code.indent() 282 # added by SS 283 for param in self.config_parameters: 284 if param.pointer: 285 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 286 else: 287 code('${{param.type_ast.type}} m_${{param.ident}};') 288 289 code(''' 290TransitionResult doTransition(${ident}_Event event, 291''') 292 293 if self.EntryType != None: 294 code(''' 295 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 296''') 297 if self.TBEType != None: 298 code(''' 299 ${{self.TBEType.c_ident}}* m_tbe_ptr, 300''') 301 302 code(''' 303 const Address& addr); 304 305TransitionResult doTransitionWorker(${ident}_Event event, 306 ${ident}_State state, 307 ${ident}_State& next_state, 308''') 309 310 if self.TBEType != None: 311 code(''' 312 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 313''') 314 if self.EntryType != None: 315 code(''' 316 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 317''') 318 319 code(''' 320 const Address& addr); 321 322static ${ident}_ProfileDumper s_profileDumper; 323${ident}_Profiler m_profiler; 324static int m_num_controllers; 325 326// Internal functions 327''') 328 329 for func in self.functions: 330 proto = func.prototype 331 if proto: 332 code('$proto') 333 334 if has_peer: 335 code('void getQueuesFromPeer(AbstractController *);') 336 if self.EntryType != None: 337 code(''' 338 339// Set and Reset for cache_entry variable 340void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 341void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 342''') 343 344 if self.TBEType != None: 345 code(''' 346 347// Set and Reset for tbe variable 348void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 349void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 350''') 351 352 code(''' 353 354// Actions 355''') 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);') 368 else: 369 for action in self.actions.itervalues(): 370 code('/** \\brief ${{action.desc}} */') 371 code('void ${{action.ident}}(const Address& addr);') 372 373 # the controller internal variables 374 code(''' 375 376// Objects 377''') 378 for var in self.objects: 379 th = var.get("template", "") 380 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 381 382 code.dedent() 383 code('};') 384 code('#endif // __${ident}_CONTROLLER_H__') 385 code.write(path, '%s.hh' % c_ident) 386 387 def printControllerCC(self, path, includes): 388 '''Output the actions for performing the actions''' 389 390 code = self.symtab.codeFormatter() 391 ident = self.ident 392 c_ident = "%s_Controller" % self.ident 393 has_peer = False 394 395 code(''' 396/** \\file $c_ident.cc 397 * 398 * Auto generated C++ code started by $__file__:$__line__ 399 * Created by slicc definition of Module "${{self.short}}" 400 */ 401 402#include <sys/types.h> 403#include <unistd.h> 404 405#include <cassert> 406#include <sstream> 407#include <string> 408 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" 419''') 420 for include_path in includes: 421 code('#include "${{include_path}}"') 422 423 code(''' 424 425using namespace std; 426''') 427 428 # include object classes 429 seen_types = set() 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) 434 435 code(''' 436$c_ident * 437${c_ident}Params::create() 438{ 439 return new $c_ident(this); 440} 441 442int $c_ident::m_num_controllers = 0; 443${ident}_ProfileDumper $c_ident::s_profileDumper; 444 445// for adding information to the protocol debug trace 446stringstream ${ident}_transitionComment; 447#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 448 449/** \\brief constructor */ 450$c_ident::$c_ident(const Params *p) 451 : AbstractController(p) 452{ 453 m_name = "${ident}"; 454''') 455 # 456 # max_port_rank is used to size vectors and thus should be one plus the 457 # largest port rank 458 # 459 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 460 code(' m_max_in_port_rank = $max_port_rank;') 461 code.indent() 462 463 # 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. 468 # 469 contains_dma_sequencer = False 470 sequencers = [] 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) 476 if param.pointer: 477 code('m_${{param.name}}_ptr = p->${{param.name}};') 478 else: 479 code('m_${{param.name}} = p->${{param.name}};') 480 481 # 482 # For the l1 cache controller, add the special atomic support which 483 # includes passing the sequencer a pointer to the controller. 484 #
|
501 # 502 # For the DMA controller, pass the sequencer a pointer to the 503 # controller. 504 # 505 if self.ident == "DMA": 506 if not contains_dma_sequencer: 507 self.error("The DMA controller must include the sequencer " \ 508 "configuration parameter") 509 510 code(''' 511m_dma_sequencer_ptr->setController(this); 512''') 513 514 code('m_num_controllers++;') 515 for var in self.objects: 516 if var.ident.find("mandatoryQueue") >= 0: 517 code(''' 518m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 519m_${{var.c_ident}}_ptr->setReceiver(this); 520''') 521 else: 522 if "network" in var and "physical_network" in var and \ 523 var["network"] == "To": 524 has_peer = True 525 code(''' 526m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 527peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr; 528m_${{var.c_ident}}_ptr->setSender(this); 529''') 530 531 code(''' 532if (p->peer != NULL) 533 connectWithPeer(p->peer); 534''') 535 code.dedent() 536 code(''' 537} 538 539void 540$c_ident::init() 541{ 542 MachineType machine_type; 543 int base; 544 machine_type = string_to_MachineType("${{var.machine.ident}}"); 545 base = MachineType_base_number(machine_type); 546 547 m_machineID.type = MachineType_${ident}; 548 m_machineID.num = m_version; 549 550 // initialize objects 551 m_profiler.setVersion(m_version); 552 s_profileDumper.registerProfiler(&m_profiler); 553 554''') 555 556 code.indent() 557 for var in self.objects: 558 vtype = var.type 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}};') 564 if "default" in var: 565 code('(*$vid) = ${{var["default"]}};') 566 else: 567 # Normal Object 568 if var.ident.find("mandatoryQueue") < 0: 569 th = var.get("template", "") 570 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 571 args = "" 572 if "non_obj" not in vtype and not vtype.isEnumeration: 573 args = var.get("constructor", "") 574 code('$expr($args);') 575 576 code('assert($vid != NULL);') 577 578 if "default" in var: 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') 583 584 # Set ordering 585 if "ordered" in var: 586 # A buffer 587 code('$vid->setOrdering(${{var["ordered"]}});') 588 589 # Set randomization 590 if "random" in var: 591 # A buffer 592 code('$vid->setRandomization(${{var["random"]}});') 593 594 # Set Priority 595 if vtype.isBuffer and "rank" in var: 596 code('$vid->setPriority(${{var["rank"]}});') 597 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);') 604 605 else: 606 # Network port object 607 network = var["network"] 608 ordered = var["ordered"] 609 610 if "virtual_network" in var: 611 vnet = var["virtual_network"] 612 vnet_type = var["vnet_type"] 613 614 assert var.machine is not None 615 code(''' 616$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 617assert($vid != NULL); 618''') 619 620 # Set the end 621 if network == "To": 622 code('$vid->setSender(this);') 623 else: 624 code('$vid->setReceiver(this);') 625 626 # Set ordering 627 if "ordered" in var: 628 # A buffer 629 code('$vid->setOrdering(${{var["ordered"]}});') 630 631 # Set randomization 632 if "random" in var: 633 # A buffer 634 code('$vid->setRandomization(${{var["random"]}});') 635 636 # Set Priority 637 if "rank" in var: 638 code('$vid->setPriority(${{var["rank"]}})') 639 640 # Set buffer size 641 if vtype.isBuffer: 642 code(''' 643if (m_buffer_size > 0) { 644 $vid->resize(m_buffer_size); 645} 646''') 647 648 # set description (may be overriden later by port def) 649 code(''' 650$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 651 652''') 653 654 if vtype.isBuffer: 655 if "recycle_latency" in var: 656 code('$vid->setRecycleLatency( ' \ 657 'Cycles(${{var["recycle_latency"]}}));') 658 else: 659 code('$vid->setRecycleLatency(m_recycle_latency);') 660 661 # Set the prefetchers 662 code() 663 for prefetcher in self.prefetchers: 664 code('${{prefetcher.code}}.setController(this);') 665 666 code() 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]");') 672 673 # Initialize the transition profiling 674 code() 675 for trans in self.transitions: 676 # Figure out if we stall 677 stall = False 678 for action in trans.actions: 679 if action.ident == "z_stall": 680 stall = True 681 682 # Only possible if it is not a 'z' case 683 if not stall: 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);') 687 688 code.dedent() 689 code(''' 690 AbstractController::init(); 691 clearStats(); 692} 693''') 694 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 699 700 if has_mandatory_q: 701 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 702 else: 703 mq_ident = "NULL" 704 705 seq_ident = "NULL" 706 for param in self.config_parameters: 707 if param.name == "sequencer": 708 assert(param.pointer) 709 seq_ident = "m_%s_ptr" % param.name 710 711 code(''' 712int 713$c_ident::getNumControllers() 714{ 715 return m_num_controllers; 716} 717 718MessageBuffer* 719$c_ident::getMandatoryQueue() const 720{ 721 return $mq_ident; 722} 723 724Sequencer* 725$c_ident::getSequencer() const 726{ 727 return $seq_ident; 728} 729 730const int & 731$c_ident::getVersion() const 732{ 733 return m_version; 734} 735 736const string 737$c_ident::toString() const 738{ 739 return "$c_ident"; 740} 741 742const string 743$c_ident::getName() const 744{ 745 return m_name; 746} 747 748void 749$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 750{ 751 m_is_blocking = true; 752 m_block_map[addr] = port; 753} 754 755void 756$c_ident::unblock(Address addr) 757{ 758 m_block_map.erase(addr); 759 if (m_block_map.size() == 0) { 760 m_is_blocking = false; 761 } 762} 763 764void 765$c_ident::print(ostream& out) const 766{ 767 out << "[$c_ident " << m_version << "]"; 768} 769 770void 771$c_ident::printStats(ostream& out) const 772{ 773''') 774 # 775 # Cache and Memory Controllers have specific profilers associated with 776 # them. Print out these stats before dumping state transition stats. 777 # 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);') 784 785 code(''' 786 if (m_version == 0) { 787 s_profileDumper.dumpStats(out); 788 } 789} 790 791void $c_ident::clearStats() { 792''') 793 # 794 # Cache and Memory Controllers have specific profilers associated with 795 # them. These stats must be cleared too. 796 # 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();') 802 803 code(''' 804 m_profiler.clearStats(); 805 AbstractController::clearStats(); 806} 807''') 808 809 if self.EntryType != None: 810 code(''' 811 812// Set and Reset for cache_entry variable 813void 814$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 815{ 816 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 817} 818 819void 820$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 821{ 822 m_cache_entry_ptr = 0; 823} 824''') 825 826 if self.TBEType != None: 827 code(''' 828 829// Set and Reset for tbe variable 830void 831$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 832{ 833 m_tbe_ptr = m_new_tbe; 834} 835 836void 837$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 838{ 839 m_tbe_ptr = NULL; 840} 841''') 842 843 code(''' 844 845void 846$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 847{ 848''') 849 # 850 # Record cache contents for all associated caches. 851 # 852 code.indent() 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);') 857 858 code.dedent() 859 code(''' 860} 861 862// Actions 863''') 864 if self.TBEType != None and self.EntryType != None: 865 for action in self.actions.itervalues(): 866 if "c_code" not in action: 867 continue 868 869 code(''' 870/** \\brief ${{action.desc}} */ 871void 872$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 873{ 874 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 875 ${{action["c_code"]}} 876} 877 878''') 879 elif self.TBEType != None: 880 for action in self.actions.itervalues(): 881 if "c_code" not in action: 882 continue 883 884 code(''' 885/** \\brief ${{action.desc}} */ 886void 887$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 888{ 889 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 890 ${{action["c_code"]}} 891} 892 893''') 894 elif self.EntryType != None: 895 for action in self.actions.itervalues(): 896 if "c_code" not in action: 897 continue 898 899 code(''' 900/** \\brief ${{action.desc}} */ 901void 902$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 903{ 904 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 905 ${{action["c_code"]}} 906} 907 908''') 909 else: 910 for action in self.actions.itervalues(): 911 if "c_code" not in action: 912 continue 913 914 code(''' 915/** \\brief ${{action.desc}} */ 916void 917$c_ident::${{action.ident}}(const Address& addr) 918{ 919 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 920 ${{action["c_code"]}} 921} 922 923''') 924 for func in self.functions: 925 code(func.generateCode()) 926 927 # Function for functional reads from messages buffered in the controller 928 code(''' 929bool 930$c_ident::functionalReadBuffers(PacketPtr& pkt) 931{ 932''') 933 for var in self.objects: 934 vtype = var.type 935 if vtype.isBuffer: 936 vid = "m_%s_ptr" % var.c_ident 937 code('if ($vid->functionalRead(pkt)) { return true; }') 938 code(''' 939 return false; 940} 941''') 942 943 # Function for functional writes to messages buffered in the controller 944 code(''' 945uint32_t 946$c_ident::functionalWriteBuffers(PacketPtr& pkt) 947{ 948 uint32_t num_functional_writes = 0; 949''') 950 for var in self.objects: 951 vtype = var.type 952 if vtype.isBuffer: 953 vid = "m_%s_ptr" % var.c_ident 954 code('num_functional_writes += $vid->functionalWrite(pkt);') 955 code(''' 956 return num_functional_writes; 957} 958''') 959 960 # Check if this controller has a peer, if yes then write the 961 # function for connecting to the peer. 962 if has_peer: 963 code(''' 964 965void 966$c_ident::getQueuesFromPeer(AbstractController *peer) 967{ 968''') 969 for var in self.objects: 970 if "network" in var and "physical_network" in var and \ 971 var["network"] == "From": 972 code(''' 973m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 974assert(m_${{var.c_ident}}_ptr != NULL); 975m_${{var.c_ident}}_ptr->setReceiver(this); 976 977''') 978 code('}') 979 980 code.write(path, "%s.cc" % c_ident) 981 982 def printCWakeup(self, path, includes): 983 '''Output the wakeup loop for the events''' 984 985 code = self.symtab.codeFormatter() 986 ident = self.ident 987 988 outputRequest_types = True 989 if len(self.request_types) == 0: 990 outputRequest_types = False 991 992 code(''' 993// Auto generated C++ code started by $__file__:$__line__ 994// ${ident}: ${{self.short}} 995 996#include <sys/types.h> 997#include <unistd.h> 998 999#include <cassert> 1000 1001#include "base/misc.hh" 1002#include "debug/RubySlicc.hh" 1003#include "mem/protocol/${ident}_Controller.hh" 1004#include "mem/protocol/${ident}_Event.hh" 1005#include "mem/protocol/${ident}_State.hh" 1006''') 1007 1008 if outputRequest_types: 1009 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1010 1011 code(''' 1012#include "mem/protocol/Types.hh" 1013#include "mem/ruby/common/Global.hh" 1014#include "mem/ruby/system/System.hh" 1015''') 1016 1017 1018 for include_path in includes: 1019 code('#include "${{include_path}}"') 1020 1021 code(''' 1022 1023using namespace std; 1024 1025void 1026${ident}_Controller::wakeup() 1027{ 1028 int counter = 0; 1029 while (true) { 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++; 1035 1036 // Wakeup in another cycle and try again 1037 scheduleEvent(Cycles(1)); 1038 break; 1039 } 1040''') 1041 1042 code.indent() 1043 code.indent() 1044 1045 # InPorts 1046 # 1047 for port in self.in_ports: 1048 code.indent() 1049 code('// ${ident}InPort $port') 1050 if port.pairs.has_key("rank"): 1051 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1052 else: 1053 code('m_cur_in_port_rank = 0;') 1054 code('${{port["c_code_in_port"]}}') 1055 code.dedent() 1056 1057 code('') 1058 1059 code.dedent() 1060 code.dedent() 1061 code(''' 1062 break; // If we got this far, we have nothing left todo 1063 } 1064} 1065''') 1066 1067 code.write(path, "%s_Wakeup.cc" % self.ident) 1068 1069 def printCSwitch(self, path): 1070 '''Output switch statement for transition table''' 1071 1072 code = self.symtab.codeFormatter() 1073 ident = self.ident 1074 1075 code(''' 1076// Auto generated C++ code started by $__file__:$__line__ 1077// ${ident}: ${{self.short}} 1078 1079#include <cassert> 1080 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" 1091 1092#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1093 1094#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1095#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1096 1097TransitionResult 1098${ident}_Controller::doTransition(${ident}_Event event, 1099''') 1100 if self.EntryType != None: 1101 code(''' 1102 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1103''') 1104 if self.TBEType != None: 1105 code(''' 1106 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1107''') 1108 code(''' 1109 const Address &addr) 1110{ 1111''') 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);') 1118 else: 1119 code('${ident}_State state = getState(addr);') 1120 1121 code(''' 1122 ${ident}_State next_state = state; 1123 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); 1127 1128 TransitionResult result = 1129''') 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);') 1136 else: 1137 code('doTransitionWorker(event, state, next_state, addr);') 1138 1139 code(''' 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()); 1150 1151 CLEAR_TRANSITION_COMMENT(); 1152''') 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);') 1162 else: 1163 code('setState(addr, next_state);') 1164 code('setAccessPermission(addr, next_state);') 1165 1166 code(''' 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"); 1182 } 1183 1184 return result; 1185} 1186 1187TransitionResult 1188${ident}_Controller::doTransitionWorker(${ident}_Event event, 1189 ${ident}_State state, 1190 ${ident}_State& next_state, 1191''') 1192 1193 if self.TBEType != None: 1194 code(''' 1195 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1196''') 1197 if self.EntryType != None: 1198 code(''' 1199 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1200''') 1201 code(''' 1202 const Address& addr) 1203{ 1204 switch(HASH_FUN(state, event)) { 1205''') 1206 1207 # This map will allow suppress generating duplicate code 1208 cases = orderdict() 1209 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) 1213 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};') 1219 1220 actions = trans.actions 1221 request_types = trans.request_types 1222 1223 # Check for resources 1224 case_sorter = [] 1225 res = trans.resources 1226 for key,val in res.iteritems(): 1227 if key.type.ident != "DNUCAStopTable": 1228 val = ''' 1229if (!%s.areNSlotsAvailable(%s)) 1230 return TransitionResult_ResourceStall; 1231''' % (key.code, val) 1232 case_sorter.append(val) 1233 1234 # Check all of the request_types for resource constraints 1235 for request_type in request_types: 1236 val = ''' 1237if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1238 return TransitionResult_ResourceStall; 1239} 1240''' % (self.ident, request_type.ident) 1241 case_sorter.append(val) 1242 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): 1247 case("$c") 1248 1249 # Record access types for this transition 1250 for request_type in request_types: 1251 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1252 1253 # Figure out if we stall 1254 stall = False 1255 for action in actions: 1256 if action.ident == "z_stall": 1257 stall = True 1258 break 1259 1260 if stall: 1261 case('return TransitionResult_ProtocolStall;') 1262 else: 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);') 1272 else: 1273 for action in actions: 1274 case('${{action.ident}}(addr);') 1275 case('return TransitionResult_Valid;') 1276 1277 case = str(case) 1278 1279 # Look to see if this transition code is unique. 1280 if case not in cases: 1281 cases[case] = [] 1282 1283 cases[case].append(case_string) 1284 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 1289 # the same code 1290 for trans in transitions: 1291 code(' case HASH_FUN($trans):') 1292 code(' $case') 1293 1294 code(''' 1295 default: 1296 fatal("Invalid transition\\n" 1297 "%s time: %d addr: %s event: %s state: %s\\n", 1298 name(), curCycle(), addr, event, state); 1299 } 1300 return TransitionResult_Valid; 1301} 1302''') 1303 code.write(path, "%s_Transitions.cc" % self.ident) 1304 1305 def printProfileDumperHH(self, path): 1306 code = self.symtab.codeFormatter() 1307 ident = self.ident 1308 1309 code(''' 1310// Auto generated C++ code started by $__file__:$__line__ 1311// ${ident}: ${{self.short}} 1312 1313#ifndef __${ident}_PROFILE_DUMPER_HH__ 1314#define __${ident}_PROFILE_DUMPER_HH__ 1315 1316#include <cassert> 1317#include <iostream> 1318#include <vector> 1319 1320#include "${ident}_Event.hh" 1321#include "${ident}_Profiler.hh" 1322 1323typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1324 1325class ${ident}_ProfileDumper 1326{ 1327 public: 1328 ${ident}_ProfileDumper(); 1329 void registerProfiler(${ident}_Profiler* profiler); 1330 void dumpStats(std::ostream& out) const; 1331 1332 private: 1333 ${ident}_profilers m_profilers; 1334}; 1335 1336#endif // __${ident}_PROFILE_DUMPER_HH__ 1337''') 1338 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1339 1340 def printProfileDumperCC(self, path): 1341 code = self.symtab.codeFormatter() 1342 ident = self.ident 1343 1344 code(''' 1345// Auto generated C++ code started by $__file__:$__line__ 1346// ${ident}: ${{self.short}} 1347 1348#include "mem/protocol/${ident}_ProfileDumper.hh" 1349 1350${ident}_ProfileDumper::${ident}_ProfileDumper() 1351{ 1352} 1353 1354void 1355${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1356{ 1357 m_profilers.push_back(profiler); 1358} 1359 1360void 1361${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1362{ 1363 out << " --- ${ident} ---\\n"; 1364 out << " - Event Counts -\\n"; 1365 for (${ident}_Event event = ${ident}_Event_FIRST; 1366 event < ${ident}_Event_NUM; 1367 ++event) { 1368 out << (${ident}_Event) event << " ["; 1369 uint64 total = 0; 1370 for (int i = 0; i < m_profilers.size(); i++) { 1371 out << m_profilers[i]->getEventCount(event) << " "; 1372 total += m_profilers[i]->getEventCount(event); 1373 } 1374 out << "] " << total << "\\n"; 1375 } 1376 out << "\\n"; 1377 out << " - Transitions -\\n"; 1378 for (${ident}_State state = ${ident}_State_FIRST; 1379 state < ${ident}_State_NUM; 1380 ++state) { 1381 for (${ident}_Event event = ${ident}_Event_FIRST; 1382 event < ${ident}_Event_NUM; 1383 ++event) { 1384 if (m_profilers[0]->isPossible(state, event)) { 1385 out << (${ident}_State) state << " " 1386 << (${ident}_Event) event << " ["; 1387 uint64 total = 0; 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); 1391 } 1392 out << "] " << total << "\\n"; 1393 } 1394 } 1395 out << "\\n"; 1396 } 1397} 1398''') 1399 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1400 1401 def printProfilerHH(self, path): 1402 code = self.symtab.codeFormatter() 1403 ident = self.ident 1404 1405 code(''' 1406// Auto generated C++ code started by $__file__:$__line__ 1407// ${ident}: ${{self.short}} 1408 1409#ifndef __${ident}_PROFILER_HH__ 1410#define __${ident}_PROFILER_HH__ 1411 1412#include <cassert> 1413#include <iostream> 1414 1415#include "mem/protocol/${ident}_Event.hh" 1416#include "mem/protocol/${ident}_State.hh" 1417#include "mem/ruby/common/TypeDefines.hh" 1418 1419class ${ident}_Profiler 1420{ 1421 public: 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); 1429 void clearStats(); 1430 1431 private: 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]; 1435 int m_version; 1436}; 1437 1438#endif // __${ident}_PROFILER_HH__ 1439''') 1440 code.write(path, "%s_Profiler.hh" % self.ident) 1441 1442 def printProfilerCC(self, path): 1443 code = self.symtab.codeFormatter() 1444 ident = self.ident 1445 1446 code(''' 1447// Auto generated C++ code started by $__file__:$__line__ 1448// ${ident}: ${{self.short}} 1449 1450#include <cassert> 1451 1452#include "mem/protocol/${ident}_Profiler.hh" 1453 1454${ident}_Profiler::${ident}_Profiler() 1455{ 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; 1460 } 1461 } 1462 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1463 m_event_counters[event] = 0; 1464 } 1465} 1466 1467void 1468${ident}_Profiler::setVersion(int version) 1469{ 1470 m_version = version; 1471} 1472 1473void 1474${ident}_Profiler::clearStats() 1475{ 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; 1479 } 1480 } 1481 1482 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1483 m_event_counters[event] = 0; 1484 } 1485} 1486void 1487${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1488{ 1489 assert(m_possible[state][event]); 1490 m_counters[state][event]++; 1491 m_event_counters[event]++; 1492} 1493void 1494${ident}_Profiler::possibleTransition(${ident}_State state, 1495 ${ident}_Event event) 1496{ 1497 m_possible[state][event] = true; 1498} 1499 1500uint64 1501${ident}_Profiler::getEventCount(${ident}_Event event) 1502{ 1503 return m_event_counters[event]; 1504} 1505 1506bool 1507${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1508{ 1509 return m_possible[state][event]; 1510} 1511 1512uint64 1513${ident}_Profiler::getTransitionCount(${ident}_State state, 1514 ${ident}_Event event) 1515{ 1516 return m_counters[state][event]; 1517} 1518 1519''') 1520 code.write(path, "%s_Profiler.cc" % self.ident) 1521 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' 1530 }\"> 1531 ${{html.formatShorthand(text)}} 1532 </A>""") 1533 return str(code) 1534 1535 def writeHTMLFiles(self, path): 1536 # Create table with no row hilighted 1537 self.printHTMLTransitions(path, None) 1538 1539 # Generate transition tables 1540 for state in self.states.itervalues(): 1541 self.printHTMLTransitions(path, state) 1542 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) 1548 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) 1554 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) 1560 1561 def printHTMLTransitions(self, path, active_state): 1562 code = self.symtab.codeFormatter() 1563 1564 code(''' 1565<HTML> 1566<BODY link="blue" vlink="blue"> 1567 1568<H1 align="center">${{html.formatShorthand(self.short)}}: 1569''') 1570 code.indent() 1571 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1572 mid = machine.ident 1573 if i != 0: 1574 extra = " - " 1575 else: 1576 extra = "" 1577 if machine == self: 1578 code('$extra$mid') 1579 else: 1580 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1581 code.dedent() 1582 1583 code(""" 1584</H1> 1585 1586<TABLE border=1> 1587<TR> 1588 <TH> </TH> 1589""") 1590 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>') 1595 1596 code('</TR>') 1597 # -- Body of table 1598 for state in self.states.itervalues(): 1599 # -- Each row 1600 if state == active_state: 1601 color = "yellow" 1602 else: 1603 color = "white" 1604 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) 1609 code(''' 1610<TR> 1611 <TH bgcolor=$color>$ref</TH> 1612''') 1613 1614 # -- One column for each event 1615 for event in self.events.itervalues(): 1616 trans = self.table.get((state,event), None) 1617 if trans is None: 1618 # This is the no transition case 1619 if state == active_state: 1620 color = "#C0C000" 1621 else: 1622 color = "lightgrey" 1623 1624 code('<TD bgcolor=$color> </TD>') 1625 continue 1626 1627 next = trans.nextState 1628 stall_action = False 1629 1630 # -- Get the actions 1631 for action in trans.actions: 1632 if action.ident == "z_stall" or \ 1633 action.ident == "zz_recycleMandatoryQueue": 1634 stall_action = True 1635 1636 # -- Print out "actions/next-state" 1637 if stall_action: 1638 if state == active_state: 1639 color = "#C0C000" 1640 else: 1641 color = "lightgrey" 1642 1643 elif active_state and next.ident == active_state.ident: 1644 color = "aqua" 1645 elif state == active_state: 1646 color = "yellow" 1647 else: 1648 color = "white" 1649 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", 1654 action.short) 1655 code(' $ref') 1656 if next != state: 1657 if trans.actions: 1658 code('/') 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) 1662 code("$ref") 1663 code("</TD>") 1664 1665 # -- Each row 1666 if state == active_state: 1667 color = "yellow" 1668 else: 1669 color = "white" 1670 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) 1674 code(''' 1675 <TH bgcolor=$color>$ref</TH> 1676</TR> 1677''') 1678 code(''' 1679<!- Column footer-> 1680<TR> 1681 <TH> </TH> 1682''') 1683 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>') 1688 code(''' 1689</TR> 1690</TABLE> 1691</BODY></HTML> 1692''') 1693 1694 1695 if active_state: 1696 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1697 else: 1698 name = "%s_table.html" % self.ident 1699 code.write(path, name) 1700 1701__all__ = [ "StateMachine" ]
| 490 # 491 # For the DMA controller, pass the sequencer a pointer to the 492 # controller. 493 # 494 if self.ident == "DMA": 495 if not contains_dma_sequencer: 496 self.error("The DMA controller must include the sequencer " \ 497 "configuration parameter") 498 499 code(''' 500m_dma_sequencer_ptr->setController(this); 501''') 502 503 code('m_num_controllers++;') 504 for var in self.objects: 505 if var.ident.find("mandatoryQueue") >= 0: 506 code(''' 507m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 508m_${{var.c_ident}}_ptr->setReceiver(this); 509''') 510 else: 511 if "network" in var and "physical_network" in var and \ 512 var["network"] == "To": 513 has_peer = True 514 code(''' 515m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}(); 516peerQueueMap[${{var["physical_network"]}}] = m_${{var.c_ident}}_ptr; 517m_${{var.c_ident}}_ptr->setSender(this); 518''') 519 520 code(''' 521if (p->peer != NULL) 522 connectWithPeer(p->peer); 523''') 524 code.dedent() 525 code(''' 526} 527 528void 529$c_ident::init() 530{ 531 MachineType machine_type; 532 int base; 533 machine_type = string_to_MachineType("${{var.machine.ident}}"); 534 base = MachineType_base_number(machine_type); 535 536 m_machineID.type = MachineType_${ident}; 537 m_machineID.num = m_version; 538 539 // initialize objects 540 m_profiler.setVersion(m_version); 541 s_profileDumper.registerProfiler(&m_profiler); 542 543''') 544 545 code.indent() 546 for var in self.objects: 547 vtype = var.type 548 vid = "m_%s_ptr" % var.c_ident 549 if "network" not in var: 550 # Not a network port object 551 if "primitive" in vtype: 552 code('$vid = new ${{vtype.c_ident}};') 553 if "default" in var: 554 code('(*$vid) = ${{var["default"]}};') 555 else: 556 # Normal Object 557 if var.ident.find("mandatoryQueue") < 0: 558 th = var.get("template", "") 559 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 560 args = "" 561 if "non_obj" not in vtype and not vtype.isEnumeration: 562 args = var.get("constructor", "") 563 code('$expr($args);') 564 565 code('assert($vid != NULL);') 566 567 if "default" in var: 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') 572 573 # Set ordering 574 if "ordered" in var: 575 # A buffer 576 code('$vid->setOrdering(${{var["ordered"]}});') 577 578 # Set randomization 579 if "random" in var: 580 # A buffer 581 code('$vid->setRandomization(${{var["random"]}});') 582 583 # Set Priority 584 if vtype.isBuffer and "rank" in var: 585 code('$vid->setPriority(${{var["rank"]}});') 586 587 # Set sender and receiver for trigger queue 588 if var.ident.find("triggerQueue") >= 0: 589 code('$vid->setSender(this);') 590 code('$vid->setReceiver(this);') 591 elif vtype.c_ident == "TimerTable": 592 code('$vid->setClockObj(this);') 593 594 else: 595 # Network port object 596 network = var["network"] 597 ordered = var["ordered"] 598 599 if "virtual_network" in var: 600 vnet = var["virtual_network"] 601 vnet_type = var["vnet_type"] 602 603 assert var.machine is not None 604 code(''' 605$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 606assert($vid != NULL); 607''') 608 609 # Set the end 610 if network == "To": 611 code('$vid->setSender(this);') 612 else: 613 code('$vid->setReceiver(this);') 614 615 # Set ordering 616 if "ordered" in var: 617 # A buffer 618 code('$vid->setOrdering(${{var["ordered"]}});') 619 620 # Set randomization 621 if "random" in var: 622 # A buffer 623 code('$vid->setRandomization(${{var["random"]}});') 624 625 # Set Priority 626 if "rank" in var: 627 code('$vid->setPriority(${{var["rank"]}})') 628 629 # Set buffer size 630 if vtype.isBuffer: 631 code(''' 632if (m_buffer_size > 0) { 633 $vid->resize(m_buffer_size); 634} 635''') 636 637 # set description (may be overriden later by port def) 638 code(''' 639$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 640 641''') 642 643 if vtype.isBuffer: 644 if "recycle_latency" in var: 645 code('$vid->setRecycleLatency( ' \ 646 'Cycles(${{var["recycle_latency"]}}));') 647 else: 648 code('$vid->setRecycleLatency(m_recycle_latency);') 649 650 # Set the prefetchers 651 code() 652 for prefetcher in self.prefetchers: 653 code('${{prefetcher.code}}.setController(this);') 654 655 code() 656 for port in self.in_ports: 657 # Set the queue consumers 658 code('${{port.code}}.setConsumer(this);') 659 # Set the queue descriptions 660 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 661 662 # Initialize the transition profiling 663 code() 664 for trans in self.transitions: 665 # Figure out if we stall 666 stall = False 667 for action in trans.actions: 668 if action.ident == "z_stall": 669 stall = True 670 671 # Only possible if it is not a 'z' case 672 if not stall: 673 state = "%s_State_%s" % (self.ident, trans.state.ident) 674 event = "%s_Event_%s" % (self.ident, trans.event.ident) 675 code('m_profiler.possibleTransition($state, $event);') 676 677 code.dedent() 678 code(''' 679 AbstractController::init(); 680 clearStats(); 681} 682''') 683 684 has_mandatory_q = False 685 for port in self.in_ports: 686 if port.code.find("mandatoryQueue_ptr") >= 0: 687 has_mandatory_q = True 688 689 if has_mandatory_q: 690 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 691 else: 692 mq_ident = "NULL" 693 694 seq_ident = "NULL" 695 for param in self.config_parameters: 696 if param.name == "sequencer": 697 assert(param.pointer) 698 seq_ident = "m_%s_ptr" % param.name 699 700 code(''' 701int 702$c_ident::getNumControllers() 703{ 704 return m_num_controllers; 705} 706 707MessageBuffer* 708$c_ident::getMandatoryQueue() const 709{ 710 return $mq_ident; 711} 712 713Sequencer* 714$c_ident::getSequencer() const 715{ 716 return $seq_ident; 717} 718 719const int & 720$c_ident::getVersion() const 721{ 722 return m_version; 723} 724 725const string 726$c_ident::toString() const 727{ 728 return "$c_ident"; 729} 730 731const string 732$c_ident::getName() const 733{ 734 return m_name; 735} 736 737void 738$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 739{ 740 m_is_blocking = true; 741 m_block_map[addr] = port; 742} 743 744void 745$c_ident::unblock(Address addr) 746{ 747 m_block_map.erase(addr); 748 if (m_block_map.size() == 0) { 749 m_is_blocking = false; 750 } 751} 752 753void 754$c_ident::print(ostream& out) const 755{ 756 out << "[$c_ident " << m_version << "]"; 757} 758 759void 760$c_ident::printStats(ostream& out) const 761{ 762''') 763 # 764 # Cache and Memory Controllers have specific profilers associated with 765 # them. Print out these stats before dumping state transition stats. 766 # 767 for param in self.config_parameters: 768 if param.type_ast.type.ident == "CacheMemory" or \ 769 param.type_ast.type.ident == "DirectoryMemory" or \ 770 param.type_ast.type.ident == "MemoryControl": 771 assert(param.pointer) 772 code(' m_${{param.ident}}_ptr->printStats(out);') 773 774 code(''' 775 if (m_version == 0) { 776 s_profileDumper.dumpStats(out); 777 } 778} 779 780void $c_ident::clearStats() { 781''') 782 # 783 # Cache and Memory Controllers have specific profilers associated with 784 # them. These stats must be cleared too. 785 # 786 for param in self.config_parameters: 787 if param.type_ast.type.ident == "CacheMemory" or \ 788 param.type_ast.type.ident == "MemoryControl": 789 assert(param.pointer) 790 code(' m_${{param.ident}}_ptr->clearStats();') 791 792 code(''' 793 m_profiler.clearStats(); 794 AbstractController::clearStats(); 795} 796''') 797 798 if self.EntryType != None: 799 code(''' 800 801// Set and Reset for cache_entry variable 802void 803$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 804{ 805 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 806} 807 808void 809$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 810{ 811 m_cache_entry_ptr = 0; 812} 813''') 814 815 if self.TBEType != None: 816 code(''' 817 818// Set and Reset for tbe variable 819void 820$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 821{ 822 m_tbe_ptr = m_new_tbe; 823} 824 825void 826$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 827{ 828 m_tbe_ptr = NULL; 829} 830''') 831 832 code(''' 833 834void 835$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 836{ 837''') 838 # 839 # Record cache contents for all associated caches. 840 # 841 code.indent() 842 for param in self.config_parameters: 843 if param.type_ast.type.ident == "CacheMemory": 844 assert(param.pointer) 845 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 846 847 code.dedent() 848 code(''' 849} 850 851// Actions 852''') 853 if self.TBEType != None and self.EntryType != None: 854 for action in self.actions.itervalues(): 855 if "c_code" not in action: 856 continue 857 858 code(''' 859/** \\brief ${{action.desc}} */ 860void 861$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 862{ 863 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 864 ${{action["c_code"]}} 865} 866 867''') 868 elif self.TBEType != None: 869 for action in self.actions.itervalues(): 870 if "c_code" not in action: 871 continue 872 873 code(''' 874/** \\brief ${{action.desc}} */ 875void 876$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 877{ 878 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 879 ${{action["c_code"]}} 880} 881 882''') 883 elif self.EntryType != None: 884 for action in self.actions.itervalues(): 885 if "c_code" not in action: 886 continue 887 888 code(''' 889/** \\brief ${{action.desc}} */ 890void 891$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 892{ 893 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 894 ${{action["c_code"]}} 895} 896 897''') 898 else: 899 for action in self.actions.itervalues(): 900 if "c_code" not in action: 901 continue 902 903 code(''' 904/** \\brief ${{action.desc}} */ 905void 906$c_ident::${{action.ident}}(const Address& addr) 907{ 908 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 909 ${{action["c_code"]}} 910} 911 912''') 913 for func in self.functions: 914 code(func.generateCode()) 915 916 # Function for functional reads from messages buffered in the controller 917 code(''' 918bool 919$c_ident::functionalReadBuffers(PacketPtr& pkt) 920{ 921''') 922 for var in self.objects: 923 vtype = var.type 924 if vtype.isBuffer: 925 vid = "m_%s_ptr" % var.c_ident 926 code('if ($vid->functionalRead(pkt)) { return true; }') 927 code(''' 928 return false; 929} 930''') 931 932 # Function for functional writes to messages buffered in the controller 933 code(''' 934uint32_t 935$c_ident::functionalWriteBuffers(PacketPtr& pkt) 936{ 937 uint32_t num_functional_writes = 0; 938''') 939 for var in self.objects: 940 vtype = var.type 941 if vtype.isBuffer: 942 vid = "m_%s_ptr" % var.c_ident 943 code('num_functional_writes += $vid->functionalWrite(pkt);') 944 code(''' 945 return num_functional_writes; 946} 947''') 948 949 # Check if this controller has a peer, if yes then write the 950 # function for connecting to the peer. 951 if has_peer: 952 code(''' 953 954void 955$c_ident::getQueuesFromPeer(AbstractController *peer) 956{ 957''') 958 for var in self.objects: 959 if "network" in var and "physical_network" in var and \ 960 var["network"] == "From": 961 code(''' 962m_${{var.c_ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 963assert(m_${{var.c_ident}}_ptr != NULL); 964m_${{var.c_ident}}_ptr->setReceiver(this); 965 966''') 967 code('}') 968 969 code.write(path, "%s.cc" % c_ident) 970 971 def printCWakeup(self, path, includes): 972 '''Output the wakeup loop for the events''' 973 974 code = self.symtab.codeFormatter() 975 ident = self.ident 976 977 outputRequest_types = True 978 if len(self.request_types) == 0: 979 outputRequest_types = False 980 981 code(''' 982// Auto generated C++ code started by $__file__:$__line__ 983// ${ident}: ${{self.short}} 984 985#include <sys/types.h> 986#include <unistd.h> 987 988#include <cassert> 989 990#include "base/misc.hh" 991#include "debug/RubySlicc.hh" 992#include "mem/protocol/${ident}_Controller.hh" 993#include "mem/protocol/${ident}_Event.hh" 994#include "mem/protocol/${ident}_State.hh" 995''') 996 997 if outputRequest_types: 998 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 999 1000 code(''' 1001#include "mem/protocol/Types.hh" 1002#include "mem/ruby/common/Global.hh" 1003#include "mem/ruby/system/System.hh" 1004''') 1005 1006 1007 for include_path in includes: 1008 code('#include "${{include_path}}"') 1009 1010 code(''' 1011 1012using namespace std; 1013 1014void 1015${ident}_Controller::wakeup() 1016{ 1017 int counter = 0; 1018 while (true) { 1019 // Some cases will put us into an infinite loop without this limit 1020 assert(counter <= m_transitions_per_cycle); 1021 if (counter == m_transitions_per_cycle) { 1022 // Count how often we are fully utilized 1023 m_fully_busy_cycles++; 1024 1025 // Wakeup in another cycle and try again 1026 scheduleEvent(Cycles(1)); 1027 break; 1028 } 1029''') 1030 1031 code.indent() 1032 code.indent() 1033 1034 # InPorts 1035 # 1036 for port in self.in_ports: 1037 code.indent() 1038 code('// ${ident}InPort $port') 1039 if port.pairs.has_key("rank"): 1040 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1041 else: 1042 code('m_cur_in_port_rank = 0;') 1043 code('${{port["c_code_in_port"]}}') 1044 code.dedent() 1045 1046 code('') 1047 1048 code.dedent() 1049 code.dedent() 1050 code(''' 1051 break; // If we got this far, we have nothing left todo 1052 } 1053} 1054''') 1055 1056 code.write(path, "%s_Wakeup.cc" % self.ident) 1057 1058 def printCSwitch(self, path): 1059 '''Output switch statement for transition table''' 1060 1061 code = self.symtab.codeFormatter() 1062 ident = self.ident 1063 1064 code(''' 1065// Auto generated C++ code started by $__file__:$__line__ 1066// ${ident}: ${{self.short}} 1067 1068#include <cassert> 1069 1070#include "base/misc.hh" 1071#include "base/trace.hh" 1072#include "debug/ProtocolTrace.hh" 1073#include "debug/RubyGenerated.hh" 1074#include "mem/protocol/${ident}_Controller.hh" 1075#include "mem/protocol/${ident}_Event.hh" 1076#include "mem/protocol/${ident}_State.hh" 1077#include "mem/protocol/Types.hh" 1078#include "mem/ruby/common/Global.hh" 1079#include "mem/ruby/system/System.hh" 1080 1081#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1082 1083#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1084#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1085 1086TransitionResult 1087${ident}_Controller::doTransition(${ident}_Event event, 1088''') 1089 if self.EntryType != None: 1090 code(''' 1091 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1092''') 1093 if self.TBEType != None: 1094 code(''' 1095 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1096''') 1097 code(''' 1098 const Address &addr) 1099{ 1100''') 1101 if self.TBEType != None and self.EntryType != None: 1102 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1103 elif self.TBEType != None: 1104 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1105 elif self.EntryType != None: 1106 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1107 else: 1108 code('${ident}_State state = getState(addr);') 1109 1110 code(''' 1111 ${ident}_State next_state = state; 1112 1113 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1114 *this, curCycle(), ${ident}_State_to_string(state), 1115 ${ident}_Event_to_string(event), addr); 1116 1117 TransitionResult result = 1118''') 1119 if self.TBEType != None and self.EntryType != None: 1120 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1121 elif self.TBEType != None: 1122 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1123 elif self.EntryType != None: 1124 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1125 else: 1126 code('doTransitionWorker(event, state, next_state, addr);') 1127 1128 code(''' 1129 if (result == TransitionResult_Valid) { 1130 DPRINTF(RubyGenerated, "next_state: %s\\n", 1131 ${ident}_State_to_string(next_state)); 1132 m_profiler.countTransition(state, event); 1133 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1134 curTick(), m_version, "${ident}", 1135 ${ident}_Event_to_string(event), 1136 ${ident}_State_to_string(state), 1137 ${ident}_State_to_string(next_state), 1138 addr, GET_TRANSITION_COMMENT()); 1139 1140 CLEAR_TRANSITION_COMMENT(); 1141''') 1142 if self.TBEType != None and self.EntryType != None: 1143 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1144 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1145 elif self.TBEType != None: 1146 code('setState(m_tbe_ptr, addr, next_state);') 1147 code('setAccessPermission(addr, next_state);') 1148 elif self.EntryType != None: 1149 code('setState(m_cache_entry_ptr, addr, next_state);') 1150 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1151 else: 1152 code('setState(addr, next_state);') 1153 code('setAccessPermission(addr, next_state);') 1154 1155 code(''' 1156 } else if (result == TransitionResult_ResourceStall) { 1157 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1158 curTick(), m_version, "${ident}", 1159 ${ident}_Event_to_string(event), 1160 ${ident}_State_to_string(state), 1161 ${ident}_State_to_string(next_state), 1162 addr, "Resource Stall"); 1163 } else if (result == TransitionResult_ProtocolStall) { 1164 DPRINTF(RubyGenerated, "stalling\\n"); 1165 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1166 curTick(), m_version, "${ident}", 1167 ${ident}_Event_to_string(event), 1168 ${ident}_State_to_string(state), 1169 ${ident}_State_to_string(next_state), 1170 addr, "Protocol Stall"); 1171 } 1172 1173 return result; 1174} 1175 1176TransitionResult 1177${ident}_Controller::doTransitionWorker(${ident}_Event event, 1178 ${ident}_State state, 1179 ${ident}_State& next_state, 1180''') 1181 1182 if self.TBEType != None: 1183 code(''' 1184 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1185''') 1186 if self.EntryType != None: 1187 code(''' 1188 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1189''') 1190 code(''' 1191 const Address& addr) 1192{ 1193 switch(HASH_FUN(state, event)) { 1194''') 1195 1196 # This map will allow suppress generating duplicate code 1197 cases = orderdict() 1198 1199 for trans in self.transitions: 1200 case_string = "%s_State_%s, %s_Event_%s" % \ 1201 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1202 1203 case = self.symtab.codeFormatter() 1204 # Only set next_state if it changes 1205 if trans.state != trans.nextState: 1206 ns_ident = trans.nextState.ident 1207 case('next_state = ${ident}_State_${ns_ident};') 1208 1209 actions = trans.actions 1210 request_types = trans.request_types 1211 1212 # Check for resources 1213 case_sorter = [] 1214 res = trans.resources 1215 for key,val in res.iteritems(): 1216 if key.type.ident != "DNUCAStopTable": 1217 val = ''' 1218if (!%s.areNSlotsAvailable(%s)) 1219 return TransitionResult_ResourceStall; 1220''' % (key.code, val) 1221 case_sorter.append(val) 1222 1223 # Check all of the request_types for resource constraints 1224 for request_type in request_types: 1225 val = ''' 1226if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1227 return TransitionResult_ResourceStall; 1228} 1229''' % (self.ident, request_type.ident) 1230 case_sorter.append(val) 1231 1232 # Emit the code sequences in a sorted order. This makes the 1233 # output deterministic (without this the output order can vary 1234 # since Map's keys() on a vector of pointers is not deterministic 1235 for c in sorted(case_sorter): 1236 case("$c") 1237 1238 # Record access types for this transition 1239 for request_type in request_types: 1240 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1241 1242 # Figure out if we stall 1243 stall = False 1244 for action in actions: 1245 if action.ident == "z_stall": 1246 stall = True 1247 break 1248 1249 if stall: 1250 case('return TransitionResult_ProtocolStall;') 1251 else: 1252 if self.TBEType != None and self.EntryType != None: 1253 for action in actions: 1254 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1255 elif self.TBEType != None: 1256 for action in actions: 1257 case('${{action.ident}}(m_tbe_ptr, addr);') 1258 elif self.EntryType != None: 1259 for action in actions: 1260 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1261 else: 1262 for action in actions: 1263 case('${{action.ident}}(addr);') 1264 case('return TransitionResult_Valid;') 1265 1266 case = str(case) 1267 1268 # Look to see if this transition code is unique. 1269 if case not in cases: 1270 cases[case] = [] 1271 1272 cases[case].append(case_string) 1273 1274 # Walk through all of the unique code blocks and spit out the 1275 # corresponding case statement elements 1276 for case,transitions in cases.iteritems(): 1277 # Iterative over all the multiple transitions that share 1278 # the same code 1279 for trans in transitions: 1280 code(' case HASH_FUN($trans):') 1281 code(' $case') 1282 1283 code(''' 1284 default: 1285 fatal("Invalid transition\\n" 1286 "%s time: %d addr: %s event: %s state: %s\\n", 1287 name(), curCycle(), addr, event, state); 1288 } 1289 return TransitionResult_Valid; 1290} 1291''') 1292 code.write(path, "%s_Transitions.cc" % self.ident) 1293 1294 def printProfileDumperHH(self, path): 1295 code = self.symtab.codeFormatter() 1296 ident = self.ident 1297 1298 code(''' 1299// Auto generated C++ code started by $__file__:$__line__ 1300// ${ident}: ${{self.short}} 1301 1302#ifndef __${ident}_PROFILE_DUMPER_HH__ 1303#define __${ident}_PROFILE_DUMPER_HH__ 1304 1305#include <cassert> 1306#include <iostream> 1307#include <vector> 1308 1309#include "${ident}_Event.hh" 1310#include "${ident}_Profiler.hh" 1311 1312typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1313 1314class ${ident}_ProfileDumper 1315{ 1316 public: 1317 ${ident}_ProfileDumper(); 1318 void registerProfiler(${ident}_Profiler* profiler); 1319 void dumpStats(std::ostream& out) const; 1320 1321 private: 1322 ${ident}_profilers m_profilers; 1323}; 1324 1325#endif // __${ident}_PROFILE_DUMPER_HH__ 1326''') 1327 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1328 1329 def printProfileDumperCC(self, path): 1330 code = self.symtab.codeFormatter() 1331 ident = self.ident 1332 1333 code(''' 1334// Auto generated C++ code started by $__file__:$__line__ 1335// ${ident}: ${{self.short}} 1336 1337#include "mem/protocol/${ident}_ProfileDumper.hh" 1338 1339${ident}_ProfileDumper::${ident}_ProfileDumper() 1340{ 1341} 1342 1343void 1344${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1345{ 1346 m_profilers.push_back(profiler); 1347} 1348 1349void 1350${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1351{ 1352 out << " --- ${ident} ---\\n"; 1353 out << " - Event Counts -\\n"; 1354 for (${ident}_Event event = ${ident}_Event_FIRST; 1355 event < ${ident}_Event_NUM; 1356 ++event) { 1357 out << (${ident}_Event) event << " ["; 1358 uint64 total = 0; 1359 for (int i = 0; i < m_profilers.size(); i++) { 1360 out << m_profilers[i]->getEventCount(event) << " "; 1361 total += m_profilers[i]->getEventCount(event); 1362 } 1363 out << "] " << total << "\\n"; 1364 } 1365 out << "\\n"; 1366 out << " - Transitions -\\n"; 1367 for (${ident}_State state = ${ident}_State_FIRST; 1368 state < ${ident}_State_NUM; 1369 ++state) { 1370 for (${ident}_Event event = ${ident}_Event_FIRST; 1371 event < ${ident}_Event_NUM; 1372 ++event) { 1373 if (m_profilers[0]->isPossible(state, event)) { 1374 out << (${ident}_State) state << " " 1375 << (${ident}_Event) event << " ["; 1376 uint64 total = 0; 1377 for (int i = 0; i < m_profilers.size(); i++) { 1378 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1379 total += m_profilers[i]->getTransitionCount(state, event); 1380 } 1381 out << "] " << total << "\\n"; 1382 } 1383 } 1384 out << "\\n"; 1385 } 1386} 1387''') 1388 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1389 1390 def printProfilerHH(self, path): 1391 code = self.symtab.codeFormatter() 1392 ident = self.ident 1393 1394 code(''' 1395// Auto generated C++ code started by $__file__:$__line__ 1396// ${ident}: ${{self.short}} 1397 1398#ifndef __${ident}_PROFILER_HH__ 1399#define __${ident}_PROFILER_HH__ 1400 1401#include <cassert> 1402#include <iostream> 1403 1404#include "mem/protocol/${ident}_Event.hh" 1405#include "mem/protocol/${ident}_State.hh" 1406#include "mem/ruby/common/TypeDefines.hh" 1407 1408class ${ident}_Profiler 1409{ 1410 public: 1411 ${ident}_Profiler(); 1412 void setVersion(int version); 1413 void countTransition(${ident}_State state, ${ident}_Event event); 1414 void possibleTransition(${ident}_State state, ${ident}_Event event); 1415 uint64 getEventCount(${ident}_Event event); 1416 bool isPossible(${ident}_State state, ${ident}_Event event); 1417 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1418 void clearStats(); 1419 1420 private: 1421 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1422 int m_event_counters[${ident}_Event_NUM]; 1423 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1424 int m_version; 1425}; 1426 1427#endif // __${ident}_PROFILER_HH__ 1428''') 1429 code.write(path, "%s_Profiler.hh" % self.ident) 1430 1431 def printProfilerCC(self, path): 1432 code = self.symtab.codeFormatter() 1433 ident = self.ident 1434 1435 code(''' 1436// Auto generated C++ code started by $__file__:$__line__ 1437// ${ident}: ${{self.short}} 1438 1439#include <cassert> 1440 1441#include "mem/protocol/${ident}_Profiler.hh" 1442 1443${ident}_Profiler::${ident}_Profiler() 1444{ 1445 for (int state = 0; state < ${ident}_State_NUM; state++) { 1446 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1447 m_possible[state][event] = false; 1448 m_counters[state][event] = 0; 1449 } 1450 } 1451 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1452 m_event_counters[event] = 0; 1453 } 1454} 1455 1456void 1457${ident}_Profiler::setVersion(int version) 1458{ 1459 m_version = version; 1460} 1461 1462void 1463${ident}_Profiler::clearStats() 1464{ 1465 for (int state = 0; state < ${ident}_State_NUM; state++) { 1466 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1467 m_counters[state][event] = 0; 1468 } 1469 } 1470 1471 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1472 m_event_counters[event] = 0; 1473 } 1474} 1475void 1476${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1477{ 1478 assert(m_possible[state][event]); 1479 m_counters[state][event]++; 1480 m_event_counters[event]++; 1481} 1482void 1483${ident}_Profiler::possibleTransition(${ident}_State state, 1484 ${ident}_Event event) 1485{ 1486 m_possible[state][event] = true; 1487} 1488 1489uint64 1490${ident}_Profiler::getEventCount(${ident}_Event event) 1491{ 1492 return m_event_counters[event]; 1493} 1494 1495bool 1496${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1497{ 1498 return m_possible[state][event]; 1499} 1500 1501uint64 1502${ident}_Profiler::getTransitionCount(${ident}_State state, 1503 ${ident}_Event event) 1504{ 1505 return m_counters[state][event]; 1506} 1507 1508''') 1509 code.write(path, "%s_Profiler.cc" % self.ident) 1510 1511 # ************************** 1512 # ******* HTML Files ******* 1513 # ************************** 1514 def frameRef(self, click_href, click_target, over_href, over_num, text): 1515 code = self.symtab.codeFormatter(fix_newlines=False) 1516 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1517 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1518 parent.frames[$over_num].location='$over_href' 1519 }\"> 1520 ${{html.formatShorthand(text)}} 1521 </A>""") 1522 return str(code) 1523 1524 def writeHTMLFiles(self, path): 1525 # Create table with no row hilighted 1526 self.printHTMLTransitions(path, None) 1527 1528 # Generate transition tables 1529 for state in self.states.itervalues(): 1530 self.printHTMLTransitions(path, state) 1531 1532 # Generate action descriptions 1533 for action in self.actions.itervalues(): 1534 name = "%s_action_%s.html" % (self.ident, action.ident) 1535 code = html.createSymbol(action, "Action") 1536 code.write(path, name) 1537 1538 # Generate state descriptions 1539 for state in self.states.itervalues(): 1540 name = "%s_State_%s.html" % (self.ident, state.ident) 1541 code = html.createSymbol(state, "State") 1542 code.write(path, name) 1543 1544 # Generate event descriptions 1545 for event in self.events.itervalues(): 1546 name = "%s_Event_%s.html" % (self.ident, event.ident) 1547 code = html.createSymbol(event, "Event") 1548 code.write(path, name) 1549 1550 def printHTMLTransitions(self, path, active_state): 1551 code = self.symtab.codeFormatter() 1552 1553 code(''' 1554<HTML> 1555<BODY link="blue" vlink="blue"> 1556 1557<H1 align="center">${{html.formatShorthand(self.short)}}: 1558''') 1559 code.indent() 1560 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1561 mid = machine.ident 1562 if i != 0: 1563 extra = " - " 1564 else: 1565 extra = "" 1566 if machine == self: 1567 code('$extra$mid') 1568 else: 1569 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1570 code.dedent() 1571 1572 code(""" 1573</H1> 1574 1575<TABLE border=1> 1576<TR> 1577 <TH> </TH> 1578""") 1579 1580 for event in self.events.itervalues(): 1581 href = "%s_Event_%s.html" % (self.ident, event.ident) 1582 ref = self.frameRef(href, "Status", href, "1", event.short) 1583 code('<TH bgcolor=white>$ref</TH>') 1584 1585 code('</TR>') 1586 # -- Body of table 1587 for state in self.states.itervalues(): 1588 # -- Each row 1589 if state == active_state: 1590 color = "yellow" 1591 else: 1592 color = "white" 1593 1594 click = "%s_table_%s.html" % (self.ident, state.ident) 1595 over = "%s_State_%s.html" % (self.ident, state.ident) 1596 text = html.formatShorthand(state.short) 1597 ref = self.frameRef(click, "Table", over, "1", state.short) 1598 code(''' 1599<TR> 1600 <TH bgcolor=$color>$ref</TH> 1601''') 1602 1603 # -- One column for each event 1604 for event in self.events.itervalues(): 1605 trans = self.table.get((state,event), None) 1606 if trans is None: 1607 # This is the no transition case 1608 if state == active_state: 1609 color = "#C0C000" 1610 else: 1611 color = "lightgrey" 1612 1613 code('<TD bgcolor=$color> </TD>') 1614 continue 1615 1616 next = trans.nextState 1617 stall_action = False 1618 1619 # -- Get the actions 1620 for action in trans.actions: 1621 if action.ident == "z_stall" or \ 1622 action.ident == "zz_recycleMandatoryQueue": 1623 stall_action = True 1624 1625 # -- Print out "actions/next-state" 1626 if stall_action: 1627 if state == active_state: 1628 color = "#C0C000" 1629 else: 1630 color = "lightgrey" 1631 1632 elif active_state and next.ident == active_state.ident: 1633 color = "aqua" 1634 elif state == active_state: 1635 color = "yellow" 1636 else: 1637 color = "white" 1638 1639 code('<TD bgcolor=$color>') 1640 for action in trans.actions: 1641 href = "%s_action_%s.html" % (self.ident, action.ident) 1642 ref = self.frameRef(href, "Status", href, "1", 1643 action.short) 1644 code(' $ref') 1645 if next != state: 1646 if trans.actions: 1647 code('/') 1648 click = "%s_table_%s.html" % (self.ident, next.ident) 1649 over = "%s_State_%s.html" % (self.ident, next.ident) 1650 ref = self.frameRef(click, "Table", over, "1", next.short) 1651 code("$ref") 1652 code("</TD>") 1653 1654 # -- Each row 1655 if state == active_state: 1656 color = "yellow" 1657 else: 1658 color = "white" 1659 1660 click = "%s_table_%s.html" % (self.ident, state.ident) 1661 over = "%s_State_%s.html" % (self.ident, state.ident) 1662 ref = self.frameRef(click, "Table", over, "1", state.short) 1663 code(''' 1664 <TH bgcolor=$color>$ref</TH> 1665</TR> 1666''') 1667 code(''' 1668<!- Column footer-> 1669<TR> 1670 <TH> </TH> 1671''') 1672 1673 for event in self.events.itervalues(): 1674 href = "%s_Event_%s.html" % (self.ident, event.ident) 1675 ref = self.frameRef(href, "Status", href, "1", event.short) 1676 code('<TH bgcolor=white>$ref</TH>') 1677 code(''' 1678</TR> 1679</TABLE> 1680</BODY></HTML> 1681''') 1682 1683 1684 if active_state: 1685 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1686 else: 1687 name = "%s_table.html" % self.ident 1688 code.write(path, name) 1689 1690__all__ = [ "StateMachine" ]
|