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 code_formatter, orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33 34python_class_map = {"int": "Int", 35 "string": "String", 36 "bool": "Bool", 37 "CacheMemory": "RubyCache", 38 "Sequencer": "RubySequencer", 39 "DirectoryMemory": "RubyDirectoryMemory", 40 "MemoryControl": "RubyMemoryControl", 41 "DMASequencer": "DMASequencer" 42 } 43 44class StateMachine(Symbol): 45 def __init__(self, symtab, ident, location, pairs, config_parameters): 46 super(StateMachine, self).__init__(symtab, ident, location, pairs) 47 self.table = None 48 self.config_parameters = config_parameters 49 for param in config_parameters: 50 if param.pointer: 51 var = Var(symtab, param.name, location, param.type_ast.type, 52 "(*m_%s_ptr)" % param.name, {}, self) 53 else: 54 var = Var(symtab, param.name, location, param.type_ast.type, 55 "m_%s" % param.name, {}, self) 56 self.symtab.registerSym(param.name, var) 57 58 self.states = orderdict() 59 self.events = orderdict() 60 self.actions = orderdict() 61 self.transitions = [] 62 self.in_ports = [] 63 self.functions = [] 64 self.objects = [] 65 66 self.message_buffer_names = [] 67 68 def __repr__(self): 69 return "[StateMachine: %s]" % self.ident 70 71 def addState(self, state): 72 assert self.table is None 73 self.states[state.ident] = state 74 75 def addEvent(self, event): 76 assert self.table is None 77 self.events[event.ident] = event 78 79 def addAction(self, action): 80 assert self.table is None 81 82 # Check for duplicate action 83 for other in self.actions.itervalues(): 84 if action.ident == other.ident: 85 action.warning("Duplicate action definition: %s" % action.ident) 86 action.error("Duplicate action definition: %s" % action.ident) 87 if action.short == other.short: 88 other.warning("Duplicate action shorthand: %s" % other.ident) 89 other.warning(" shorthand = %s" % other.short) 90 action.warning("Duplicate action shorthand: %s" % action.ident) 91 action.error(" shorthand = %s" % action.short) 92 93 self.actions[action.ident] = action 94 95 def addTransition(self, trans): 96 assert self.table is None 97 self.transitions.append(trans) 98 99 def addInPort(self, var): 100 self.in_ports.append(var) 101 102 def addFunc(self, func): 103 # register func in the symbol table 104 self.symtab.registerSym(str(func), func) 105 self.functions.append(func) 106 107 def addObject(self, obj): 108 self.objects.append(obj) 109 110 # Needs to be called before accessing the table 111 def buildTable(self): 112 assert self.table is None 113 114 table = {} 115 116 for trans in self.transitions: 117 # Track which actions we touch so we know if we use them 118 # all -- really this should be done for all symbols as 119 # part of the symbol table, then only trigger it for 120 # Actions, States, Events, etc. 121 122 for action in trans.actions: 123 action.used = True 124 125 index = (trans.state, trans.event) 126 if index in table: 127 table[index].warning("Duplicate transition: %s" % table[index]) 128 trans.error("Duplicate transition: %s" % trans) 129 table[index] = trans 130 131 # Look at all actions to make sure we used them all 132 for action in self.actions.itervalues(): 133 if not action.used: 134 error_msg = "Unused action: %s" % action.ident 135 if "desc" in action: 136 error_msg += ", " + action.desc 137 action.warning(error_msg) 138 self.table = table 139 140 def writeCodeFiles(self, path): 141 self.printControllerPython(path) 142 self.printControllerHH(path) 143 self.printControllerCC(path) 144 self.printCSwitch(path) 145 self.printCWakeup(path) 146 self.printProfilerCC(path) 147 self.printProfilerHH(path) 148 149 for func in self.functions: 150 func.writeCodeFiles(path) 151 152 def printControllerPython(self, path): 153 code = code_formatter() 154 ident = self.ident 155 py_ident = "%s_Controller" % ident 156 c_ident = "%s_Controller" % self.ident 157 code(''' 158from m5.params import * 159from m5.SimObject import SimObject 160from Controller import RubyController 161 162class $py_ident(RubyController): 163 type = '$py_ident' 164''') 165 code.indent() 166 for param in self.config_parameters: 167 dflt_str = '' 168 if param.default is not None: 169 dflt_str = str(param.default) + ', ' 170 if python_class_map.has_key(param.type_ast.type.c_ident): 171 python_type = python_class_map[param.type_ast.type.c_ident] 172 code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 173 else: 174 self.error("Unknown c++ to python class conversion for c++ " \ 175 "type: '%s'. Please update the python_class_map " \ 176 "in StateMachine.py", param.type_ast.type.c_ident) 177 code.dedent() 178 code.write(path, '%s.py' % py_ident) 179 180 181 def printControllerHH(self, path): 182 '''Output the method declarations for the class declaration''' 183 code = code_formatter() 184 ident = self.ident 185 c_ident = "%s_Controller" % self.ident 186 187 self.message_buffer_names = [] 188 189 code(''' 190/** \\file $ident.hh 191 * 192 * Auto generated C++ code started by $__file__:$__line__ 193 * Created by slicc definition of Module "${{self.short}}" 194 */ 195 196#ifndef ${ident}_CONTROLLER_H 197#define ${ident}_CONTROLLER_H 198 199#include "params/$c_ident.hh" 200 201#include "mem/ruby/common/Global.hh" 202#include "mem/ruby/common/Consumer.hh" 203#include "mem/ruby/slicc_interface/AbstractController.hh" 204#include "mem/protocol/TransitionResult.hh" 205#include "mem/protocol/Types.hh" 206#include "mem/protocol/${ident}_Profiler.hh" 207''') 208 209 seen_types = set() 210 for var in self.objects: 211 if var.type.ident not in seen_types and not var.type.isPrimitive: 212 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 213 seen_types.add(var.type.ident) 214 215 # for adding information to the protocol debug trace 216 code(''' 217extern stringstream ${ident}_transitionComment; 218 219class $c_ident : public AbstractController { 220#ifdef CHECK_COHERENCE 221#endif /* CHECK_COHERENCE */ 222public: 223 typedef ${c_ident}Params Params; 224 $c_ident(const Params *p); 225 static int getNumControllers(); 226 void init(); 227 MessageBuffer* getMandatoryQueue() const; 228 const int & getVersion() const; 229 const string toString() const; 230 const string getName() const; 231 const MachineType getMachineType() const; 232 void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; } 233 void print(ostream& out) const; 234 void printConfig(ostream& out) const; 235 void wakeup();
|
238 void blockOnQueue(Address addr, MessageBuffer* port); 239 void unblock(Address addr); 240private: 241''') 242 243 code.indent() 244 # added by SS 245 for param in self.config_parameters: 246 if param.pointer: 247 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 248 else: 249 code('${{param.type_ast.type}} m_${{param.ident}};') 250 251 code(''' 252int m_number_of_TBEs; 253 254TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc 255TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc 256string m_name; 257int m_transitions_per_cycle; 258int m_buffer_size; 259int m_recycle_latency; 260map< string, string > m_cfg; 261NodeID m_version; 262Network* m_net_ptr; 263MachineID m_machineID; 264bool m_is_blocking; 265map< Address, MessageBuffer* > m_block_map; 266${ident}_Profiler s_profiler; 267static int m_num_controllers; 268// Internal functions 269''') 270 271 for func in self.functions: 272 proto = func.prototype 273 if proto: 274 code('$proto') 275 276 code(''' 277 278// Actions 279''') 280 for action in self.actions.itervalues(): 281 code('/** \\brief ${{action.desc}} */') 282 code('void ${{action.ident}}(const Address& addr);') 283 284 # the controller internal variables 285 code(''' 286 287// Object 288''') 289 for var in self.objects: 290 th = var.get("template_hack", "") 291 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 292 293 if var.type.ident == "MessageBuffer": 294 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 295 296 code.dedent() 297 code('};') 298 code('#endif // ${ident}_CONTROLLER_H') 299 code.write(path, '%s.hh' % c_ident) 300 301 def printControllerCC(self, path): 302 '''Output the actions for performing the actions''' 303 304 code = code_formatter() 305 ident = self.ident 306 c_ident = "%s_Controller" % self.ident 307 308 code(''' 309/** \\file $ident.cc 310 * 311 * Auto generated C++ code started by $__file__:$__line__ 312 * Created by slicc definition of Module "${{self.short}}" 313 */ 314 315#include "mem/ruby/common/Global.hh" 316#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 317#include "mem/protocol/${ident}_Controller.hh" 318#include "mem/protocol/${ident}_State.hh" 319#include "mem/protocol/${ident}_Event.hh" 320#include "mem/protocol/Types.hh" 321#include "mem/ruby/system/System.hh" 322''') 323 324 # include object classes 325 seen_types = set() 326 for var in self.objects: 327 if var.type.ident not in seen_types and not var.type.isPrimitive: 328 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 329 seen_types.add(var.type.ident) 330 331 code(''' 332$c_ident * 333${c_ident}Params::create() 334{ 335 return new $c_ident(this); 336} 337 338 339int $c_ident::m_num_controllers = 0; 340 341stringstream ${ident}_transitionComment; 342#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 343/** \\brief constructor */ 344$c_ident::$c_ident(const Params *p) 345 : AbstractController(p) 346{ 347 m_version = p->version; 348 m_transitions_per_cycle = p->transitions_per_cycle; 349 m_buffer_size = p->buffer_size; 350 m_recycle_latency = p->recycle_latency; 351 m_number_of_TBEs = p->number_of_TBEs; 352''') 353 code.indent() 354 355 # 356 # After initializing the universal machine parameters, initialize the 357 # this machines config parameters. Also detemine if these configuration 358 # params include a sequencer. This information will be used later for 359 # contecting the sequencer back to the L1 cache controller. 360 # 361 contains_sequencer = False 362 for param in self.config_parameters: 363 if param.name == "sequencer" or param.name == "dma_sequencer": 364 contains_sequencer = True 365 if param.pointer: 366 code('m_${{param.name}}_ptr = p->${{param.name}};') 367 else: 368 code('m_${{param.name}} = p->${{param.name}};') 369 370 # 371 # For the l1 cache controller, add the special atomic support which 372 # includes passing the sequencer a pointer to the controller. 373 # 374 if self.ident == "L1Cache": 375 if not contains_sequencer: 376 self.error("The L1Cache controller must include the sequencer " \ 377 "configuration parameter") 378 379 code(''' 380m_sequencer_ptr->setController(this); 381''') 382 # 383 # For the DMA controller, pass the sequencer a pointer to the 384 # controller. 385 # 386 if self.ident == "DMA": 387 if not contains_sequencer: 388 self.error("The DMA controller must include the sequencer " \ 389 "configuration parameter") 390 391 code(''' 392m_dma_sequencer_ptr->setController(this); 393''') 394 395 code('m_num_controllers++;') 396 for var in self.objects: 397 if var.ident.find("mandatoryQueue") >= 0: 398 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 399 400 code.dedent() 401 code(''' 402} 403 404void $c_ident::init() 405{ 406 m_machineID.type = MachineType_${ident}; 407 m_machineID.num = m_version; 408 409 // Objects 410 s_profiler.setVersion(m_version); 411''') 412 413 code.indent() 414 for var in self.objects: 415 vtype = var.type 416 vid = "m_%s_ptr" % var.c_ident 417 if "network" not in var: 418 # Not a network port object 419 if "primitive" in vtype: 420 code('$vid = new ${{vtype.c_ident}};') 421 if "default" in var: 422 code('(*$vid) = ${{var["default"]}};') 423 else: 424 # Normal Object 425 # added by SS 426 if "factory" in var: 427 code('$vid = ${{var["factory"]}};') 428 elif var.ident.find("mandatoryQueue") < 0: 429 th = var.get("template_hack", "") 430 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 431 432 args = "" 433 if "non_obj" not in vtype and not vtype.isEnumeration: 434 if expr.find("TBETable") >= 0: 435 args = "m_number_of_TBEs" 436 else: 437 args = var.get("constructor_hack", "") 438 args = "(%s)" % args 439 440 code('$expr$args;') 441 else: 442 code(';') 443 444 code('assert($vid != NULL);') 445 446 if "default" in var: 447 code('(*$vid) = ${{var["default"]}}; // Object default') 448 elif "default" in vtype: 449 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 450 451 # Set ordering 452 if "ordered" in var and "trigger_queue" not in var: 453 # A buffer 454 code('$vid->setOrdering(${{var["ordered"]}});') 455 456 # Set randomization 457 if "random" in var: 458 # A buffer 459 code('$vid->setRandomization(${{var["random"]}});') 460 461 # Set Priority 462 if vtype.isBuffer and \ 463 "rank" in var and "trigger_queue" not in var: 464 code('$vid->setPriority(${{var["rank"]}});') 465 else: 466 # Network port object 467 network = var["network"] 468 ordered = var["ordered"] 469 vnet = var["virtual_network"] 470 471 assert var.machine is not None 472 code(''' 473$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 474''') 475 476 code('assert($vid != NULL);') 477 478 # Set ordering 479 if "ordered" in var: 480 # A buffer 481 code('$vid->setOrdering(${{var["ordered"]}});') 482 483 # Set randomization 484 if "random" in var: 485 # A buffer 486 code('$vid->setRandomization(${{var["random"]}})') 487 488 # Set Priority 489 if "rank" in var: 490 code('$vid->setPriority(${{var["rank"]}})') 491 492 # Set buffer size 493 if vtype.isBuffer: 494 code(''' 495if (m_buffer_size > 0) { 496 $vid->setSize(m_buffer_size); 497} 498''') 499 500 # set description (may be overriden later by port def) 501 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 502 503 # Set the queue consumers 504 code.insert_newline() 505 for port in self.in_ports: 506 code('${{port.code}}.setConsumer(this);') 507 508 # Set the queue descriptions 509 code.insert_newline() 510 for port in self.in_ports: 511 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 512 513 # Initialize the transition profiling 514 code.insert_newline() 515 for trans in self.transitions: 516 # Figure out if we stall 517 stall = False 518 for action in trans.actions: 519 if action.ident == "z_stall": 520 stall = True 521 522 # Only possible if it is not a 'z' case 523 if not stall: 524 state = "%s_State_%s" % (self.ident, trans.state.ident) 525 event = "%s_Event_%s" % (self.ident, trans.event.ident) 526 code('s_profiler.possibleTransition($state, $event);') 527 528 # added by SS to initialize recycle_latency of message buffers 529 for buf in self.message_buffer_names: 530 code("$buf->setRecycleLatency(m_recycle_latency);") 531 532 code.dedent() 533 code('}') 534 535 has_mandatory_q = False 536 for port in self.in_ports: 537 if port.code.find("mandatoryQueue_ptr") >= 0: 538 has_mandatory_q = True 539 540 if has_mandatory_q: 541 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 542 else: 543 mq_ident = "NULL" 544 545 code(''' 546int $c_ident::getNumControllers() { 547 return m_num_controllers; 548} 549 550MessageBuffer* $c_ident::getMandatoryQueue() const { 551 return $mq_ident; 552} 553 554const int & $c_ident::getVersion() const{ 555 return m_version; 556} 557 558const string $c_ident::toString() const{ 559 return "$c_ident"; 560} 561 562const string $c_ident::getName() const{ 563 return m_name; 564} 565const MachineType $c_ident::getMachineType() const{ 566 return MachineType_${ident}; 567} 568 569void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) { 570 m_is_blocking = true; 571 m_block_map[addr] = port; 572} 573void $c_ident::unblock(Address addr) { 574 m_block_map.erase(addr); 575 if (m_block_map.size() == 0) { 576 m_is_blocking = false; 577 } 578} 579 580void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 581 582void $c_ident::printConfig(ostream& out) const { 583 out << "$c_ident config: " << m_name << endl; 584 out << " version: " << m_version << endl; 585 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 586 out << " " << (*it).first << ": " << (*it).second << endl; 587 } 588} 589
|
622// Actions 623''') 624 625 for action in self.actions.itervalues(): 626 if "c_code" not in action: 627 continue 628 629 code(''' 630/** \\brief ${{action.desc}} */ 631void $c_ident::${{action.ident}}(const Address& addr) 632{ 633 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 634 ${{action["c_code"]}} 635} 636 637''') 638 code.write(path, "%s.cc" % c_ident) 639 640 def printCWakeup(self, path): 641 '''Output the wakeup loop for the events''' 642 643 code = code_formatter() 644 ident = self.ident 645 646 code(''' 647// Auto generated C++ code started by $__file__:$__line__ 648// ${ident}: ${{self.short}} 649 650#include "mem/ruby/common/Global.hh" 651#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 652#include "mem/protocol/${ident}_Controller.hh" 653#include "mem/protocol/${ident}_State.hh" 654#include "mem/protocol/${ident}_Event.hh" 655#include "mem/protocol/Types.hh" 656#include "mem/ruby/system/System.hh" 657 658void ${ident}_Controller::wakeup() 659{ 660 661 int counter = 0; 662 while (true) { 663 // Some cases will put us into an infinite loop without this limit 664 assert(counter <= m_transitions_per_cycle); 665 if (counter == m_transitions_per_cycle) { 666 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 667 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 668 break; 669 } 670''') 671 672 code.indent() 673 code.indent() 674 675 # InPorts 676 # 677 for port in self.in_ports: 678 code.indent() 679 code('// ${ident}InPort $port') 680 code('${{port["c_code_in_port"]}}') 681 code.dedent() 682 683 code('') 684 685 code.dedent() 686 code.dedent() 687 code(''' 688 break; // If we got this far, we have nothing left todo 689 } 690} 691''') 692 693 code.write(path, "%s_Wakeup.cc" % self.ident) 694 695 def printCSwitch(self, path): 696 '''Output switch statement for transition table''' 697 698 code = code_formatter() 699 ident = self.ident 700 701 code(''' 702// Auto generated C++ code started by $__file__:$__line__ 703// ${ident}: ${{self.short}} 704 705#include "mem/ruby/common/Global.hh" 706#include "mem/protocol/${ident}_Controller.hh" 707#include "mem/protocol/${ident}_State.hh" 708#include "mem/protocol/${ident}_Event.hh" 709#include "mem/protocol/Types.hh" 710#include "mem/ruby/system/System.hh" 711 712#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 713 714#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 715#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 716 717TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 718) 719{ 720 ${ident}_State next_state = state; 721 722 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 723 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 724 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 725 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 726 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 727 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 728 729 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 730 731 if (result == TransitionResult_Valid) { 732 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 733 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 734 s_profiler.countTransition(state, event); 735 if (Debug::getProtocolTrace()) { 736 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 737 ${ident}_State_to_string(state), 738 ${ident}_Event_to_string(event), 739 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 740 } 741 CLEAR_TRANSITION_COMMENT(); 742 ${ident}_setState(addr, next_state); 743 744 } else if (result == TransitionResult_ResourceStall) { 745 if (Debug::getProtocolTrace()) { 746 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 747 ${ident}_State_to_string(state), 748 ${ident}_Event_to_string(event), 749 ${ident}_State_to_string(next_state), 750 "Resource Stall"); 751 } 752 } else if (result == TransitionResult_ProtocolStall) { 753 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 754 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 755 if (Debug::getProtocolTrace()) { 756 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 757 ${ident}_State_to_string(state), 758 ${ident}_Event_to_string(event), 759 ${ident}_State_to_string(next_state), 760 "Protocol Stall"); 761 } 762 } 763 764 return result; 765} 766 767TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 768) 769{ 770 switch(HASH_FUN(state, event)) { 771''') 772 773 # This map will allow suppress generating duplicate code 774 cases = orderdict() 775 776 for trans in self.transitions: 777 case_string = "%s_State_%s, %s_Event_%s" % \ 778 (self.ident, trans.state.ident, self.ident, trans.event.ident) 779 780 case = code_formatter() 781 # Only set next_state if it changes 782 if trans.state != trans.nextState: 783 ns_ident = trans.nextState.ident 784 case('next_state = ${ident}_State_${ns_ident};') 785 786 actions = trans.actions 787 788 # Check for resources 789 case_sorter = [] 790 res = trans.resources 791 for key,val in res.iteritems(): 792 if key.type.ident != "DNUCAStopTable": 793 val = ''' 794if (!%s.areNSlotsAvailable(%s)) { 795 return TransitionResult_ResourceStall; 796} 797''' % (key.code, val) 798 case_sorter.append(val) 799 800 801 # Emit the code sequences in a sorted order. This makes the 802 # output deterministic (without this the output order can vary 803 # since Map's keys() on a vector of pointers is not deterministic 804 for c in sorted(case_sorter): 805 case("$c") 806 807 # Figure out if we stall 808 stall = False 809 for action in actions: 810 if action.ident == "z_stall": 811 stall = True 812 break 813 814 if stall: 815 case('return TransitionResult_ProtocolStall;') 816 else: 817 for action in actions: 818 case('${{action.ident}}(addr);') 819 case('return TransitionResult_Valid;') 820 821 case = str(case) 822 823 # Look to see if this transition code is unique. 824 if case not in cases: 825 cases[case] = [] 826 827 cases[case].append(case_string) 828 829 # Walk through all of the unique code blocks and spit out the 830 # corresponding case statement elements 831 for case,transitions in cases.iteritems(): 832 # Iterative over all the multiple transitions that share 833 # the same code 834 for trans in transitions: 835 code(' case HASH_FUN($trans):') 836 code(' {') 837 code(' $case') 838 code(' }') 839 840 code(''' 841 default: 842 WARN_EXPR(m_version); 843 WARN_EXPR(g_eventQueue_ptr->getTime()); 844 WARN_EXPR(addr); 845 WARN_EXPR(event); 846 WARN_EXPR(state); 847 ERROR_MSG(\"Invalid transition\"); 848 } 849 return TransitionResult_Valid; 850} 851''') 852 code.write(path, "%s_Transitions.cc" % self.ident) 853 854 def printProfilerHH(self, path): 855 code = code_formatter() 856 ident = self.ident 857 858 code(''' 859// Auto generated C++ code started by $__file__:$__line__ 860// ${ident}: ${{self.short}} 861 862#ifndef ${ident}_PROFILER_H 863#define ${ident}_PROFILER_H 864 865#include "mem/ruby/common/Global.hh" 866#include "mem/protocol/${ident}_State.hh" 867#include "mem/protocol/${ident}_Event.hh" 868 869class ${ident}_Profiler { 870 public: 871 ${ident}_Profiler(); 872 void setVersion(int version); 873 void countTransition(${ident}_State state, ${ident}_Event event); 874 void possibleTransition(${ident}_State state, ${ident}_Event event); 875 void dumpStats(ostream& out) const; 876 void clearStats(); 877 878 private: 879 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 880 int m_event_counters[${ident}_Event_NUM]; 881 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 882 int m_version; 883}; 884 885#endif // ${ident}_PROFILER_H 886''') 887 code.write(path, "%s_Profiler.hh" % self.ident) 888 889 def printProfilerCC(self, path): 890 code = code_formatter() 891 ident = self.ident 892 893 code(''' 894// Auto generated C++ code started by $__file__:$__line__ 895// ${ident}: ${{self.short}} 896 897#include "mem/protocol/${ident}_Profiler.hh" 898 899${ident}_Profiler::${ident}_Profiler() 900{ 901 for (int state = 0; state < ${ident}_State_NUM; state++) { 902 for (int event = 0; event < ${ident}_Event_NUM; event++) { 903 m_possible[state][event] = false; 904 m_counters[state][event] = 0; 905 } 906 } 907 for (int event = 0; event < ${ident}_Event_NUM; event++) { 908 m_event_counters[event] = 0; 909 } 910} 911void ${ident}_Profiler::setVersion(int version) 912{ 913 m_version = version; 914} 915void ${ident}_Profiler::clearStats() 916{ 917 for (int state = 0; state < ${ident}_State_NUM; state++) { 918 for (int event = 0; event < ${ident}_Event_NUM; event++) { 919 m_counters[state][event] = 0; 920 } 921 } 922 923 for (int event = 0; event < ${ident}_Event_NUM; event++) { 924 m_event_counters[event] = 0; 925 } 926} 927void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 928{ 929 assert(m_possible[state][event]); 930 m_counters[state][event]++; 931 m_event_counters[event]++; 932} 933void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 934{ 935 m_possible[state][event] = true; 936} 937void ${ident}_Profiler::dumpStats(ostream& out) const 938{ 939 out << " --- ${ident} " << m_version << " ---" << endl; 940 out << " - Event Counts -" << endl; 941 for (int event = 0; event < ${ident}_Event_NUM; event++) { 942 int count = m_event_counters[event]; 943 out << (${ident}_Event) event << " " << count << endl; 944 } 945 out << endl; 946 out << " - Transitions -" << endl; 947 for (int state = 0; state < ${ident}_State_NUM; state++) { 948 for (int event = 0; event < ${ident}_Event_NUM; event++) { 949 if (m_possible[state][event]) { 950 int count = m_counters[state][event]; 951 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 952 if (count == 0) { 953 out << " <-- "; 954 } 955 out << endl; 956 } 957 } 958 out << endl; 959 } 960} 961''') 962 code.write(path, "%s_Profiler.cc" % self.ident) 963 964 # ************************** 965 # ******* HTML Files ******* 966 # ************************** 967 def frameRef(self, click_href, click_target, over_href, over_target_num, 968 text): 969 code = code_formatter(fix_newlines=False) 970 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""") 971 return str(code) 972 973 def writeHTMLFiles(self, path): 974 # Create table with no row hilighted 975 self.printHTMLTransitions(path, None) 976 977 # Generate transition tables 978 for state in self.states.itervalues(): 979 self.printHTMLTransitions(path, state) 980 981 # Generate action descriptions 982 for action in self.actions.itervalues(): 983 name = "%s_action_%s.html" % (self.ident, action.ident) 984 code = html.createSymbol(action, "Action") 985 code.write(path, name) 986 987 # Generate state descriptions 988 for state in self.states.itervalues(): 989 name = "%s_State_%s.html" % (self.ident, state.ident) 990 code = html.createSymbol(state, "State") 991 code.write(path, name) 992 993 # Generate event descriptions 994 for event in self.events.itervalues(): 995 name = "%s_Event_%s.html" % (self.ident, event.ident) 996 code = html.createSymbol(event, "Event") 997 code.write(path, name) 998 999 def printHTMLTransitions(self, path, active_state): 1000 code = code_formatter() 1001 1002 code(''' 1003<HTML><BODY link="blue" vlink="blue"> 1004 1005<H1 align="center">${{html.formatShorthand(self.short)}}: 1006''') 1007 code.indent() 1008 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1009 mid = machine.ident 1010 if i != 0: 1011 extra = " - " 1012 else: 1013 extra = "" 1014 if machine == self: 1015 code('$extra$mid') 1016 else: 1017 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1018 code.dedent() 1019 1020 code(""" 1021</H1> 1022 1023<TABLE border=1> 1024<TR> 1025 <TH> </TH> 1026""") 1027 1028 for event in self.events.itervalues(): 1029 href = "%s_Event_%s.html" % (self.ident, event.ident) 1030 ref = self.frameRef(href, "Status", href, "1", event.short) 1031 code('<TH bgcolor=white>$ref</TH>') 1032 1033 code('</TR>') 1034 # -- Body of table 1035 for state in self.states.itervalues(): 1036 # -- Each row 1037 if state == active_state: 1038 color = "yellow" 1039 else: 1040 color = "white" 1041 1042 click = "%s_table_%s.html" % (self.ident, state.ident) 1043 over = "%s_State_%s.html" % (self.ident, state.ident) 1044 text = html.formatShorthand(state.short) 1045 ref = self.frameRef(click, "Table", over, "1", state.short) 1046 code(''' 1047<TR> 1048 <TH bgcolor=$color>$ref</TH> 1049''') 1050 1051 # -- One column for each event 1052 for event in self.events.itervalues(): 1053 trans = self.table.get((state,event), None) 1054 if trans is None: 1055 # This is the no transition case 1056 if state == active_state: 1057 color = "#C0C000" 1058 else: 1059 color = "lightgrey" 1060 1061 code('<TD bgcolor=$color> </TD>') 1062 continue 1063 1064 next = trans.nextState 1065 stall_action = False 1066 1067 # -- Get the actions 1068 for action in trans.actions: 1069 if action.ident == "z_stall" or \ 1070 action.ident == "zz_recycleMandatoryQueue": 1071 stall_action = True 1072 1073 # -- Print out "actions/next-state" 1074 if stall_action: 1075 if state == active_state: 1076 color = "#C0C000" 1077 else: 1078 color = "lightgrey" 1079 1080 elif active_state and next.ident == active_state.ident: 1081 color = "aqua" 1082 elif state == active_state: 1083 color = "yellow" 1084 else: 1085 color = "white" 1086 1087 fix = code.nofix() 1088 code('<TD bgcolor=$color>') 1089 for action in trans.actions: 1090 href = "%s_action_%s.html" % (self.ident, action.ident) 1091 ref = self.frameRef(href, "Status", href, "1", 1092 action.short) 1093 code(' $ref\n') 1094 if next != state: 1095 if trans.actions: 1096 code('/') 1097 click = "%s_table_%s.html" % (self.ident, next.ident) 1098 over = "%s_State_%s.html" % (self.ident, next.ident) 1099 ref = self.frameRef(click, "Table", over, "1", next.short) 1100 code("$ref") 1101 code("</TD>\n") 1102 code.fix(fix) 1103 1104 # -- Each row 1105 if state == active_state: 1106 color = "yellow" 1107 else: 1108 color = "white" 1109 1110 click = "%s_table_%s.html" % (self.ident, state.ident) 1111 over = "%s_State_%s.html" % (self.ident, state.ident) 1112 ref = self.frameRef(click, "Table", over, "1", state.short) 1113 code(''' 1114 <TH bgcolor=$color>$ref</TH> 1115</TR> 1116''') 1117 code(''' 1118<TR> 1119 <TH> </TH> 1120''') 1121 1122 for event in self.events.itervalues(): 1123 href = "%s_Event_%s.html" % (self.ident, event.ident) 1124 ref = self.frameRef(href, "Status", href, "1", event.short) 1125 code('<TH bgcolor=white>$ref</TH>') 1126 code(''' 1127</TR> 1128</TABLE> 1129</BODY></HTML> 1130''') 1131 1132 1133 if active_state: 1134 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1135 else: 1136 name = "%s_table.html" % self.ident 1137 code.write(path, name) 1138 1139__all__ = [ "StateMachine" ]
|