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