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