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