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