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