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