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