StateMachine.py revision 9230:33eb3c8a98b9
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28from m5.util import orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33import re 34 35python_class_map = {"int": "Int", 36 "std::string": "String", 37 "bool": "Bool", 38 "CacheMemory": "RubyCache", 39 "WireBuffer": "RubyWireBuffer", 40 "Sequencer": "RubySequencer", 41 "DirectoryMemory": "RubyDirectoryMemory", 42 "MemoryControl": "MemoryControl", 43 "DMASequencer": "DMASequencer" 44 } 45 46class StateMachine(Symbol): 47 def __init__(self, symtab, ident, location, pairs, config_parameters): 48 super(StateMachine, self).__init__(symtab, ident, location, pairs) 49 self.table = None 50 self.config_parameters = config_parameters 51 52 for param in config_parameters: 53 if param.pointer: 54 var = Var(symtab, param.name, location, param.type_ast.type, 55 "(*m_%s_ptr)" % param.name, {}, self) 56 else: 57 var = Var(symtab, param.name, location, param.type_ast.type, 58 "m_%s" % param.name, {}, self) 59 self.symtab.registerSym(param.name, var) 60 61 self.states = orderdict() 62 self.events = orderdict() 63 self.actions = orderdict() 64 self.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, includes): 166 self.printControllerPython(path) 167 self.printControllerHH(path) 168 self.printControllerCC(path, includes) 169 self.printCSwitch(path) 170 self.printCWakeup(path, includes) 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, includes): 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/system/System.hh" 433''') 434 for include_path in includes: 435 code('#include "${{include_path}}"') 436 437 code(''' 438 439using namespace std; 440''') 441 442 # include object classes 443 seen_types = set() 444 for var in self.objects: 445 if var.type.ident not in seen_types and not var.type.isPrimitive: 446 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 447 seen_types.add(var.type.ident) 448 449 code(''' 450$c_ident * 451${c_ident}Params::create() 452{ 453 return new $c_ident(this); 454} 455 456int $c_ident::m_num_controllers = 0; 457${ident}_ProfileDumper $c_ident::s_profileDumper; 458 459// for adding information to the protocol debug trace 460stringstream ${ident}_transitionComment; 461#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 462 463/** \\brief constructor */ 464$c_ident::$c_ident(const Params *p) 465 : AbstractController(p) 466{ 467 m_version = p->version; 468 m_transitions_per_cycle = p->transitions_per_cycle; 469 m_buffer_size = p->buffer_size; 470 m_recycle_latency = p->recycle_latency; 471 m_number_of_TBEs = p->number_of_TBEs; 472 m_is_blocking = false; 473 m_name = "${ident}"; 474''') 475 # 476 # max_port_rank is used to size vectors and thus should be one plus the 477 # largest port rank 478 # 479 max_port_rank = self.in_ports[0].pairs["max_port_rank"] + 1 480 code(' m_max_in_port_rank = $max_port_rank;') 481 code.indent() 482 483 # 484 # After initializing the universal machine parameters, initialize the 485 # this machines config parameters. Also detemine if these configuration 486 # params include a sequencer. This information will be used later for 487 # contecting the sequencer back to the L1 cache controller. 488 # 489 contains_dma_sequencer = False 490 sequencers = [] 491 for param in self.config_parameters: 492 if param.name == "dma_sequencer": 493 contains_dma_sequencer = True 494 elif re.compile("sequencer").search(param.name): 495 sequencers.append(param.name) 496 if param.pointer: 497 code('m_${{param.name}}_ptr = p->${{param.name}};') 498 else: 499 code('m_${{param.name}} = p->${{param.name}};') 500 501 # 502 # For the l1 cache controller, add the special atomic support which 503 # includes passing the sequencer a pointer to the controller. 504 # 505 if self.ident == "L1Cache": 506 if not sequencers: 507 self.error("The L1Cache controller must include the sequencer " \ 508 "configuration parameter") 509 510 for seq in sequencers: 511 code(''' 512m_${{seq}}_ptr->setController(this); 513 ''') 514 515 else: 516 for seq in sequencers: 517 code(''' 518m_${{seq}}_ptr->setController(this); 519 ''') 520 521 # 522 # For the DMA controller, pass the sequencer a pointer to the 523 # controller. 524 # 525 if self.ident == "DMA": 526 if not contains_dma_sequencer: 527 self.error("The DMA controller must include the sequencer " \ 528 "configuration parameter") 529 530 code(''' 531m_dma_sequencer_ptr->setController(this); 532''') 533 534 code('m_num_controllers++;') 535 for var in self.objects: 536 if var.ident.find("mandatoryQueue") >= 0: 537 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 538 539 code.dedent() 540 code(''' 541} 542 543void 544$c_ident::init() 545{ 546 MachineType machine_type; 547 int base; 548 549 m_machineID.type = MachineType_${ident}; 550 m_machineID.num = m_version; 551 552 // initialize objects 553 m_profiler.setVersion(m_version); 554 s_profileDumper.registerProfiler(&m_profiler); 555 556''') 557 558 code.indent() 559 for var in self.objects: 560 vtype = var.type 561 vid = "m_%s_ptr" % var.c_ident 562 if "network" not in var: 563 # Not a network port object 564 if "primitive" in vtype: 565 code('$vid = new ${{vtype.c_ident}};') 566 if "default" in var: 567 code('(*$vid) = ${{var["default"]}};') 568 else: 569 # Normal Object 570 # added by SS 571 if "factory" in var: 572 code('$vid = ${{var["factory"]}};') 573 elif var.ident.find("mandatoryQueue") < 0: 574 th = var.get("template_hack", "") 575 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 576 577 args = "" 578 if "non_obj" not in vtype and not vtype.isEnumeration: 579 if expr.find("TBETable") >= 0: 580 args = "m_number_of_TBEs" 581 else: 582 args = var.get("constructor_hack", "") 583 584 code('$expr($args);') 585 586 code('assert($vid != NULL);') 587 588 if "default" in var: 589 code('*$vid = ${{var["default"]}}; // Object default') 590 elif "default" in vtype: 591 comment = "Type %s default" % vtype.ident 592 code('*$vid = ${{vtype["default"]}}; // $comment') 593 594 # Set ordering 595 if "ordered" in var and "trigger_queue" not in var: 596 # A buffer 597 code('$vid->setOrdering(${{var["ordered"]}});') 598 599 # Set randomization 600 if "random" in var: 601 # A buffer 602 code('$vid->setRandomization(${{var["random"]}});') 603 604 # Set Priority 605 if vtype.isBuffer and \ 606 "rank" in var and "trigger_queue" not in var: 607 code('$vid->setPriority(${{var["rank"]}});') 608 609 else: 610 # Network port object 611 network = var["network"] 612 ordered = var["ordered"] 613 vnet = var["virtual_network"] 614 vnet_type = var["vnet_type"] 615 616 assert var.machine is not None 617 code(''' 618machine_type = string_to_MachineType("${{var.machine.ident}}"); 619base = MachineType_base_number(machine_type); 620$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 621''') 622 623 code('assert($vid != NULL);') 624 625 # Set ordering 626 if "ordered" in var: 627 # A buffer 628 code('$vid->setOrdering(${{var["ordered"]}});') 629 630 # Set randomization 631 if "random" in var: 632 # A buffer 633 code('$vid->setRandomization(${{var["random"]}});') 634 635 # Set Priority 636 if "rank" in var: 637 code('$vid->setPriority(${{var["rank"]}})') 638 639 # Set buffer size 640 if vtype.isBuffer: 641 code(''' 642if (m_buffer_size > 0) { 643 $vid->resize(m_buffer_size); 644} 645''') 646 647 # set description (may be overriden later by port def) 648 code(''' 649$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]"); 650 651''') 652 653 if vtype.isBuffer: 654 if "recycle_latency" in var: 655 code('$vid->setRecycleLatency(${{var["recycle_latency"]}});') 656 else: 657 code('$vid->setRecycleLatency(m_recycle_latency);') 658 659 660 # Set the queue consumers 661 code() 662 for port in self.in_ports: 663 code('${{port.code}}.setConsumer(this);') 664 665 # Set the queue descriptions 666 code() 667 for port in self.in_ports: 668 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 669 670 # Initialize the transition profiling 671 code() 672 for trans in self.transitions: 673 # Figure out if we stall 674 stall = False 675 for action in trans.actions: 676 if action.ident == "z_stall": 677 stall = True 678 679 # Only possible if it is not a 'z' case 680 if not stall: 681 state = "%s_State_%s" % (self.ident, trans.state.ident) 682 event = "%s_Event_%s" % (self.ident, trans.event.ident) 683 code('m_profiler.possibleTransition($state, $event);') 684 685 code.dedent() 686 code('}') 687 688 has_mandatory_q = False 689 for port in self.in_ports: 690 if port.code.find("mandatoryQueue_ptr") >= 0: 691 has_mandatory_q = True 692 693 if has_mandatory_q: 694 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 695 else: 696 mq_ident = "NULL" 697 698 seq_ident = "NULL" 699 for param in self.config_parameters: 700 if param.name == "sequencer": 701 assert(param.pointer) 702 seq_ident = "m_%s_ptr" % param.name 703 704 code(''' 705int 706$c_ident::getNumControllers() 707{ 708 return m_num_controllers; 709} 710 711MessageBuffer* 712$c_ident::getMandatoryQueue() const 713{ 714 return $mq_ident; 715} 716 717Sequencer* 718$c_ident::getSequencer() const 719{ 720 return $seq_ident; 721} 722 723const int & 724$c_ident::getVersion() const 725{ 726 return m_version; 727} 728 729const string 730$c_ident::toString() const 731{ 732 return "$c_ident"; 733} 734 735const string 736$c_ident::getName() const 737{ 738 return m_name; 739} 740 741void 742$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 743{ 744 if (m_waiting_buffers.count(addr) == 0) { 745 MsgVecType* msgVec = new MsgVecType; 746 msgVec->resize(m_max_in_port_rank, NULL); 747 m_waiting_buffers[addr] = msgVec; 748 } 749 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 750} 751 752void 753$c_ident::wakeUpBuffers(Address addr) 754{ 755 if (m_waiting_buffers.count(addr) > 0) { 756 // 757 // Wake up all possible lower rank (i.e. lower priority) buffers that could 758 // be waiting on this message. 759 // 760 for (int in_port_rank = m_cur_in_port_rank - 1; 761 in_port_rank >= 0; 762 in_port_rank--) { 763 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 764 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 765 } 766 } 767 delete m_waiting_buffers[addr]; 768 m_waiting_buffers.erase(addr); 769 } 770} 771 772void 773$c_ident::wakeUpAllBuffers() 774{ 775 // 776 // Wake up all possible buffers that could be waiting on any message. 777 // 778 779 std::vector<MsgVecType*> wokeUpMsgVecs; 780 781 if(m_waiting_buffers.size() > 0) { 782 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 783 buf_iter != m_waiting_buffers.end(); 784 ++buf_iter) { 785 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 786 vec_iter != buf_iter->second->end(); 787 ++vec_iter) { 788 if (*vec_iter != NULL) { 789 (*vec_iter)->reanalyzeAllMessages(); 790 } 791 } 792 wokeUpMsgVecs.push_back(buf_iter->second); 793 } 794 795 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 796 wb_iter != wokeUpMsgVecs.end(); 797 ++wb_iter) { 798 delete (*wb_iter); 799 } 800 801 m_waiting_buffers.clear(); 802 } 803} 804 805void 806$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 807{ 808 m_is_blocking = true; 809 m_block_map[addr] = port; 810} 811 812void 813$c_ident::unblock(Address addr) 814{ 815 m_block_map.erase(addr); 816 if (m_block_map.size() == 0) { 817 m_is_blocking = false; 818 } 819} 820 821void 822$c_ident::print(ostream& out) const 823{ 824 out << "[$c_ident " << m_version << "]"; 825} 826 827void 828$c_ident::printConfig(ostream& out) const 829{ 830 out << "$c_ident config: " << m_name << endl; 831 out << " version: " << m_version << endl; 832 map<string, string>::const_iterator it; 833 for (it = m_cfg.begin(); it != m_cfg.end(); it++) 834 out << " " << it->first << ": " << it->second << endl; 835} 836 837void 838$c_ident::printStats(ostream& out) const 839{ 840''') 841 # 842 # Cache and Memory Controllers have specific profilers associated with 843 # them. Print out these stats before dumping state transition stats. 844 # 845 for param in self.config_parameters: 846 if param.type_ast.type.ident == "CacheMemory" or \ 847 param.type_ast.type.ident == "DirectoryMemory" or \ 848 param.type_ast.type.ident == "MemoryControl": 849 assert(param.pointer) 850 code(' m_${{param.ident}}_ptr->printStats(out);') 851 852 code(''' 853 if (m_version == 0) { 854 s_profileDumper.dumpStats(out); 855 } 856} 857 858void $c_ident::clearStats() { 859''') 860 # 861 # Cache and Memory Controllers have specific profilers associated with 862 # them. These stats must be cleared too. 863 # 864 for param in self.config_parameters: 865 if param.type_ast.type.ident == "CacheMemory" or \ 866 param.type_ast.type.ident == "MemoryControl": 867 assert(param.pointer) 868 code(' m_${{param.ident}}_ptr->clearStats();') 869 870 code(''' 871 m_profiler.clearStats(); 872} 873''') 874 875 if self.EntryType != None: 876 code(''' 877 878// Set and Reset for cache_entry variable 879void 880$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 881{ 882 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 883} 884 885void 886$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 887{ 888 m_cache_entry_ptr = 0; 889} 890''') 891 892 if self.TBEType != None: 893 code(''' 894 895// Set and Reset for tbe variable 896void 897$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 898{ 899 m_tbe_ptr = m_new_tbe; 900} 901 902void 903$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 904{ 905 m_tbe_ptr = NULL; 906} 907''') 908 909 code(''' 910 911void 912$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 913{ 914''') 915 # 916 # Record cache contents for all associated caches. 917 # 918 code.indent() 919 for param in self.config_parameters: 920 if param.type_ast.type.ident == "CacheMemory": 921 assert(param.pointer) 922 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 923 924 code.dedent() 925 code(''' 926} 927 928// Actions 929''') 930 if self.TBEType != None and self.EntryType != None: 931 for action in self.actions.itervalues(): 932 if "c_code" not in action: 933 continue 934 935 code(''' 936/** \\brief ${{action.desc}} */ 937void 938$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 939{ 940 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 941 ${{action["c_code"]}} 942} 943 944''') 945 elif self.TBEType != None: 946 for action in self.actions.itervalues(): 947 if "c_code" not in action: 948 continue 949 950 code(''' 951/** \\brief ${{action.desc}} */ 952void 953$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 954{ 955 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 956 ${{action["c_code"]}} 957} 958 959''') 960 elif self.EntryType != None: 961 for action in self.actions.itervalues(): 962 if "c_code" not in action: 963 continue 964 965 code(''' 966/** \\brief ${{action.desc}} */ 967void 968$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 969{ 970 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 971 ${{action["c_code"]}} 972} 973 974''') 975 else: 976 for action in self.actions.itervalues(): 977 if "c_code" not in action: 978 continue 979 980 code(''' 981/** \\brief ${{action.desc}} */ 982void 983$c_ident::${{action.ident}}(const Address& addr) 984{ 985 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 986 ${{action["c_code"]}} 987} 988 989''') 990 for func in self.functions: 991 code(func.generateCode()) 992 993 code.write(path, "%s.cc" % c_ident) 994 995 def printCWakeup(self, path, includes): 996 '''Output the wakeup loop for the events''' 997 998 code = self.symtab.codeFormatter() 999 ident = self.ident 1000 1001 outputRequest_types = True 1002 if len(self.request_types) == 0: 1003 outputRequest_types = False 1004 1005 code(''' 1006// Auto generated C++ code started by $__file__:$__line__ 1007// ${ident}: ${{self.short}} 1008 1009#include <sys/types.h> 1010#include <unistd.h> 1011 1012#include <cassert> 1013 1014#include "base/misc.hh" 1015#include "debug/RubySlicc.hh" 1016#include "mem/protocol/${ident}_Controller.hh" 1017#include "mem/protocol/${ident}_Event.hh" 1018#include "mem/protocol/${ident}_State.hh" 1019''') 1020 1021 if outputRequest_types: 1022 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1023 1024 code(''' 1025#include "mem/protocol/Types.hh" 1026#include "mem/ruby/common/Global.hh" 1027#include "mem/ruby/system/System.hh" 1028''') 1029 1030 1031 for include_path in includes: 1032 code('#include "${{include_path}}"') 1033 1034 code(''' 1035 1036using namespace std; 1037 1038void 1039${ident}_Controller::wakeup() 1040{ 1041 int counter = 0; 1042 while (true) { 1043 // Some cases will put us into an infinite loop without this limit 1044 assert(counter <= m_transitions_per_cycle); 1045 if (counter == m_transitions_per_cycle) { 1046 // Count how often we are fully utilized 1047 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 1048 1049 // Wakeup in another cycle and try again 1050 scheduleEvent(1); 1051 break; 1052 } 1053''') 1054 1055 code.indent() 1056 code.indent() 1057 1058 # InPorts 1059 # 1060 for port in self.in_ports: 1061 code.indent() 1062 code('// ${ident}InPort $port') 1063 if port.pairs.has_key("rank"): 1064 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1065 else: 1066 code('m_cur_in_port_rank = 0;') 1067 code('${{port["c_code_in_port"]}}') 1068 code.dedent() 1069 1070 code('') 1071 1072 code.dedent() 1073 code.dedent() 1074 code(''' 1075 break; // If we got this far, we have nothing left todo 1076 } 1077} 1078''') 1079 1080 code.write(path, "%s_Wakeup.cc" % self.ident) 1081 1082 def printCSwitch(self, path): 1083 '''Output switch statement for transition table''' 1084 1085 code = self.symtab.codeFormatter() 1086 ident = self.ident 1087 1088 code(''' 1089// Auto generated C++ code started by $__file__:$__line__ 1090// ${ident}: ${{self.short}} 1091 1092#include <cassert> 1093 1094#include "base/misc.hh" 1095#include "base/trace.hh" 1096#include "debug/ProtocolTrace.hh" 1097#include "debug/RubyGenerated.hh" 1098#include "mem/protocol/${ident}_Controller.hh" 1099#include "mem/protocol/${ident}_Event.hh" 1100#include "mem/protocol/${ident}_State.hh" 1101#include "mem/protocol/Types.hh" 1102#include "mem/ruby/common/Global.hh" 1103#include "mem/ruby/system/System.hh" 1104 1105#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1106 1107#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1108#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1109 1110TransitionResult 1111${ident}_Controller::doTransition(${ident}_Event event, 1112''') 1113 if self.EntryType != None: 1114 code(''' 1115 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1116''') 1117 if self.TBEType != None: 1118 code(''' 1119 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1120''') 1121 code(''' 1122 const Address &addr) 1123{ 1124''') 1125 if self.TBEType != None and self.EntryType != None: 1126 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1127 elif self.TBEType != None: 1128 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1129 elif self.EntryType != None: 1130 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1131 else: 1132 code('${ident}_State state = getState(addr);') 1133 1134 code(''' 1135 ${ident}_State next_state = state; 1136 1137 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1138 *this, g_system_ptr->getTime(), ${ident}_State_to_string(state), 1139 ${ident}_Event_to_string(event), addr); 1140 1141 TransitionResult result = 1142''') 1143 if self.TBEType != None and self.EntryType != None: 1144 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1145 elif self.TBEType != None: 1146 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1147 elif self.EntryType != None: 1148 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1149 else: 1150 code('doTransitionWorker(event, state, next_state, addr);') 1151 1152 code(''' 1153 if (result == TransitionResult_Valid) { 1154 DPRINTF(RubyGenerated, "next_state: %s\\n", 1155 ${ident}_State_to_string(next_state)); 1156 m_profiler.countTransition(state, event); 1157 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1158 curTick(), m_version, "${ident}", 1159 ${ident}_Event_to_string(event), 1160 ${ident}_State_to_string(state), 1161 ${ident}_State_to_string(next_state), 1162 addr, GET_TRANSITION_COMMENT()); 1163 1164 CLEAR_TRANSITION_COMMENT(); 1165''') 1166 if self.TBEType != None and self.EntryType != None: 1167 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1168 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1169 elif self.TBEType != None: 1170 code('setState(m_tbe_ptr, addr, next_state);') 1171 code('setAccessPermission(addr, next_state);') 1172 elif self.EntryType != None: 1173 code('setState(m_cache_entry_ptr, addr, next_state);') 1174 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1175 else: 1176 code('setState(addr, next_state);') 1177 code('setAccessPermission(addr, next_state);') 1178 1179 code(''' 1180 } else if (result == TransitionResult_ResourceStall) { 1181 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1182 curTick(), m_version, "${ident}", 1183 ${ident}_Event_to_string(event), 1184 ${ident}_State_to_string(state), 1185 ${ident}_State_to_string(next_state), 1186 addr, "Resource Stall"); 1187 } else if (result == TransitionResult_ProtocolStall) { 1188 DPRINTF(RubyGenerated, "stalling\\n"); 1189 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1190 curTick(), m_version, "${ident}", 1191 ${ident}_Event_to_string(event), 1192 ${ident}_State_to_string(state), 1193 ${ident}_State_to_string(next_state), 1194 addr, "Protocol Stall"); 1195 } 1196 1197 return result; 1198} 1199 1200TransitionResult 1201${ident}_Controller::doTransitionWorker(${ident}_Event event, 1202 ${ident}_State state, 1203 ${ident}_State& next_state, 1204''') 1205 1206 if self.TBEType != None: 1207 code(''' 1208 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1209''') 1210 if self.EntryType != None: 1211 code(''' 1212 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1213''') 1214 code(''' 1215 const Address& addr) 1216{ 1217 switch(HASH_FUN(state, event)) { 1218''') 1219 1220 # This map will allow suppress generating duplicate code 1221 cases = orderdict() 1222 1223 for trans in self.transitions: 1224 case_string = "%s_State_%s, %s_Event_%s" % \ 1225 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1226 1227 case = self.symtab.codeFormatter() 1228 # Only set next_state if it changes 1229 if trans.state != trans.nextState: 1230 ns_ident = trans.nextState.ident 1231 case('next_state = ${ident}_State_${ns_ident};') 1232 1233 actions = trans.actions 1234 request_types = trans.request_types 1235 1236 # Check for resources 1237 case_sorter = [] 1238 res = trans.resources 1239 for key,val in res.iteritems(): 1240 if key.type.ident != "DNUCAStopTable": 1241 val = ''' 1242if (!%s.areNSlotsAvailable(%s)) 1243 return TransitionResult_ResourceStall; 1244''' % (key.code, val) 1245 case_sorter.append(val) 1246 1247 # Check all of the request_types for resource constraints 1248 for request_type in request_types: 1249 val = ''' 1250if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1251 return TransitionResult_ResourceStall; 1252} 1253''' % (self.ident, request_type.ident) 1254 case_sorter.append(val) 1255 1256 # Emit the code sequences in a sorted order. This makes the 1257 # output deterministic (without this the output order can vary 1258 # since Map's keys() on a vector of pointers is not deterministic 1259 for c in sorted(case_sorter): 1260 case("$c") 1261 1262 # Record access types for this transition 1263 for request_type in request_types: 1264 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1265 1266 # Figure out if we stall 1267 stall = False 1268 for action in actions: 1269 if action.ident == "z_stall": 1270 stall = True 1271 break 1272 1273 if stall: 1274 case('return TransitionResult_ProtocolStall;') 1275 else: 1276 if self.TBEType != None and self.EntryType != None: 1277 for action in actions: 1278 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1279 elif self.TBEType != None: 1280 for action in actions: 1281 case('${{action.ident}}(m_tbe_ptr, addr);') 1282 elif self.EntryType != None: 1283 for action in actions: 1284 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1285 else: 1286 for action in actions: 1287 case('${{action.ident}}(addr);') 1288 case('return TransitionResult_Valid;') 1289 1290 case = str(case) 1291 1292 # Look to see if this transition code is unique. 1293 if case not in cases: 1294 cases[case] = [] 1295 1296 cases[case].append(case_string) 1297 1298 # Walk through all of the unique code blocks and spit out the 1299 # corresponding case statement elements 1300 for case,transitions in cases.iteritems(): 1301 # Iterative over all the multiple transitions that share 1302 # the same code 1303 for trans in transitions: 1304 code(' case HASH_FUN($trans):') 1305 code(' $case') 1306 1307 code(''' 1308 default: 1309 fatal("Invalid transition\\n" 1310 "%s time: %d addr: %s event: %s state: %s\\n", 1311 name(), g_system_ptr->getTime(), addr, event, state); 1312 } 1313 return TransitionResult_Valid; 1314} 1315''') 1316 code.write(path, "%s_Transitions.cc" % self.ident) 1317 1318 def printProfileDumperHH(self, path): 1319 code = self.symtab.codeFormatter() 1320 ident = self.ident 1321 1322 code(''' 1323// Auto generated C++ code started by $__file__:$__line__ 1324// ${ident}: ${{self.short}} 1325 1326#ifndef __${ident}_PROFILE_DUMPER_HH__ 1327#define __${ident}_PROFILE_DUMPER_HH__ 1328 1329#include <cassert> 1330#include <iostream> 1331#include <vector> 1332 1333#include "${ident}_Event.hh" 1334#include "${ident}_Profiler.hh" 1335 1336typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1337 1338class ${ident}_ProfileDumper 1339{ 1340 public: 1341 ${ident}_ProfileDumper(); 1342 void registerProfiler(${ident}_Profiler* profiler); 1343 void dumpStats(std::ostream& out) const; 1344 1345 private: 1346 ${ident}_profilers m_profilers; 1347}; 1348 1349#endif // __${ident}_PROFILE_DUMPER_HH__ 1350''') 1351 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1352 1353 def printProfileDumperCC(self, path): 1354 code = self.symtab.codeFormatter() 1355 ident = self.ident 1356 1357 code(''' 1358// Auto generated C++ code started by $__file__:$__line__ 1359// ${ident}: ${{self.short}} 1360 1361#include "mem/protocol/${ident}_ProfileDumper.hh" 1362 1363${ident}_ProfileDumper::${ident}_ProfileDumper() 1364{ 1365} 1366 1367void 1368${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1369{ 1370 m_profilers.push_back(profiler); 1371} 1372 1373void 1374${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1375{ 1376 out << " --- ${ident} ---\\n"; 1377 out << " - Event Counts -\\n"; 1378 for (${ident}_Event event = ${ident}_Event_FIRST; 1379 event < ${ident}_Event_NUM; 1380 ++event) { 1381 out << (${ident}_Event) event << " ["; 1382 uint64 total = 0; 1383 for (int i = 0; i < m_profilers.size(); i++) { 1384 out << m_profilers[i]->getEventCount(event) << " "; 1385 total += m_profilers[i]->getEventCount(event); 1386 } 1387 out << "] " << total << "\\n"; 1388 } 1389 out << "\\n"; 1390 out << " - Transitions -\\n"; 1391 for (${ident}_State state = ${ident}_State_FIRST; 1392 state < ${ident}_State_NUM; 1393 ++state) { 1394 for (${ident}_Event event = ${ident}_Event_FIRST; 1395 event < ${ident}_Event_NUM; 1396 ++event) { 1397 if (m_profilers[0]->isPossible(state, event)) { 1398 out << (${ident}_State) state << " " 1399 << (${ident}_Event) event << " ["; 1400 uint64 total = 0; 1401 for (int i = 0; i < m_profilers.size(); i++) { 1402 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1403 total += m_profilers[i]->getTransitionCount(state, event); 1404 } 1405 out << "] " << total << "\\n"; 1406 } 1407 } 1408 out << "\\n"; 1409 } 1410} 1411''') 1412 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1413 1414 def printProfilerHH(self, path): 1415 code = self.symtab.codeFormatter() 1416 ident = self.ident 1417 1418 code(''' 1419// Auto generated C++ code started by $__file__:$__line__ 1420// ${ident}: ${{self.short}} 1421 1422#ifndef __${ident}_PROFILER_HH__ 1423#define __${ident}_PROFILER_HH__ 1424 1425#include <cassert> 1426#include <iostream> 1427 1428#include "mem/protocol/${ident}_Event.hh" 1429#include "mem/protocol/${ident}_State.hh" 1430#include "mem/ruby/common/TypeDefines.hh" 1431 1432class ${ident}_Profiler 1433{ 1434 public: 1435 ${ident}_Profiler(); 1436 void setVersion(int version); 1437 void countTransition(${ident}_State state, ${ident}_Event event); 1438 void possibleTransition(${ident}_State state, ${ident}_Event event); 1439 uint64 getEventCount(${ident}_Event event); 1440 bool isPossible(${ident}_State state, ${ident}_Event event); 1441 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1442 void clearStats(); 1443 1444 private: 1445 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1446 int m_event_counters[${ident}_Event_NUM]; 1447 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1448 int m_version; 1449}; 1450 1451#endif // __${ident}_PROFILER_HH__ 1452''') 1453 code.write(path, "%s_Profiler.hh" % self.ident) 1454 1455 def printProfilerCC(self, path): 1456 code = self.symtab.codeFormatter() 1457 ident = self.ident 1458 1459 code(''' 1460// Auto generated C++ code started by $__file__:$__line__ 1461// ${ident}: ${{self.short}} 1462 1463#include <cassert> 1464 1465#include "mem/protocol/${ident}_Profiler.hh" 1466 1467${ident}_Profiler::${ident}_Profiler() 1468{ 1469 for (int state = 0; state < ${ident}_State_NUM; state++) { 1470 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1471 m_possible[state][event] = false; 1472 m_counters[state][event] = 0; 1473 } 1474 } 1475 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1476 m_event_counters[event] = 0; 1477 } 1478} 1479 1480void 1481${ident}_Profiler::setVersion(int version) 1482{ 1483 m_version = version; 1484} 1485 1486void 1487${ident}_Profiler::clearStats() 1488{ 1489 for (int state = 0; state < ${ident}_State_NUM; state++) { 1490 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1491 m_counters[state][event] = 0; 1492 } 1493 } 1494 1495 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1496 m_event_counters[event] = 0; 1497 } 1498} 1499void 1500${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1501{ 1502 assert(m_possible[state][event]); 1503 m_counters[state][event]++; 1504 m_event_counters[event]++; 1505} 1506void 1507${ident}_Profiler::possibleTransition(${ident}_State state, 1508 ${ident}_Event event) 1509{ 1510 m_possible[state][event] = true; 1511} 1512 1513uint64 1514${ident}_Profiler::getEventCount(${ident}_Event event) 1515{ 1516 return m_event_counters[event]; 1517} 1518 1519bool 1520${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1521{ 1522 return m_possible[state][event]; 1523} 1524 1525uint64 1526${ident}_Profiler::getTransitionCount(${ident}_State state, 1527 ${ident}_Event event) 1528{ 1529 return m_counters[state][event]; 1530} 1531 1532''') 1533 code.write(path, "%s_Profiler.cc" % self.ident) 1534 1535 # ************************** 1536 # ******* HTML Files ******* 1537 # ************************** 1538 def frameRef(self, click_href, click_target, over_href, over_num, text): 1539 code = self.symtab.codeFormatter(fix_newlines=False) 1540 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1541 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1542 parent.frames[$over_num].location='$over_href' 1543 }\"> 1544 ${{html.formatShorthand(text)}} 1545 </A>""") 1546 return str(code) 1547 1548 def writeHTMLFiles(self, path): 1549 # Create table with no row hilighted 1550 self.printHTMLTransitions(path, None) 1551 1552 # Generate transition tables 1553 for state in self.states.itervalues(): 1554 self.printHTMLTransitions(path, state) 1555 1556 # Generate action descriptions 1557 for action in self.actions.itervalues(): 1558 name = "%s_action_%s.html" % (self.ident, action.ident) 1559 code = html.createSymbol(action, "Action") 1560 code.write(path, name) 1561 1562 # Generate state descriptions 1563 for state in self.states.itervalues(): 1564 name = "%s_State_%s.html" % (self.ident, state.ident) 1565 code = html.createSymbol(state, "State") 1566 code.write(path, name) 1567 1568 # Generate event descriptions 1569 for event in self.events.itervalues(): 1570 name = "%s_Event_%s.html" % (self.ident, event.ident) 1571 code = html.createSymbol(event, "Event") 1572 code.write(path, name) 1573 1574 def printHTMLTransitions(self, path, active_state): 1575 code = self.symtab.codeFormatter() 1576 1577 code(''' 1578<HTML> 1579<BODY link="blue" vlink="blue"> 1580 1581<H1 align="center">${{html.formatShorthand(self.short)}}: 1582''') 1583 code.indent() 1584 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1585 mid = machine.ident 1586 if i != 0: 1587 extra = " - " 1588 else: 1589 extra = "" 1590 if machine == self: 1591 code('$extra$mid') 1592 else: 1593 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1594 code.dedent() 1595 1596 code(""" 1597</H1> 1598 1599<TABLE border=1> 1600<TR> 1601 <TH> </TH> 1602""") 1603 1604 for event in self.events.itervalues(): 1605 href = "%s_Event_%s.html" % (self.ident, event.ident) 1606 ref = self.frameRef(href, "Status", href, "1", event.short) 1607 code('<TH bgcolor=white>$ref</TH>') 1608 1609 code('</TR>') 1610 # -- Body of table 1611 for state in self.states.itervalues(): 1612 # -- Each row 1613 if state == active_state: 1614 color = "yellow" 1615 else: 1616 color = "white" 1617 1618 click = "%s_table_%s.html" % (self.ident, state.ident) 1619 over = "%s_State_%s.html" % (self.ident, state.ident) 1620 text = html.formatShorthand(state.short) 1621 ref = self.frameRef(click, "Table", over, "1", state.short) 1622 code(''' 1623<TR> 1624 <TH bgcolor=$color>$ref</TH> 1625''') 1626 1627 # -- One column for each event 1628 for event in self.events.itervalues(): 1629 trans = self.table.get((state,event), None) 1630 if trans is None: 1631 # This is the no transition case 1632 if state == active_state: 1633 color = "#C0C000" 1634 else: 1635 color = "lightgrey" 1636 1637 code('<TD bgcolor=$color> </TD>') 1638 continue 1639 1640 next = trans.nextState 1641 stall_action = False 1642 1643 # -- Get the actions 1644 for action in trans.actions: 1645 if action.ident == "z_stall" or \ 1646 action.ident == "zz_recycleMandatoryQueue": 1647 stall_action = True 1648 1649 # -- Print out "actions/next-state" 1650 if stall_action: 1651 if state == active_state: 1652 color = "#C0C000" 1653 else: 1654 color = "lightgrey" 1655 1656 elif active_state and next.ident == active_state.ident: 1657 color = "aqua" 1658 elif state == active_state: 1659 color = "yellow" 1660 else: 1661 color = "white" 1662 1663 code('<TD bgcolor=$color>') 1664 for action in trans.actions: 1665 href = "%s_action_%s.html" % (self.ident, action.ident) 1666 ref = self.frameRef(href, "Status", href, "1", 1667 action.short) 1668 code(' $ref') 1669 if next != state: 1670 if trans.actions: 1671 code('/') 1672 click = "%s_table_%s.html" % (self.ident, next.ident) 1673 over = "%s_State_%s.html" % (self.ident, next.ident) 1674 ref = self.frameRef(click, "Table", over, "1", next.short) 1675 code("$ref") 1676 code("</TD>") 1677 1678 # -- Each row 1679 if state == active_state: 1680 color = "yellow" 1681 else: 1682 color = "white" 1683 1684 click = "%s_table_%s.html" % (self.ident, state.ident) 1685 over = "%s_State_%s.html" % (self.ident, state.ident) 1686 ref = self.frameRef(click, "Table", over, "1", state.short) 1687 code(''' 1688 <TH bgcolor=$color>$ref</TH> 1689</TR> 1690''') 1691 code(''' 1692<!- Column footer-> 1693<TR> 1694 <TH> </TH> 1695''') 1696 1697 for event in self.events.itervalues(): 1698 href = "%s_Event_%s.html" % (self.ident, event.ident) 1699 ref = self.frameRef(href, "Status", href, "1", event.short) 1700 code('<TH bgcolor=white>$ref</TH>') 1701 code(''' 1702</TR> 1703</TABLE> 1704</BODY></HTML> 1705''') 1706 1707 1708 if active_state: 1709 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1710 else: 1711 name = "%s_table.html" % self.ident 1712 code.write(path, name) 1713 1714__all__ = [ "StateMachine" ] 1715