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