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 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path):
| 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 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path):
|
339 340 // Objects 341 s_profiler.setVersion(m_version); 342''') 343 344 code.indent() 345 for var in self.objects: 346 vtype = var.type 347 vid = "m_%s_ptr" % var.c_ident 348 if "network" not in var: 349 # Not a network port object 350 if "primitive" in vtype: 351 code('$vid = new ${{vtype.c_ident}};') 352 if "default" in var: 353 code('(*$vid) = ${{var["default"]}};') 354 else: 355 # Normal Object 356 # added by SS 357 if "factory" in var: 358 code('$vid = ${{var["factory"]}};') 359 elif var.ident.find("mandatoryQueue") < 0: 360 th = var.get("template_hack", "") 361 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 362 363 args = "" 364 if "non_obj" not in vtype and not vtype.isEnumeration: 365 if expr.find("TBETable") >= 0: 366 args = "m_number_of_TBEs" 367 else: 368 args = var.get("constructor_hack", "") 369 args = "(%s)" % args 370 371 code('$expr$args;') 372 else: 373 code(';') 374 375 code('assert($vid != NULL);') 376 377 if "default" in var: 378 code('(*$vid) = ${{var["default"]}}; // Object default') 379 elif "default" in vtype: 380 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 381 382 # Set ordering 383 if "ordered" in var and "trigger_queue" not in var: 384 # A buffer 385 code('$vid->setOrdering(${{var["ordered"]}});') 386 387 # Set randomization 388 if "random" in var: 389 # A buffer 390 code('$vid->setRandomization(${{var["random"]}});') 391 392 # Set Priority 393 if vtype.isBuffer and \ 394 "rank" in var and "trigger_queue" not in var: 395 code('$vid->setPriority(${{var["rank"]}});') 396 else: 397 # Network port object 398 network = var["network"] 399 ordered = var["ordered"] 400 vnet = var["virtual_network"] 401 402 assert var.machine is not None 403 code(''' 404$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 405''') 406 407 code('assert($vid != NULL);') 408 409 # Set ordering 410 if "ordered" in var: 411 # A buffer 412 code('$vid->setOrdering(${{var["ordered"]}});') 413 414 # Set randomization 415 if "random" in var: 416 # A buffer 417 code('$vid->setRandomization(${{var["random"]}})') 418 419 # Set Priority 420 if "rank" in var: 421 code('$vid->setPriority(${{var["rank"]}})') 422 423 # Set buffer size 424 if vtype.isBuffer: 425 code(''' 426if (m_buffer_size > 0) { 427 $vid->setSize(m_buffer_size); 428} 429''') 430 431 # set description (may be overriden later by port def) 432 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 433 434 # Set the queue consumers 435 code.insert_newline() 436 for port in self.in_ports: 437 code('${{port.code}}.setConsumer(this);') 438 439 # Set the queue descriptions 440 code.insert_newline() 441 for port in self.in_ports: 442 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 443 444 # Initialize the transition profiling 445 code.insert_newline() 446 for trans in self.transitions: 447 # Figure out if we stall 448 stall = False 449 for action in trans.actions: 450 if action.ident == "z_stall": 451 stall = True 452 453 # Only possible if it is not a 'z' case 454 if not stall: 455 state = "%s_State_%s" % (self.ident, trans.state.ident) 456 event = "%s_Event_%s" % (self.ident, trans.event.ident) 457 code('s_profiler.possibleTransition($state, $event);') 458 459 # added by SS to initialize recycle_latency of message buffers 460 for buf in self.message_buffer_names: 461 code("$buf->setRecycleLatency(m_recycle_latency);") 462 463 code.dedent() 464 code('}') 465 466 has_mandatory_q = False 467 for port in self.in_ports: 468 if port.code.find("mandatoryQueue_ptr") >= 0: 469 has_mandatory_q = True 470 471 if has_mandatory_q: 472 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 473 else: 474 mq_ident = "NULL" 475 476 code(''' 477int $c_ident::getNumControllers() { 478 return m_num_controllers; 479} 480 481MessageBuffer* $c_ident::getMandatoryQueue() const { 482 return $mq_ident; 483} 484 485const int & $c_ident::getVersion() const{ 486 return m_version; 487} 488 489const string $c_ident::toString() const{ 490 return "$c_ident"; 491} 492 493const string $c_ident::getName() const{ 494 return m_name; 495} 496const MachineType $c_ident::getMachineType() const{ 497 return MachineType_${ident}; 498} 499 500void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) { 501 m_is_blocking = true; 502 m_block_map[addr] = port; 503} 504void $c_ident::unblock(Address addr) { 505 m_block_map.erase(addr); 506 if (m_block_map.size() == 0) { 507 m_is_blocking = false; 508 } 509} 510 511void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 512 513void $c_ident::printConfig(ostream& out) const { 514 out << "$c_ident config: " << m_name << endl; 515 out << " version: " << m_version << endl; 516 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 517 out << " " << (*it).first << ": " << (*it).second << endl; 518 } 519} 520 521// Actions 522''') 523 524 for action in self.actions.itervalues(): 525 if "c_code" not in action: 526 continue 527 528 code(''' 529/** \\brief ${{action.desc}} */ 530void $c_ident::${{action.ident}}(const Address& addr) 531{ 532 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 533 ${{action["c_code"]}} 534} 535 536''') 537 code.write(path, "%s.cc" % c_ident) 538 539 def printCWakeup(self, path): 540 '''Output the wakeup loop for the events''' 541 542 code = code_formatter() 543 ident = self.ident 544 545 code(''' 546// Auto generated C++ code started by $__file__:$__line__ 547// ${ident}: ${{self.short}} 548 549#include "mem/ruby/common/Global.hh" 550#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 551#include "mem/protocol/${ident}_Controller.hh" 552#include "mem/protocol/${ident}_State.hh" 553#include "mem/protocol/${ident}_Event.hh" 554#include "mem/protocol/Types.hh" 555#include "mem/ruby/system/System.hh" 556 557void ${ident}_Controller::wakeup() 558{ 559 560 int counter = 0; 561 while (true) { 562 // Some cases will put us into an infinite loop without this limit 563 assert(counter <= m_transitions_per_cycle); 564 if (counter == m_transitions_per_cycle) { 565 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 566 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 567 break; 568 } 569''') 570 571 code.indent() 572 code.indent() 573 574 # InPorts 575 # 576 for port in self.in_ports: 577 code.indent() 578 code('// ${ident}InPort $port') 579 code('${{port["c_code_in_port"]}}') 580 code.dedent() 581 582 code('') 583 584 code.dedent() 585 code.dedent() 586 code(''' 587 break; // If we got this far, we have nothing left todo 588 } 589} 590''') 591 592 code.write(path, "%s_Wakeup.cc" % self.ident) 593 594 def printCSwitch(self, path): 595 '''Output switch statement for transition table''' 596 597 code = code_formatter() 598 ident = self.ident 599 600 code(''' 601// Auto generated C++ code started by $__file__:$__line__ 602// ${ident}: ${{self.short}} 603 604#include "mem/ruby/common/Global.hh" 605#include "mem/protocol/${ident}_Controller.hh" 606#include "mem/protocol/${ident}_State.hh" 607#include "mem/protocol/${ident}_Event.hh" 608#include "mem/protocol/Types.hh" 609#include "mem/ruby/system/System.hh" 610 611#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 612 613#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 614#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 615 616TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 617) 618{ 619 ${ident}_State next_state = state; 620 621 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 622 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 623 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 624 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 625 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 626 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 627 628 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 629 630 if (result == TransitionResult_Valid) { 631 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 632 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 633 s_profiler.countTransition(state, event); 634 if (Debug::getProtocolTrace()) { 635 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 636 ${ident}_State_to_string(state), 637 ${ident}_Event_to_string(event), 638 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 639 } 640 CLEAR_TRANSITION_COMMENT(); 641 ${ident}_setState(addr, next_state); 642 643 } else if (result == TransitionResult_ResourceStall) { 644 if (Debug::getProtocolTrace()) { 645 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 646 ${ident}_State_to_string(state), 647 ${ident}_Event_to_string(event), 648 ${ident}_State_to_string(next_state), 649 "Resource Stall"); 650 } 651 } else if (result == TransitionResult_ProtocolStall) { 652 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 653 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 654 if (Debug::getProtocolTrace()) { 655 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 656 ${ident}_State_to_string(state), 657 ${ident}_Event_to_string(event), 658 ${ident}_State_to_string(next_state), 659 "Protocol Stall"); 660 } 661 } 662 663 return result; 664} 665 666TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 667) 668{ 669 switch(HASH_FUN(state, event)) { 670''') 671 672 # This map will allow suppress generating duplicate code 673 cases = orderdict() 674 675 for trans in self.transitions: 676 case_string = "%s_State_%s, %s_Event_%s" % \ 677 (self.ident, trans.state.ident, self.ident, trans.event.ident) 678 679 case = code_formatter() 680 # Only set next_state if it changes 681 if trans.state != trans.nextState: 682 ns_ident = trans.nextState.ident 683 case('next_state = ${ident}_State_${ns_ident};') 684 685 actions = trans.actions 686 687 # Check for resources 688 case_sorter = [] 689 res = trans.resources 690 for key,val in res.iteritems(): 691 if key.type.ident != "DNUCAStopTable": 692 val = ''' 693if (!%s.areNSlotsAvailable(%s)) { 694 return TransitionResult_ResourceStall; 695} 696''' % (key.code, val) 697 case_sorter.append(val) 698 699 700 # Emit the code sequences in a sorted order. This makes the 701 # output deterministic (without this the output order can vary 702 # since Map's keys() on a vector of pointers is not deterministic 703 for c in sorted(case_sorter): 704 case("$c") 705 706 # Figure out if we stall 707 stall = False 708 for action in actions: 709 if action.ident == "z_stall": 710 stall = True 711 break 712 713 if stall: 714 case('return TransitionResult_ProtocolStall;') 715 else: 716 for action in actions: 717 case('${{action.ident}}(addr);') 718 case('return TransitionResult_Valid;') 719 720 case = str(case) 721 722 # Look to see if this transition code is unique. 723 if case not in cases: 724 cases[case] = [] 725 726 cases[case].append(case_string) 727 728 # Walk through all of the unique code blocks and spit out the 729 # corresponding case statement elements 730 for case,transitions in cases.iteritems(): 731 # Iterative over all the multiple transitions that share 732 # the same code 733 for trans in transitions: 734 code(' case HASH_FUN($trans):') 735 code(' {') 736 code(' $case') 737 code(' }') 738 739 code(''' 740 default: 741 WARN_EXPR(m_version); 742 WARN_EXPR(g_eventQueue_ptr->getTime()); 743 WARN_EXPR(addr); 744 WARN_EXPR(event); 745 WARN_EXPR(state); 746 ERROR_MSG(\"Invalid transition\"); 747 } 748 return TransitionResult_Valid; 749} 750''') 751 code.write(path, "%s_Transitions.cc" % self.ident) 752 753 def printProfilerHH(self, path): 754 code = code_formatter() 755 ident = self.ident 756 757 code(''' 758// Auto generated C++ code started by $__file__:$__line__ 759// ${ident}: ${{self.short}} 760 761#ifndef ${ident}_PROFILER_H 762#define ${ident}_PROFILER_H 763 764#include "mem/ruby/common/Global.hh" 765#include "mem/protocol/${ident}_State.hh" 766#include "mem/protocol/${ident}_Event.hh" 767 768class ${ident}_Profiler { 769 public: 770 ${ident}_Profiler(); 771 void setVersion(int version); 772 void countTransition(${ident}_State state, ${ident}_Event event); 773 void possibleTransition(${ident}_State state, ${ident}_Event event); 774 void dumpStats(ostream& out) const; 775 void clearStats(); 776 777 private: 778 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 779 int m_event_counters[${ident}_Event_NUM]; 780 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 781 int m_version; 782}; 783 784#endif // ${ident}_PROFILER_H 785''') 786 code.write(path, "%s_Profiler.hh" % self.ident) 787 788 def printProfilerCC(self, path): 789 code = code_formatter() 790 ident = self.ident 791 792 code(''' 793// Auto generated C++ code started by $__file__:$__line__ 794// ${ident}: ${{self.short}} 795 796#include "mem/protocol/${ident}_Profiler.hh" 797 798${ident}_Profiler::${ident}_Profiler() 799{ 800 for (int state = 0; state < ${ident}_State_NUM; state++) { 801 for (int event = 0; event < ${ident}_Event_NUM; event++) { 802 m_possible[state][event] = false; 803 m_counters[state][event] = 0; 804 } 805 } 806 for (int event = 0; event < ${ident}_Event_NUM; event++) { 807 m_event_counters[event] = 0; 808 } 809} 810void ${ident}_Profiler::setVersion(int version) 811{ 812 m_version = version; 813} 814void ${ident}_Profiler::clearStats() 815{ 816 for (int state = 0; state < ${ident}_State_NUM; state++) { 817 for (int event = 0; event < ${ident}_Event_NUM; event++) { 818 m_counters[state][event] = 0; 819 } 820 } 821 822 for (int event = 0; event < ${ident}_Event_NUM; event++) { 823 m_event_counters[event] = 0; 824 } 825} 826void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 827{ 828 assert(m_possible[state][event]); 829 m_counters[state][event]++; 830 m_event_counters[event]++; 831} 832void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 833{ 834 m_possible[state][event] = true; 835} 836void ${ident}_Profiler::dumpStats(ostream& out) const 837{ 838 out << " --- ${ident} " << m_version << " ---" << endl; 839 out << " - Event Counts -" << endl; 840 for (int event = 0; event < ${ident}_Event_NUM; event++) { 841 int count = m_event_counters[event]; 842 out << (${ident}_Event) event << " " << count << endl; 843 } 844 out << endl; 845 out << " - Transitions -" << endl; 846 for (int state = 0; state < ${ident}_State_NUM; state++) { 847 for (int event = 0; event < ${ident}_Event_NUM; event++) { 848 if (m_possible[state][event]) { 849 int count = m_counters[state][event]; 850 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 851 if (count == 0) { 852 out << " <-- "; 853 } 854 out << endl; 855 } 856 } 857 out << endl; 858 } 859} 860''') 861 code.write(path, "%s_Profiler.cc" % self.ident) 862 863 # ************************** 864 # ******* HTML Files ******* 865 # ************************** 866 def frameRef(self, click_href, click_target, over_href, over_target_num, 867 text): 868 code = code_formatter(fix_newlines=False) 869 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>""") 870 return str(code) 871 872 def writeHTMLFiles(self, path): 873 # Create table with no row hilighted 874 self.printHTMLTransitions(path, None) 875 876 # Generate transition tables 877 for state in self.states.itervalues(): 878 self.printHTMLTransitions(path, state) 879 880 # Generate action descriptions 881 for action in self.actions.itervalues(): 882 name = "%s_action_%s.html" % (self.ident, action.ident) 883 code = html.createSymbol(action, "Action") 884 code.write(path, name) 885 886 # Generate state descriptions 887 for state in self.states.itervalues(): 888 name = "%s_State_%s.html" % (self.ident, state.ident) 889 code = html.createSymbol(state, "State") 890 code.write(path, name) 891 892 # Generate event descriptions 893 for event in self.events.itervalues(): 894 name = "%s_Event_%s.html" % (self.ident, event.ident) 895 code = html.createSymbol(event, "Event") 896 code.write(path, name) 897 898 def printHTMLTransitions(self, path, active_state): 899 code = code_formatter() 900 901 code(''' 902<HTML><BODY link="blue" vlink="blue"> 903 904<H1 align="center">${{html.formatShorthand(self.short)}}: 905''') 906 code.indent() 907 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 908 mid = machine.ident 909 if i != 0: 910 extra = " - " 911 else: 912 extra = "" 913 if machine == self: 914 code('$extra$mid') 915 else: 916 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 917 code.dedent() 918 919 code(""" 920</H1> 921 922<TABLE border=1> 923<TR> 924 <TH> </TH> 925""") 926 927 for event in self.events.itervalues(): 928 href = "%s_Event_%s.html" % (self.ident, event.ident) 929 ref = self.frameRef(href, "Status", href, "1", event.short) 930 code('<TH bgcolor=white>$ref</TH>') 931 932 code('</TR>') 933 # -- Body of table 934 for state in self.states.itervalues(): 935 # -- Each row 936 if state == active_state: 937 color = "yellow" 938 else: 939 color = "white" 940 941 click = "%s_table_%s.html" % (self.ident, state.ident) 942 over = "%s_State_%s.html" % (self.ident, state.ident) 943 text = html.formatShorthand(state.short) 944 ref = self.frameRef(click, "Table", over, "1", state.short) 945 code(''' 946<TR> 947 <TH bgcolor=$color>$ref</TH> 948''') 949 950 # -- One column for each event 951 for event in self.events.itervalues(): 952 trans = self.table.get((state,event), None) 953 if trans is None: 954 # This is the no transition case 955 if state == active_state: 956 color = "#C0C000" 957 else: 958 color = "lightgrey" 959 960 code('<TD bgcolor=$color> </TD>') 961 continue 962 963 next = trans.nextState 964 stall_action = False 965 966 # -- Get the actions 967 for action in trans.actions: 968 if action.ident == "z_stall" or \ 969 action.ident == "zz_recycleMandatoryQueue": 970 stall_action = True 971 972 # -- Print out "actions/next-state" 973 if stall_action: 974 if state == active_state: 975 color = "#C0C000" 976 else: 977 color = "lightgrey" 978 979 elif active_state and next.ident == active_state.ident: 980 color = "aqua" 981 elif state == active_state: 982 color = "yellow" 983 else: 984 color = "white" 985 986 fix = code.nofix() 987 code('<TD bgcolor=$color>') 988 for action in trans.actions: 989 href = "%s_action_%s.html" % (self.ident, action.ident) 990 ref = self.frameRef(href, "Status", href, "1", 991 action.short) 992 code(' $ref\n') 993 if next != state: 994 if trans.actions: 995 code('/') 996 click = "%s_table_%s.html" % (self.ident, next.ident) 997 over = "%s_State_%s.html" % (self.ident, next.ident) 998 ref = self.frameRef(click, "Table", over, "1", next.short) 999 code("$ref") 1000 code("</TD>\n") 1001 code.fix(fix) 1002 1003 # -- Each row 1004 if state == active_state: 1005 color = "yellow" 1006 else: 1007 color = "white" 1008 1009 click = "%s_table_%s.html" % (self.ident, state.ident) 1010 over = "%s_State_%s.html" % (self.ident, state.ident) 1011 ref = self.frameRef(click, "Table", over, "1", state.short) 1012 code(''' 1013 <TH bgcolor=$color>$ref</TH> 1014</TR> 1015''') 1016 code(''' 1017<TR> 1018 <TH> </TH> 1019''') 1020 1021 for event in self.events.itervalues(): 1022 href = "%s_Event_%s.html" % (self.ident, event.ident) 1023 ref = self.frameRef(href, "Status", href, "1", event.short) 1024 code('<TH bgcolor=white>$ref</TH>') 1025 code(''' 1026</TR> 1027</TABLE> 1028</BODY></HTML> 1029''') 1030 1031 1032 if active_state: 1033 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1034 else: 1035 name = "%s_table.html" % self.ident 1036 code.write(path, name) 1037 1038__all__ = [ "StateMachine" ]
| 346 347 // Objects 348 s_profiler.setVersion(m_version); 349''') 350 351 code.indent() 352 for var in self.objects: 353 vtype = var.type 354 vid = "m_%s_ptr" % var.c_ident 355 if "network" not in var: 356 # Not a network port object 357 if "primitive" in vtype: 358 code('$vid = new ${{vtype.c_ident}};') 359 if "default" in var: 360 code('(*$vid) = ${{var["default"]}};') 361 else: 362 # Normal Object 363 # added by SS 364 if "factory" in var: 365 code('$vid = ${{var["factory"]}};') 366 elif var.ident.find("mandatoryQueue") < 0: 367 th = var.get("template_hack", "") 368 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 369 370 args = "" 371 if "non_obj" not in vtype and not vtype.isEnumeration: 372 if expr.find("TBETable") >= 0: 373 args = "m_number_of_TBEs" 374 else: 375 args = var.get("constructor_hack", "") 376 args = "(%s)" % args 377 378 code('$expr$args;') 379 else: 380 code(';') 381 382 code('assert($vid != NULL);') 383 384 if "default" in var: 385 code('(*$vid) = ${{var["default"]}}; // Object default') 386 elif "default" in vtype: 387 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 388 389 # Set ordering 390 if "ordered" in var and "trigger_queue" not in var: 391 # A buffer 392 code('$vid->setOrdering(${{var["ordered"]}});') 393 394 # Set randomization 395 if "random" in var: 396 # A buffer 397 code('$vid->setRandomization(${{var["random"]}});') 398 399 # Set Priority 400 if vtype.isBuffer and \ 401 "rank" in var and "trigger_queue" not in var: 402 code('$vid->setPriority(${{var["rank"]}});') 403 else: 404 # Network port object 405 network = var["network"] 406 ordered = var["ordered"] 407 vnet = var["virtual_network"] 408 409 assert var.machine is not None 410 code(''' 411$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 412''') 413 414 code('assert($vid != NULL);') 415 416 # Set ordering 417 if "ordered" in var: 418 # A buffer 419 code('$vid->setOrdering(${{var["ordered"]}});') 420 421 # Set randomization 422 if "random" in var: 423 # A buffer 424 code('$vid->setRandomization(${{var["random"]}})') 425 426 # Set Priority 427 if "rank" in var: 428 code('$vid->setPriority(${{var["rank"]}})') 429 430 # Set buffer size 431 if vtype.isBuffer: 432 code(''' 433if (m_buffer_size > 0) { 434 $vid->setSize(m_buffer_size); 435} 436''') 437 438 # set description (may be overriden later by port def) 439 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 440 441 # Set the queue consumers 442 code.insert_newline() 443 for port in self.in_ports: 444 code('${{port.code}}.setConsumer(this);') 445 446 # Set the queue descriptions 447 code.insert_newline() 448 for port in self.in_ports: 449 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 450 451 # Initialize the transition profiling 452 code.insert_newline() 453 for trans in self.transitions: 454 # Figure out if we stall 455 stall = False 456 for action in trans.actions: 457 if action.ident == "z_stall": 458 stall = True 459 460 # Only possible if it is not a 'z' case 461 if not stall: 462 state = "%s_State_%s" % (self.ident, trans.state.ident) 463 event = "%s_Event_%s" % (self.ident, trans.event.ident) 464 code('s_profiler.possibleTransition($state, $event);') 465 466 # added by SS to initialize recycle_latency of message buffers 467 for buf in self.message_buffer_names: 468 code("$buf->setRecycleLatency(m_recycle_latency);") 469 470 code.dedent() 471 code('}') 472 473 has_mandatory_q = False 474 for port in self.in_ports: 475 if port.code.find("mandatoryQueue_ptr") >= 0: 476 has_mandatory_q = True 477 478 if has_mandatory_q: 479 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 480 else: 481 mq_ident = "NULL" 482 483 code(''' 484int $c_ident::getNumControllers() { 485 return m_num_controllers; 486} 487 488MessageBuffer* $c_ident::getMandatoryQueue() const { 489 return $mq_ident; 490} 491 492const int & $c_ident::getVersion() const{ 493 return m_version; 494} 495 496const string $c_ident::toString() const{ 497 return "$c_ident"; 498} 499 500const string $c_ident::getName() const{ 501 return m_name; 502} 503const MachineType $c_ident::getMachineType() const{ 504 return MachineType_${ident}; 505} 506 507void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) { 508 m_is_blocking = true; 509 m_block_map[addr] = port; 510} 511void $c_ident::unblock(Address addr) { 512 m_block_map.erase(addr); 513 if (m_block_map.size() == 0) { 514 m_is_blocking = false; 515 } 516} 517 518void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 519 520void $c_ident::printConfig(ostream& out) const { 521 out << "$c_ident config: " << m_name << endl; 522 out << " version: " << m_version << endl; 523 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 524 out << " " << (*it).first << ": " << (*it).second << endl; 525 } 526} 527 528// Actions 529''') 530 531 for action in self.actions.itervalues(): 532 if "c_code" not in action: 533 continue 534 535 code(''' 536/** \\brief ${{action.desc}} */ 537void $c_ident::${{action.ident}}(const Address& addr) 538{ 539 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 540 ${{action["c_code"]}} 541} 542 543''') 544 code.write(path, "%s.cc" % c_ident) 545 546 def printCWakeup(self, path): 547 '''Output the wakeup loop for the events''' 548 549 code = code_formatter() 550 ident = self.ident 551 552 code(''' 553// Auto generated C++ code started by $__file__:$__line__ 554// ${ident}: ${{self.short}} 555 556#include "mem/ruby/common/Global.hh" 557#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 558#include "mem/protocol/${ident}_Controller.hh" 559#include "mem/protocol/${ident}_State.hh" 560#include "mem/protocol/${ident}_Event.hh" 561#include "mem/protocol/Types.hh" 562#include "mem/ruby/system/System.hh" 563 564void ${ident}_Controller::wakeup() 565{ 566 567 int counter = 0; 568 while (true) { 569 // Some cases will put us into an infinite loop without this limit 570 assert(counter <= m_transitions_per_cycle); 571 if (counter == m_transitions_per_cycle) { 572 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 573 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 574 break; 575 } 576''') 577 578 code.indent() 579 code.indent() 580 581 # InPorts 582 # 583 for port in self.in_ports: 584 code.indent() 585 code('// ${ident}InPort $port') 586 code('${{port["c_code_in_port"]}}') 587 code.dedent() 588 589 code('') 590 591 code.dedent() 592 code.dedent() 593 code(''' 594 break; // If we got this far, we have nothing left todo 595 } 596} 597''') 598 599 code.write(path, "%s_Wakeup.cc" % self.ident) 600 601 def printCSwitch(self, path): 602 '''Output switch statement for transition table''' 603 604 code = code_formatter() 605 ident = self.ident 606 607 code(''' 608// Auto generated C++ code started by $__file__:$__line__ 609// ${ident}: ${{self.short}} 610 611#include "mem/ruby/common/Global.hh" 612#include "mem/protocol/${ident}_Controller.hh" 613#include "mem/protocol/${ident}_State.hh" 614#include "mem/protocol/${ident}_Event.hh" 615#include "mem/protocol/Types.hh" 616#include "mem/ruby/system/System.hh" 617 618#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 619 620#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 621#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 622 623TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 624) 625{ 626 ${ident}_State next_state = state; 627 628 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 629 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 630 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 631 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 632 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 633 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 634 635 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 636 637 if (result == TransitionResult_Valid) { 638 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 639 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 640 s_profiler.countTransition(state, event); 641 if (Debug::getProtocolTrace()) { 642 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 643 ${ident}_State_to_string(state), 644 ${ident}_Event_to_string(event), 645 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 646 } 647 CLEAR_TRANSITION_COMMENT(); 648 ${ident}_setState(addr, next_state); 649 650 } else if (result == TransitionResult_ResourceStall) { 651 if (Debug::getProtocolTrace()) { 652 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 653 ${ident}_State_to_string(state), 654 ${ident}_Event_to_string(event), 655 ${ident}_State_to_string(next_state), 656 "Resource Stall"); 657 } 658 } else if (result == TransitionResult_ProtocolStall) { 659 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 660 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 661 if (Debug::getProtocolTrace()) { 662 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 663 ${ident}_State_to_string(state), 664 ${ident}_Event_to_string(event), 665 ${ident}_State_to_string(next_state), 666 "Protocol Stall"); 667 } 668 } 669 670 return result; 671} 672 673TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 674) 675{ 676 switch(HASH_FUN(state, event)) { 677''') 678 679 # This map will allow suppress generating duplicate code 680 cases = orderdict() 681 682 for trans in self.transitions: 683 case_string = "%s_State_%s, %s_Event_%s" % \ 684 (self.ident, trans.state.ident, self.ident, trans.event.ident) 685 686 case = code_formatter() 687 # Only set next_state if it changes 688 if trans.state != trans.nextState: 689 ns_ident = trans.nextState.ident 690 case('next_state = ${ident}_State_${ns_ident};') 691 692 actions = trans.actions 693 694 # Check for resources 695 case_sorter = [] 696 res = trans.resources 697 for key,val in res.iteritems(): 698 if key.type.ident != "DNUCAStopTable": 699 val = ''' 700if (!%s.areNSlotsAvailable(%s)) { 701 return TransitionResult_ResourceStall; 702} 703''' % (key.code, val) 704 case_sorter.append(val) 705 706 707 # Emit the code sequences in a sorted order. This makes the 708 # output deterministic (without this the output order can vary 709 # since Map's keys() on a vector of pointers is not deterministic 710 for c in sorted(case_sorter): 711 case("$c") 712 713 # Figure out if we stall 714 stall = False 715 for action in actions: 716 if action.ident == "z_stall": 717 stall = True 718 break 719 720 if stall: 721 case('return TransitionResult_ProtocolStall;') 722 else: 723 for action in actions: 724 case('${{action.ident}}(addr);') 725 case('return TransitionResult_Valid;') 726 727 case = str(case) 728 729 # Look to see if this transition code is unique. 730 if case not in cases: 731 cases[case] = [] 732 733 cases[case].append(case_string) 734 735 # Walk through all of the unique code blocks and spit out the 736 # corresponding case statement elements 737 for case,transitions in cases.iteritems(): 738 # Iterative over all the multiple transitions that share 739 # the same code 740 for trans in transitions: 741 code(' case HASH_FUN($trans):') 742 code(' {') 743 code(' $case') 744 code(' }') 745 746 code(''' 747 default: 748 WARN_EXPR(m_version); 749 WARN_EXPR(g_eventQueue_ptr->getTime()); 750 WARN_EXPR(addr); 751 WARN_EXPR(event); 752 WARN_EXPR(state); 753 ERROR_MSG(\"Invalid transition\"); 754 } 755 return TransitionResult_Valid; 756} 757''') 758 code.write(path, "%s_Transitions.cc" % self.ident) 759 760 def printProfilerHH(self, path): 761 code = code_formatter() 762 ident = self.ident 763 764 code(''' 765// Auto generated C++ code started by $__file__:$__line__ 766// ${ident}: ${{self.short}} 767 768#ifndef ${ident}_PROFILER_H 769#define ${ident}_PROFILER_H 770 771#include "mem/ruby/common/Global.hh" 772#include "mem/protocol/${ident}_State.hh" 773#include "mem/protocol/${ident}_Event.hh" 774 775class ${ident}_Profiler { 776 public: 777 ${ident}_Profiler(); 778 void setVersion(int version); 779 void countTransition(${ident}_State state, ${ident}_Event event); 780 void possibleTransition(${ident}_State state, ${ident}_Event event); 781 void dumpStats(ostream& out) const; 782 void clearStats(); 783 784 private: 785 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 786 int m_event_counters[${ident}_Event_NUM]; 787 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 788 int m_version; 789}; 790 791#endif // ${ident}_PROFILER_H 792''') 793 code.write(path, "%s_Profiler.hh" % self.ident) 794 795 def printProfilerCC(self, path): 796 code = code_formatter() 797 ident = self.ident 798 799 code(''' 800// Auto generated C++ code started by $__file__:$__line__ 801// ${ident}: ${{self.short}} 802 803#include "mem/protocol/${ident}_Profiler.hh" 804 805${ident}_Profiler::${ident}_Profiler() 806{ 807 for (int state = 0; state < ${ident}_State_NUM; state++) { 808 for (int event = 0; event < ${ident}_Event_NUM; event++) { 809 m_possible[state][event] = false; 810 m_counters[state][event] = 0; 811 } 812 } 813 for (int event = 0; event < ${ident}_Event_NUM; event++) { 814 m_event_counters[event] = 0; 815 } 816} 817void ${ident}_Profiler::setVersion(int version) 818{ 819 m_version = version; 820} 821void ${ident}_Profiler::clearStats() 822{ 823 for (int state = 0; state < ${ident}_State_NUM; state++) { 824 for (int event = 0; event < ${ident}_Event_NUM; event++) { 825 m_counters[state][event] = 0; 826 } 827 } 828 829 for (int event = 0; event < ${ident}_Event_NUM; event++) { 830 m_event_counters[event] = 0; 831 } 832} 833void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 834{ 835 assert(m_possible[state][event]); 836 m_counters[state][event]++; 837 m_event_counters[event]++; 838} 839void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 840{ 841 m_possible[state][event] = true; 842} 843void ${ident}_Profiler::dumpStats(ostream& out) const 844{ 845 out << " --- ${ident} " << m_version << " ---" << endl; 846 out << " - Event Counts -" << endl; 847 for (int event = 0; event < ${ident}_Event_NUM; event++) { 848 int count = m_event_counters[event]; 849 out << (${ident}_Event) event << " " << count << endl; 850 } 851 out << endl; 852 out << " - Transitions -" << endl; 853 for (int state = 0; state < ${ident}_State_NUM; state++) { 854 for (int event = 0; event < ${ident}_Event_NUM; event++) { 855 if (m_possible[state][event]) { 856 int count = m_counters[state][event]; 857 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 858 if (count == 0) { 859 out << " <-- "; 860 } 861 out << endl; 862 } 863 } 864 out << endl; 865 } 866} 867''') 868 code.write(path, "%s_Profiler.cc" % self.ident) 869 870 # ************************** 871 # ******* HTML Files ******* 872 # ************************** 873 def frameRef(self, click_href, click_target, over_href, over_target_num, 874 text): 875 code = code_formatter(fix_newlines=False) 876 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>""") 877 return str(code) 878 879 def writeHTMLFiles(self, path): 880 # Create table with no row hilighted 881 self.printHTMLTransitions(path, None) 882 883 # Generate transition tables 884 for state in self.states.itervalues(): 885 self.printHTMLTransitions(path, state) 886 887 # Generate action descriptions 888 for action in self.actions.itervalues(): 889 name = "%s_action_%s.html" % (self.ident, action.ident) 890 code = html.createSymbol(action, "Action") 891 code.write(path, name) 892 893 # Generate state descriptions 894 for state in self.states.itervalues(): 895 name = "%s_State_%s.html" % (self.ident, state.ident) 896 code = html.createSymbol(state, "State") 897 code.write(path, name) 898 899 # Generate event descriptions 900 for event in self.events.itervalues(): 901 name = "%s_Event_%s.html" % (self.ident, event.ident) 902 code = html.createSymbol(event, "Event") 903 code.write(path, name) 904 905 def printHTMLTransitions(self, path, active_state): 906 code = code_formatter() 907 908 code(''' 909<HTML><BODY link="blue" vlink="blue"> 910 911<H1 align="center">${{html.formatShorthand(self.short)}}: 912''') 913 code.indent() 914 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 915 mid = machine.ident 916 if i != 0: 917 extra = " - " 918 else: 919 extra = "" 920 if machine == self: 921 code('$extra$mid') 922 else: 923 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 924 code.dedent() 925 926 code(""" 927</H1> 928 929<TABLE border=1> 930<TR> 931 <TH> </TH> 932""") 933 934 for event in self.events.itervalues(): 935 href = "%s_Event_%s.html" % (self.ident, event.ident) 936 ref = self.frameRef(href, "Status", href, "1", event.short) 937 code('<TH bgcolor=white>$ref</TH>') 938 939 code('</TR>') 940 # -- Body of table 941 for state in self.states.itervalues(): 942 # -- Each row 943 if state == active_state: 944 color = "yellow" 945 else: 946 color = "white" 947 948 click = "%s_table_%s.html" % (self.ident, state.ident) 949 over = "%s_State_%s.html" % (self.ident, state.ident) 950 text = html.formatShorthand(state.short) 951 ref = self.frameRef(click, "Table", over, "1", state.short) 952 code(''' 953<TR> 954 <TH bgcolor=$color>$ref</TH> 955''') 956 957 # -- One column for each event 958 for event in self.events.itervalues(): 959 trans = self.table.get((state,event), None) 960 if trans is None: 961 # This is the no transition case 962 if state == active_state: 963 color = "#C0C000" 964 else: 965 color = "lightgrey" 966 967 code('<TD bgcolor=$color> </TD>') 968 continue 969 970 next = trans.nextState 971 stall_action = False 972 973 # -- Get the actions 974 for action in trans.actions: 975 if action.ident == "z_stall" or \ 976 action.ident == "zz_recycleMandatoryQueue": 977 stall_action = True 978 979 # -- Print out "actions/next-state" 980 if stall_action: 981 if state == active_state: 982 color = "#C0C000" 983 else: 984 color = "lightgrey" 985 986 elif active_state and next.ident == active_state.ident: 987 color = "aqua" 988 elif state == active_state: 989 color = "yellow" 990 else: 991 color = "white" 992 993 fix = code.nofix() 994 code('<TD bgcolor=$color>') 995 for action in trans.actions: 996 href = "%s_action_%s.html" % (self.ident, action.ident) 997 ref = self.frameRef(href, "Status", href, "1", 998 action.short) 999 code(' $ref\n') 1000 if next != state: 1001 if trans.actions: 1002 code('/') 1003 click = "%s_table_%s.html" % (self.ident, next.ident) 1004 over = "%s_State_%s.html" % (self.ident, next.ident) 1005 ref = self.frameRef(click, "Table", over, "1", next.short) 1006 code("$ref") 1007 code("</TD>\n") 1008 code.fix(fix) 1009 1010 # -- Each row 1011 if state == active_state: 1012 color = "yellow" 1013 else: 1014 color = "white" 1015 1016 click = "%s_table_%s.html" % (self.ident, state.ident) 1017 over = "%s_State_%s.html" % (self.ident, state.ident) 1018 ref = self.frameRef(click, "Table", over, "1", state.short) 1019 code(''' 1020 <TH bgcolor=$color>$ref</TH> 1021</TR> 1022''') 1023 code(''' 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 code(''' 1033</TR> 1034</TABLE> 1035</BODY></HTML> 1036''') 1037 1038 1039 if active_state: 1040 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1041 else: 1042 name = "%s_table.html" % self.ident 1043 code.write(path, name) 1044 1045__all__ = [ "StateMachine" ]
|