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