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