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