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