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