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