StateMachine.py revision 9366:bf8eb26c7b7e
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 531 m_machineID.type = MachineType_${ident}; 532 m_machineID.num = m_version; 533 534 // initialize objects 535 m_profiler.setVersion(m_version); 536 s_profileDumper.registerProfiler(&m_profiler); 537 538''') 539 540 code.indent() 541 for var in self.objects: 542 vtype = var.type 543 vid = "m_%s_ptr" % var.c_ident 544 if "network" not in var: 545 # Not a network port object 546 if "primitive" in vtype: 547 code('$vid = new ${{vtype.c_ident}};') 548 if "default" in var: 549 code('(*$vid) = ${{var["default"]}};') 550 else: 551 # Normal Object 552 # added by SS 553 if "factory" in var: 554 code('$vid = ${{var["factory"]}};') 555 elif var.ident.find("mandatoryQueue") < 0: 556 th = var.get("template", "") 557 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 558 args = "" 559 if "non_obj" not in vtype and not vtype.isEnumeration: 560 args = var.get("constructor", "") 561 code('$expr($args);') 562 563 code('assert($vid != NULL);') 564 565 if "default" in var: 566 code('*$vid = ${{var["default"]}}; // Object default') 567 elif "default" in vtype: 568 comment = "Type %s default" % vtype.ident 569 code('*$vid = ${{vtype["default"]}}; // $comment') 570 571 # Set ordering 572 if "ordered" in var and "trigger_queue" not in var: 573 # A buffer 574 code('$vid->setOrdering(${{var["ordered"]}});') 575 576 # Set randomization 577 if "random" in var: 578 # A buffer 579 code('$vid->setRandomization(${{var["random"]}});') 580 581 # Set Priority 582 if vtype.isBuffer and \ 583 "rank" in var and "trigger_queue" not in var: 584 code('$vid->setPriority(${{var["rank"]}});') 585 586 else: 587 # Network port object 588 network = var["network"] 589 ordered = var["ordered"] 590 vnet = var["virtual_network"] 591 vnet_type = var["vnet_type"] 592 593 assert var.machine is not None 594 code(''' 595machine_type = string_to_MachineType("${{var.machine.ident}}"); 596base = MachineType_base_number(machine_type); 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 # Set the queue consumers 642 code() 643 for port in self.in_ports: 644 code('${{port.code}}.setConsumer(this);') 645 646 # Set the queue descriptions 647 code() 648 for port in self.in_ports: 649 code('${{port.code}}.setDescription("[Version " + to_string(m_version) + ", $ident, $port]");') 650 651 # Initialize the transition profiling 652 code() 653 for trans in self.transitions: 654 # Figure out if we stall 655 stall = False 656 for action in trans.actions: 657 if action.ident == "z_stall": 658 stall = True 659 660 # Only possible if it is not a 'z' case 661 if not stall: 662 state = "%s_State_%s" % (self.ident, trans.state.ident) 663 event = "%s_Event_%s" % (self.ident, trans.event.ident) 664 code('m_profiler.possibleTransition($state, $event);') 665 666 code.dedent() 667 code('}') 668 669 has_mandatory_q = False 670 for port in self.in_ports: 671 if port.code.find("mandatoryQueue_ptr") >= 0: 672 has_mandatory_q = True 673 674 if has_mandatory_q: 675 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 676 else: 677 mq_ident = "NULL" 678 679 seq_ident = "NULL" 680 for param in self.config_parameters: 681 if param.name == "sequencer": 682 assert(param.pointer) 683 seq_ident = "m_%s_ptr" % param.name 684 685 code(''' 686int 687$c_ident::getNumControllers() 688{ 689 return m_num_controllers; 690} 691 692MessageBuffer* 693$c_ident::getMandatoryQueue() const 694{ 695 return $mq_ident; 696} 697 698Sequencer* 699$c_ident::getSequencer() const 700{ 701 return $seq_ident; 702} 703 704const int & 705$c_ident::getVersion() const 706{ 707 return m_version; 708} 709 710const string 711$c_ident::toString() const 712{ 713 return "$c_ident"; 714} 715 716const string 717$c_ident::getName() const 718{ 719 return m_name; 720} 721 722void 723$c_ident::stallBuffer(MessageBuffer* buf, Address addr) 724{ 725 if (m_waiting_buffers.count(addr) == 0) { 726 MsgVecType* msgVec = new MsgVecType; 727 msgVec->resize(m_max_in_port_rank, NULL); 728 m_waiting_buffers[addr] = msgVec; 729 } 730 (*(m_waiting_buffers[addr]))[m_cur_in_port_rank] = buf; 731} 732 733void 734$c_ident::wakeUpBuffers(Address addr) 735{ 736 if (m_waiting_buffers.count(addr) > 0) { 737 // 738 // Wake up all possible lower rank (i.e. lower priority) buffers that could 739 // be waiting on this message. 740 // 741 for (int in_port_rank = m_cur_in_port_rank - 1; 742 in_port_rank >= 0; 743 in_port_rank--) { 744 if ((*(m_waiting_buffers[addr]))[in_port_rank] != NULL) { 745 (*(m_waiting_buffers[addr]))[in_port_rank]->reanalyzeMessages(addr); 746 } 747 } 748 delete m_waiting_buffers[addr]; 749 m_waiting_buffers.erase(addr); 750 } 751} 752 753void 754$c_ident::wakeUpAllBuffers() 755{ 756 // 757 // Wake up all possible buffers that could be waiting on any message. 758 // 759 760 std::vector<MsgVecType*> wokeUpMsgVecs; 761 762 if(m_waiting_buffers.size() > 0) { 763 for (WaitingBufType::iterator buf_iter = m_waiting_buffers.begin(); 764 buf_iter != m_waiting_buffers.end(); 765 ++buf_iter) { 766 for (MsgVecType::iterator vec_iter = buf_iter->second->begin(); 767 vec_iter != buf_iter->second->end(); 768 ++vec_iter) { 769 if (*vec_iter != NULL) { 770 (*vec_iter)->reanalyzeAllMessages(); 771 } 772 } 773 wokeUpMsgVecs.push_back(buf_iter->second); 774 } 775 776 for (std::vector<MsgVecType*>::iterator wb_iter = wokeUpMsgVecs.begin(); 777 wb_iter != wokeUpMsgVecs.end(); 778 ++wb_iter) { 779 delete (*wb_iter); 780 } 781 782 m_waiting_buffers.clear(); 783 } 784} 785 786void 787$c_ident::blockOnQueue(Address addr, MessageBuffer* port) 788{ 789 m_is_blocking = true; 790 m_block_map[addr] = port; 791} 792 793void 794$c_ident::unblock(Address addr) 795{ 796 m_block_map.erase(addr); 797 if (m_block_map.size() == 0) { 798 m_is_blocking = false; 799 } 800} 801 802void 803$c_ident::print(ostream& out) const 804{ 805 out << "[$c_ident " << m_version << "]"; 806} 807 808void 809$c_ident::printStats(ostream& out) const 810{ 811''') 812 # 813 # Cache and Memory Controllers have specific profilers associated with 814 # them. Print out these stats before dumping state transition stats. 815 # 816 for param in self.config_parameters: 817 if param.type_ast.type.ident == "CacheMemory" or \ 818 param.type_ast.type.ident == "DirectoryMemory" or \ 819 param.type_ast.type.ident == "MemoryControl": 820 assert(param.pointer) 821 code(' m_${{param.ident}}_ptr->printStats(out);') 822 823 code(''' 824 if (m_version == 0) { 825 s_profileDumper.dumpStats(out); 826 } 827} 828 829void $c_ident::clearStats() { 830''') 831 # 832 # Cache and Memory Controllers have specific profilers associated with 833 # them. These stats must be cleared too. 834 # 835 for param in self.config_parameters: 836 if param.type_ast.type.ident == "CacheMemory" or \ 837 param.type_ast.type.ident == "MemoryControl": 838 assert(param.pointer) 839 code(' m_${{param.ident}}_ptr->clearStats();') 840 841 code(''' 842 m_profiler.clearStats(); 843} 844''') 845 846 if self.EntryType != None: 847 code(''' 848 849// Set and Reset for cache_entry variable 850void 851$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 852{ 853 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 854} 855 856void 857$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 858{ 859 m_cache_entry_ptr = 0; 860} 861''') 862 863 if self.TBEType != None: 864 code(''' 865 866// Set and Reset for tbe variable 867void 868$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 869{ 870 m_tbe_ptr = m_new_tbe; 871} 872 873void 874$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 875{ 876 m_tbe_ptr = NULL; 877} 878''') 879 880 code(''' 881 882void 883$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 884{ 885''') 886 # 887 # Record cache contents for all associated caches. 888 # 889 code.indent() 890 for param in self.config_parameters: 891 if param.type_ast.type.ident == "CacheMemory": 892 assert(param.pointer) 893 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 894 895 code.dedent() 896 code(''' 897} 898 899// Actions 900''') 901 if self.TBEType != None and self.EntryType != None: 902 for action in self.actions.itervalues(): 903 if "c_code" not in action: 904 continue 905 906 code(''' 907/** \\brief ${{action.desc}} */ 908void 909$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 910{ 911 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 912 ${{action["c_code"]}} 913} 914 915''') 916 elif self.TBEType != None: 917 for action in self.actions.itervalues(): 918 if "c_code" not in action: 919 continue 920 921 code(''' 922/** \\brief ${{action.desc}} */ 923void 924$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 925{ 926 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 927 ${{action["c_code"]}} 928} 929 930''') 931 elif self.EntryType != None: 932 for action in self.actions.itervalues(): 933 if "c_code" not in action: 934 continue 935 936 code(''' 937/** \\brief ${{action.desc}} */ 938void 939$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 940{ 941 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 942 ${{action["c_code"]}} 943} 944 945''') 946 else: 947 for action in self.actions.itervalues(): 948 if "c_code" not in action: 949 continue 950 951 code(''' 952/** \\brief ${{action.desc}} */ 953void 954$c_ident::${{action.ident}}(const Address& addr) 955{ 956 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 957 ${{action["c_code"]}} 958} 959 960''') 961 for func in self.functions: 962 code(func.generateCode()) 963 964 # Function for functional reads from messages buffered in the controller 965 code(''' 966bool 967$c_ident::functionalReadBuffers(PacketPtr& pkt) 968{ 969''') 970 for var in self.objects: 971 vtype = var.type 972 if vtype.isBuffer: 973 vid = "m_%s_ptr" % var.c_ident 974 code('if ($vid->functionalRead(pkt)) { return true; }') 975 code(''' 976 return false; 977} 978''') 979 980 # Function for functional writes to messages buffered in the controller 981 code(''' 982uint32_t 983$c_ident::functionalWriteBuffers(PacketPtr& pkt) 984{ 985 uint32_t num_functional_writes = 0; 986''') 987 for var in self.objects: 988 vtype = var.type 989 if vtype.isBuffer: 990 vid = "m_%s_ptr" % var.c_ident 991 code('num_functional_writes += $vid->functionalWrite(pkt);') 992 code(''' 993 return num_functional_writes; 994} 995''') 996 997 code.write(path, "%s.cc" % c_ident) 998 999 def printCWakeup(self, path, includes): 1000 '''Output the wakeup loop for the events''' 1001 1002 code = self.symtab.codeFormatter() 1003 ident = self.ident 1004 1005 outputRequest_types = True 1006 if len(self.request_types) == 0: 1007 outputRequest_types = False 1008 1009 code(''' 1010// Auto generated C++ code started by $__file__:$__line__ 1011// ${ident}: ${{self.short}} 1012 1013#include <sys/types.h> 1014#include <unistd.h> 1015 1016#include <cassert> 1017 1018#include "base/misc.hh" 1019#include "debug/RubySlicc.hh" 1020#include "mem/protocol/${ident}_Controller.hh" 1021#include "mem/protocol/${ident}_Event.hh" 1022#include "mem/protocol/${ident}_State.hh" 1023''') 1024 1025 if outputRequest_types: 1026 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1027 1028 code(''' 1029#include "mem/protocol/Types.hh" 1030#include "mem/ruby/common/Global.hh" 1031#include "mem/ruby/system/System.hh" 1032''') 1033 1034 1035 for include_path in includes: 1036 code('#include "${{include_path}}"') 1037 1038 code(''' 1039 1040using namespace std; 1041 1042void 1043${ident}_Controller::wakeup() 1044{ 1045 int counter = 0; 1046 while (true) { 1047 // Some cases will put us into an infinite loop without this limit 1048 assert(counter <= m_transitions_per_cycle); 1049 if (counter == m_transitions_per_cycle) { 1050 // Count how often we are fully utilized 1051 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 1052 1053 // Wakeup in another cycle and try again 1054 scheduleEvent(1); 1055 break; 1056 } 1057''') 1058 1059 code.indent() 1060 code.indent() 1061 1062 # InPorts 1063 # 1064 for port in self.in_ports: 1065 code.indent() 1066 code('// ${ident}InPort $port') 1067 if port.pairs.has_key("rank"): 1068 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1069 else: 1070 code('m_cur_in_port_rank = 0;') 1071 code('${{port["c_code_in_port"]}}') 1072 code.dedent() 1073 1074 code('') 1075 1076 code.dedent() 1077 code.dedent() 1078 code(''' 1079 break; // If we got this far, we have nothing left todo 1080 } 1081} 1082''') 1083 1084 code.write(path, "%s_Wakeup.cc" % self.ident) 1085 1086 def printCSwitch(self, path): 1087 '''Output switch statement for transition table''' 1088 1089 code = self.symtab.codeFormatter() 1090 ident = self.ident 1091 1092 code(''' 1093// Auto generated C++ code started by $__file__:$__line__ 1094// ${ident}: ${{self.short}} 1095 1096#include <cassert> 1097 1098#include "base/misc.hh" 1099#include "base/trace.hh" 1100#include "debug/ProtocolTrace.hh" 1101#include "debug/RubyGenerated.hh" 1102#include "mem/protocol/${ident}_Controller.hh" 1103#include "mem/protocol/${ident}_Event.hh" 1104#include "mem/protocol/${ident}_State.hh" 1105#include "mem/protocol/Types.hh" 1106#include "mem/ruby/common/Global.hh" 1107#include "mem/ruby/system/System.hh" 1108 1109#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1110 1111#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1112#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1113 1114TransitionResult 1115${ident}_Controller::doTransition(${ident}_Event event, 1116''') 1117 if self.EntryType != None: 1118 code(''' 1119 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1120''') 1121 if self.TBEType != None: 1122 code(''' 1123 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1124''') 1125 code(''' 1126 const Address &addr) 1127{ 1128''') 1129 if self.TBEType != None and self.EntryType != None: 1130 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1131 elif self.TBEType != None: 1132 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1133 elif self.EntryType != None: 1134 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1135 else: 1136 code('${ident}_State state = getState(addr);') 1137 1138 code(''' 1139 ${ident}_State next_state = state; 1140 1141 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1142 *this, g_system_ptr->getTime(), ${ident}_State_to_string(state), 1143 ${ident}_Event_to_string(event), addr); 1144 1145 TransitionResult result = 1146''') 1147 if self.TBEType != None and self.EntryType != None: 1148 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1149 elif self.TBEType != None: 1150 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1151 elif self.EntryType != None: 1152 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1153 else: 1154 code('doTransitionWorker(event, state, next_state, addr);') 1155 1156 code(''' 1157 if (result == TransitionResult_Valid) { 1158 DPRINTF(RubyGenerated, "next_state: %s\\n", 1159 ${ident}_State_to_string(next_state)); 1160 m_profiler.countTransition(state, event); 1161 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1162 curTick(), m_version, "${ident}", 1163 ${ident}_Event_to_string(event), 1164 ${ident}_State_to_string(state), 1165 ${ident}_State_to_string(next_state), 1166 addr, GET_TRANSITION_COMMENT()); 1167 1168 CLEAR_TRANSITION_COMMENT(); 1169''') 1170 if self.TBEType != None and self.EntryType != None: 1171 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1172 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1173 elif self.TBEType != None: 1174 code('setState(m_tbe_ptr, addr, next_state);') 1175 code('setAccessPermission(addr, next_state);') 1176 elif self.EntryType != None: 1177 code('setState(m_cache_entry_ptr, addr, next_state);') 1178 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1179 else: 1180 code('setState(addr, next_state);') 1181 code('setAccessPermission(addr, next_state);') 1182 1183 code(''' 1184 } else if (result == TransitionResult_ResourceStall) { 1185 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1186 curTick(), m_version, "${ident}", 1187 ${ident}_Event_to_string(event), 1188 ${ident}_State_to_string(state), 1189 ${ident}_State_to_string(next_state), 1190 addr, "Resource Stall"); 1191 } else if (result == TransitionResult_ProtocolStall) { 1192 DPRINTF(RubyGenerated, "stalling\\n"); 1193 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1194 curTick(), m_version, "${ident}", 1195 ${ident}_Event_to_string(event), 1196 ${ident}_State_to_string(state), 1197 ${ident}_State_to_string(next_state), 1198 addr, "Protocol Stall"); 1199 } 1200 1201 return result; 1202} 1203 1204TransitionResult 1205${ident}_Controller::doTransitionWorker(${ident}_Event event, 1206 ${ident}_State state, 1207 ${ident}_State& next_state, 1208''') 1209 1210 if self.TBEType != None: 1211 code(''' 1212 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1213''') 1214 if self.EntryType != None: 1215 code(''' 1216 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1217''') 1218 code(''' 1219 const Address& addr) 1220{ 1221 switch(HASH_FUN(state, event)) { 1222''') 1223 1224 # This map will allow suppress generating duplicate code 1225 cases = orderdict() 1226 1227 for trans in self.transitions: 1228 case_string = "%s_State_%s, %s_Event_%s" % \ 1229 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1230 1231 case = self.symtab.codeFormatter() 1232 # Only set next_state if it changes 1233 if trans.state != trans.nextState: 1234 ns_ident = trans.nextState.ident 1235 case('next_state = ${ident}_State_${ns_ident};') 1236 1237 actions = trans.actions 1238 request_types = trans.request_types 1239 1240 # Check for resources 1241 case_sorter = [] 1242 res = trans.resources 1243 for key,val in res.iteritems(): 1244 if key.type.ident != "DNUCAStopTable": 1245 val = ''' 1246if (!%s.areNSlotsAvailable(%s)) 1247 return TransitionResult_ResourceStall; 1248''' % (key.code, val) 1249 case_sorter.append(val) 1250 1251 # Check all of the request_types for resource constraints 1252 for request_type in request_types: 1253 val = ''' 1254if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1255 return TransitionResult_ResourceStall; 1256} 1257''' % (self.ident, request_type.ident) 1258 case_sorter.append(val) 1259 1260 # Emit the code sequences in a sorted order. This makes the 1261 # output deterministic (without this the output order can vary 1262 # since Map's keys() on a vector of pointers is not deterministic 1263 for c in sorted(case_sorter): 1264 case("$c") 1265 1266 # Record access types for this transition 1267 for request_type in request_types: 1268 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1269 1270 # Figure out if we stall 1271 stall = False 1272 for action in actions: 1273 if action.ident == "z_stall": 1274 stall = True 1275 break 1276 1277 if stall: 1278 case('return TransitionResult_ProtocolStall;') 1279 else: 1280 if self.TBEType != None and self.EntryType != None: 1281 for action in actions: 1282 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1283 elif self.TBEType != None: 1284 for action in actions: 1285 case('${{action.ident}}(m_tbe_ptr, addr);') 1286 elif self.EntryType != None: 1287 for action in actions: 1288 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1289 else: 1290 for action in actions: 1291 case('${{action.ident}}(addr);') 1292 case('return TransitionResult_Valid;') 1293 1294 case = str(case) 1295 1296 # Look to see if this transition code is unique. 1297 if case not in cases: 1298 cases[case] = [] 1299 1300 cases[case].append(case_string) 1301 1302 # Walk through all of the unique code blocks and spit out the 1303 # corresponding case statement elements 1304 for case,transitions in cases.iteritems(): 1305 # Iterative over all the multiple transitions that share 1306 # the same code 1307 for trans in transitions: 1308 code(' case HASH_FUN($trans):') 1309 code(' $case') 1310 1311 code(''' 1312 default: 1313 fatal("Invalid transition\\n" 1314 "%s time: %d addr: %s event: %s state: %s\\n", 1315 name(), g_system_ptr->getTime(), addr, event, state); 1316 } 1317 return TransitionResult_Valid; 1318} 1319''') 1320 code.write(path, "%s_Transitions.cc" % self.ident) 1321 1322 def printProfileDumperHH(self, path): 1323 code = self.symtab.codeFormatter() 1324 ident = self.ident 1325 1326 code(''' 1327// Auto generated C++ code started by $__file__:$__line__ 1328// ${ident}: ${{self.short}} 1329 1330#ifndef __${ident}_PROFILE_DUMPER_HH__ 1331#define __${ident}_PROFILE_DUMPER_HH__ 1332 1333#include <cassert> 1334#include <iostream> 1335#include <vector> 1336 1337#include "${ident}_Event.hh" 1338#include "${ident}_Profiler.hh" 1339 1340typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1341 1342class ${ident}_ProfileDumper 1343{ 1344 public: 1345 ${ident}_ProfileDumper(); 1346 void registerProfiler(${ident}_Profiler* profiler); 1347 void dumpStats(std::ostream& out) const; 1348 1349 private: 1350 ${ident}_profilers m_profilers; 1351}; 1352 1353#endif // __${ident}_PROFILE_DUMPER_HH__ 1354''') 1355 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1356 1357 def printProfileDumperCC(self, path): 1358 code = self.symtab.codeFormatter() 1359 ident = self.ident 1360 1361 code(''' 1362// Auto generated C++ code started by $__file__:$__line__ 1363// ${ident}: ${{self.short}} 1364 1365#include "mem/protocol/${ident}_ProfileDumper.hh" 1366 1367${ident}_ProfileDumper::${ident}_ProfileDumper() 1368{ 1369} 1370 1371void 1372${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1373{ 1374 m_profilers.push_back(profiler); 1375} 1376 1377void 1378${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1379{ 1380 out << " --- ${ident} ---\\n"; 1381 out << " - Event Counts -\\n"; 1382 for (${ident}_Event event = ${ident}_Event_FIRST; 1383 event < ${ident}_Event_NUM; 1384 ++event) { 1385 out << (${ident}_Event) event << " ["; 1386 uint64 total = 0; 1387 for (int i = 0; i < m_profilers.size(); i++) { 1388 out << m_profilers[i]->getEventCount(event) << " "; 1389 total += m_profilers[i]->getEventCount(event); 1390 } 1391 out << "] " << total << "\\n"; 1392 } 1393 out << "\\n"; 1394 out << " - Transitions -\\n"; 1395 for (${ident}_State state = ${ident}_State_FIRST; 1396 state < ${ident}_State_NUM; 1397 ++state) { 1398 for (${ident}_Event event = ${ident}_Event_FIRST; 1399 event < ${ident}_Event_NUM; 1400 ++event) { 1401 if (m_profilers[0]->isPossible(state, event)) { 1402 out << (${ident}_State) state << " " 1403 << (${ident}_Event) event << " ["; 1404 uint64 total = 0; 1405 for (int i = 0; i < m_profilers.size(); i++) { 1406 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1407 total += m_profilers[i]->getTransitionCount(state, event); 1408 } 1409 out << "] " << total << "\\n"; 1410 } 1411 } 1412 out << "\\n"; 1413 } 1414} 1415''') 1416 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1417 1418 def printProfilerHH(self, path): 1419 code = self.symtab.codeFormatter() 1420 ident = self.ident 1421 1422 code(''' 1423// Auto generated C++ code started by $__file__:$__line__ 1424// ${ident}: ${{self.short}} 1425 1426#ifndef __${ident}_PROFILER_HH__ 1427#define __${ident}_PROFILER_HH__ 1428 1429#include <cassert> 1430#include <iostream> 1431 1432#include "mem/protocol/${ident}_Event.hh" 1433#include "mem/protocol/${ident}_State.hh" 1434#include "mem/ruby/common/TypeDefines.hh" 1435 1436class ${ident}_Profiler 1437{ 1438 public: 1439 ${ident}_Profiler(); 1440 void setVersion(int version); 1441 void countTransition(${ident}_State state, ${ident}_Event event); 1442 void possibleTransition(${ident}_State state, ${ident}_Event event); 1443 uint64 getEventCount(${ident}_Event event); 1444 bool isPossible(${ident}_State state, ${ident}_Event event); 1445 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1446 void clearStats(); 1447 1448 private: 1449 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1450 int m_event_counters[${ident}_Event_NUM]; 1451 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1452 int m_version; 1453}; 1454 1455#endif // __${ident}_PROFILER_HH__ 1456''') 1457 code.write(path, "%s_Profiler.hh" % self.ident) 1458 1459 def printProfilerCC(self, path): 1460 code = self.symtab.codeFormatter() 1461 ident = self.ident 1462 1463 code(''' 1464// Auto generated C++ code started by $__file__:$__line__ 1465// ${ident}: ${{self.short}} 1466 1467#include <cassert> 1468 1469#include "mem/protocol/${ident}_Profiler.hh" 1470 1471${ident}_Profiler::${ident}_Profiler() 1472{ 1473 for (int state = 0; state < ${ident}_State_NUM; state++) { 1474 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1475 m_possible[state][event] = false; 1476 m_counters[state][event] = 0; 1477 } 1478 } 1479 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1480 m_event_counters[event] = 0; 1481 } 1482} 1483 1484void 1485${ident}_Profiler::setVersion(int version) 1486{ 1487 m_version = version; 1488} 1489 1490void 1491${ident}_Profiler::clearStats() 1492{ 1493 for (int state = 0; state < ${ident}_State_NUM; state++) { 1494 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1495 m_counters[state][event] = 0; 1496 } 1497 } 1498 1499 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1500 m_event_counters[event] = 0; 1501 } 1502} 1503void 1504${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1505{ 1506 assert(m_possible[state][event]); 1507 m_counters[state][event]++; 1508 m_event_counters[event]++; 1509} 1510void 1511${ident}_Profiler::possibleTransition(${ident}_State state, 1512 ${ident}_Event event) 1513{ 1514 m_possible[state][event] = true; 1515} 1516 1517uint64 1518${ident}_Profiler::getEventCount(${ident}_Event event) 1519{ 1520 return m_event_counters[event]; 1521} 1522 1523bool 1524${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1525{ 1526 return m_possible[state][event]; 1527} 1528 1529uint64 1530${ident}_Profiler::getTransitionCount(${ident}_State state, 1531 ${ident}_Event event) 1532{ 1533 return m_counters[state][event]; 1534} 1535 1536''') 1537 code.write(path, "%s_Profiler.cc" % self.ident) 1538 1539 # ************************** 1540 # ******* HTML Files ******* 1541 # ************************** 1542 def frameRef(self, click_href, click_target, over_href, over_num, text): 1543 code = self.symtab.codeFormatter(fix_newlines=False) 1544 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1545 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1546 parent.frames[$over_num].location='$over_href' 1547 }\"> 1548 ${{html.formatShorthand(text)}} 1549 </A>""") 1550 return str(code) 1551 1552 def writeHTMLFiles(self, path): 1553 # Create table with no row hilighted 1554 self.printHTMLTransitions(path, None) 1555 1556 # Generate transition tables 1557 for state in self.states.itervalues(): 1558 self.printHTMLTransitions(path, state) 1559 1560 # Generate action descriptions 1561 for action in self.actions.itervalues(): 1562 name = "%s_action_%s.html" % (self.ident, action.ident) 1563 code = html.createSymbol(action, "Action") 1564 code.write(path, name) 1565 1566 # Generate state descriptions 1567 for state in self.states.itervalues(): 1568 name = "%s_State_%s.html" % (self.ident, state.ident) 1569 code = html.createSymbol(state, "State") 1570 code.write(path, name) 1571 1572 # Generate event descriptions 1573 for event in self.events.itervalues(): 1574 name = "%s_Event_%s.html" % (self.ident, event.ident) 1575 code = html.createSymbol(event, "Event") 1576 code.write(path, name) 1577 1578 def printHTMLTransitions(self, path, active_state): 1579 code = self.symtab.codeFormatter() 1580 1581 code(''' 1582<HTML> 1583<BODY link="blue" vlink="blue"> 1584 1585<H1 align="center">${{html.formatShorthand(self.short)}}: 1586''') 1587 code.indent() 1588 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1589 mid = machine.ident 1590 if i != 0: 1591 extra = " - " 1592 else: 1593 extra = "" 1594 if machine == self: 1595 code('$extra$mid') 1596 else: 1597 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1598 code.dedent() 1599 1600 code(""" 1601</H1> 1602 1603<TABLE border=1> 1604<TR> 1605 <TH> </TH> 1606""") 1607 1608 for event in self.events.itervalues(): 1609 href = "%s_Event_%s.html" % (self.ident, event.ident) 1610 ref = self.frameRef(href, "Status", href, "1", event.short) 1611 code('<TH bgcolor=white>$ref</TH>') 1612 1613 code('</TR>') 1614 # -- Body of table 1615 for state in self.states.itervalues(): 1616 # -- Each row 1617 if state == active_state: 1618 color = "yellow" 1619 else: 1620 color = "white" 1621 1622 click = "%s_table_%s.html" % (self.ident, state.ident) 1623 over = "%s_State_%s.html" % (self.ident, state.ident) 1624 text = html.formatShorthand(state.short) 1625 ref = self.frameRef(click, "Table", over, "1", state.short) 1626 code(''' 1627<TR> 1628 <TH bgcolor=$color>$ref</TH> 1629''') 1630 1631 # -- One column for each event 1632 for event in self.events.itervalues(): 1633 trans = self.table.get((state,event), None) 1634 if trans is None: 1635 # This is the no transition case 1636 if state == active_state: 1637 color = "#C0C000" 1638 else: 1639 color = "lightgrey" 1640 1641 code('<TD bgcolor=$color> </TD>') 1642 continue 1643 1644 next = trans.nextState 1645 stall_action = False 1646 1647 # -- Get the actions 1648 for action in trans.actions: 1649 if action.ident == "z_stall" or \ 1650 action.ident == "zz_recycleMandatoryQueue": 1651 stall_action = True 1652 1653 # -- Print out "actions/next-state" 1654 if stall_action: 1655 if state == active_state: 1656 color = "#C0C000" 1657 else: 1658 color = "lightgrey" 1659 1660 elif active_state and next.ident == active_state.ident: 1661 color = "aqua" 1662 elif state == active_state: 1663 color = "yellow" 1664 else: 1665 color = "white" 1666 1667 code('<TD bgcolor=$color>') 1668 for action in trans.actions: 1669 href = "%s_action_%s.html" % (self.ident, action.ident) 1670 ref = self.frameRef(href, "Status", href, "1", 1671 action.short) 1672 code(' $ref') 1673 if next != state: 1674 if trans.actions: 1675 code('/') 1676 click = "%s_table_%s.html" % (self.ident, next.ident) 1677 over = "%s_State_%s.html" % (self.ident, next.ident) 1678 ref = self.frameRef(click, "Table", over, "1", next.short) 1679 code("$ref") 1680 code("</TD>") 1681 1682 # -- Each row 1683 if state == active_state: 1684 color = "yellow" 1685 else: 1686 color = "white" 1687 1688 click = "%s_table_%s.html" % (self.ident, state.ident) 1689 over = "%s_State_%s.html" % (self.ident, state.ident) 1690 ref = self.frameRef(click, "Table", over, "1", state.short) 1691 code(''' 1692 <TH bgcolor=$color>$ref</TH> 1693</TR> 1694''') 1695 code(''' 1696<!- Column footer-> 1697<TR> 1698 <TH> </TH> 1699''') 1700 1701 for event in self.events.itervalues(): 1702 href = "%s_Event_%s.html" % (self.ident, event.ident) 1703 ref = self.frameRef(href, "Status", href, "1", event.short) 1704 code('<TH bgcolor=white>$ref</TH>') 1705 code(''' 1706</TR> 1707</TABLE> 1708</BODY></HTML> 1709''') 1710 1711 1712 if active_state: 1713 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1714 else: 1715 name = "%s_table.html" % self.ident 1716 code.write(path, name) 1717 1718__all__ = [ "StateMachine" ] 1719