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