StateMachine.py revision 8341:30daf1dd5c91
1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28from m5.util import orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33import re 34 35python_class_map = {"int": "Int", 36 "std::string": "String", 37 "bool": "Bool", 38 "CacheMemory": "RubyCache", 39 "WireBuffer": "RubyWireBuffer", 40 "Sequencer": "RubySequencer", 41 "DirectoryMemory": "RubyDirectoryMemory", 42 "MemoryControl": "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 "mem/protocol/${ident}_ProfileDumper.hh" 226#include "mem/protocol/${ident}_Profiler.hh" 227#include "mem/protocol/TransitionResult.hh" 228#include "mem/protocol/Types.hh" 229#include "mem/ruby/common/Consumer.hh" 230#include "mem/ruby/common/Global.hh" 231#include "mem/ruby/slicc_interface/AbstractController.hh" 232#include "params/$c_ident.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''') 352 353 if self.TBEType != None: 354 code(''' 355 356// Set and Reset for tbe variable 357void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 358void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 359''') 360 361 code(''' 362 363// Actions 364''') 365 if self.TBEType != None and self.EntryType != None: 366 for action in self.actions.itervalues(): 367 code('/** \\brief ${{action.desc}} */') 368 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 369 elif self.TBEType != None: 370 for action in self.actions.itervalues(): 371 code('/** \\brief ${{action.desc}} */') 372 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') 373 elif self.EntryType != None: 374 for action in self.actions.itervalues(): 375 code('/** \\brief ${{action.desc}} */') 376 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') 377 else: 378 for action in self.actions.itervalues(): 379 code('/** \\brief ${{action.desc}} */') 380 code('void ${{action.ident}}(const Address& addr);') 381 382 # the controller internal variables 383 code(''' 384 385// Objects 386''') 387 for var in self.objects: 388 th = var.get("template_hack", "") 389 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 390 391 if var.type.ident == "MessageBuffer": 392 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 393 394 code.dedent() 395 code('};') 396 code('#endif // __${ident}_CONTROLLER_H__') 397 code.write(path, '%s.hh' % c_ident) 398 399 def printControllerCC(self, path): 400 '''Output the actions for performing the actions''' 401 402 code = self.symtab.codeFormatter() 403 ident = self.ident 404 c_ident = "%s_Controller" % self.ident 405 406 code(''' 407/** \\file $c_ident.cc 408 * 409 * Auto generated C++ code started by $__file__:$__line__ 410 * Created by slicc definition of Module "${{self.short}}" 411 */ 412 413#include <cassert> 414#include <sstream> 415#include <string> 416 417#include "base/cprintf.hh" 418#include "debug/RubyGenerated.hh" 419#include "debug/RubySlicc.hh" 420#include "mem/protocol/${ident}_Controller.hh" 421#include "mem/protocol/${ident}_Event.hh" 422#include "mem/protocol/${ident}_State.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 # 477 contains_dma_sequencer = False 478 sequencers = [] 479 for param in self.config_parameters: 480 if param.name == "dma_sequencer": 481 contains_dma_sequencer = True 482 elif re.compile("sequencer").search(param.name): 483 sequencers.append(param.name) 484 if param.pointer: 485 code('m_${{param.name}}_ptr = p->${{param.name}};') 486 else: 487 code('m_${{param.name}} = p->${{param.name}};') 488 489 # 490 # For the l1 cache controller, add the special atomic support which 491 # includes passing the sequencer a pointer to the controller. 492 # 493 if self.ident == "L1Cache": 494 if not sequencers: 495 self.error("The L1Cache controller must include the sequencer " \ 496 "configuration parameter") 497 498 for seq in sequencers: 499 code(''' 500m_${{seq}}_ptr->setController(this); 501 ''') 502 # 503 # For the DMA controller, pass the sequencer a pointer to the 504 # controller. 505 # 506 if self.ident == "DMA": 507 if not contains_dma_sequencer: 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 vnet_type = var["vnet_type"] 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, "$vnet_type"); 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''') 866 867 if self.TBEType != None: 868 code(''' 869 870// Set and Reset for tbe variable 871void 872$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 873{ 874 m_tbe_ptr = m_new_tbe; 875} 876 877void 878$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 879{ 880 m_tbe_ptr = NULL; 881} 882''') 883 884 code(''' 885 886// Actions 887''') 888 if self.TBEType != None and self.EntryType != None: 889 for action in self.actions.itervalues(): 890 if "c_code" not in action: 891 continue 892 893 code(''' 894/** \\brief ${{action.desc}} */ 895void 896$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 897{ 898 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 899 ${{action["c_code"]}} 900} 901 902''') 903 elif self.TBEType != None: 904 for action in self.actions.itervalues(): 905 if "c_code" not in action: 906 continue 907 908 code(''' 909/** \\brief ${{action.desc}} */ 910void 911$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 912{ 913 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 914 ${{action["c_code"]}} 915} 916 917''') 918 elif self.EntryType != None: 919 for action in self.actions.itervalues(): 920 if "c_code" not in action: 921 continue 922 923 code(''' 924/** \\brief ${{action.desc}} */ 925void 926$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 927{ 928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 929 ${{action["c_code"]}} 930} 931 932''') 933 else: 934 for action in self.actions.itervalues(): 935 if "c_code" not in action: 936 continue 937 938 code(''' 939/** \\brief ${{action.desc}} */ 940void 941$c_ident::${{action.ident}}(const Address& addr) 942{ 943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 944 ${{action["c_code"]}} 945} 946 947''') 948 code.write(path, "%s.cc" % c_ident) 949 950 def printCWakeup(self, path): 951 '''Output the wakeup loop for the events''' 952 953 code = self.symtab.codeFormatter() 954 ident = self.ident 955 956 code(''' 957// Auto generated C++ code started by $__file__:$__line__ 958// ${ident}: ${{self.short}} 959 960#include <cassert> 961 962#include "base/misc.hh" 963#include "debug/RubySlicc.hh" 964#include "mem/protocol/${ident}_Controller.hh" 965#include "mem/protocol/${ident}_Event.hh" 966#include "mem/protocol/${ident}_State.hh" 967#include "mem/protocol/Types.hh" 968#include "mem/ruby/common/Global.hh" 969#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 970#include "mem/ruby/system/System.hh" 971 972using namespace std; 973 974void 975${ident}_Controller::wakeup() 976{ 977 int counter = 0; 978 while (true) { 979 // Some cases will put us into an infinite loop without this limit 980 assert(counter <= m_transitions_per_cycle); 981 if (counter == m_transitions_per_cycle) { 982 // Count how often we are fully utilized 983 g_system_ptr->getProfiler()->controllerBusy(m_machineID); 984 985 // Wakeup in another cycle and try again 986 g_eventQueue_ptr->scheduleEvent(this, 1); 987 break; 988 } 989''') 990 991 code.indent() 992 code.indent() 993 994 # InPorts 995 # 996 for port in self.in_ports: 997 code.indent() 998 code('// ${ident}InPort $port') 999 if port.pairs.has_key("rank"): 1000 code('m_cur_in_port_rank = ${{port.pairs["rank"]}};') 1001 else: 1002 code('m_cur_in_port_rank = 0;') 1003 code('${{port["c_code_in_port"]}}') 1004 code.dedent() 1005 1006 code('') 1007 1008 code.dedent() 1009 code.dedent() 1010 code(''' 1011 break; // If we got this far, we have nothing left todo 1012 } 1013 // g_eventQueue_ptr->scheduleEvent(this, 1); 1014} 1015''') 1016 1017 code.write(path, "%s_Wakeup.cc" % self.ident) 1018 1019 def printCSwitch(self, path): 1020 '''Output switch statement for transition table''' 1021 1022 code = self.symtab.codeFormatter() 1023 ident = self.ident 1024 1025 code(''' 1026// Auto generated C++ code started by $__file__:$__line__ 1027// ${ident}: ${{self.short}} 1028 1029#include <cassert> 1030 1031#include "base/misc.hh" 1032#include "base/trace.hh" 1033#include "debug/ProtocolTrace.hh" 1034#include "debug/RubyGenerated.hh" 1035#include "mem/protocol/${ident}_Controller.hh" 1036#include "mem/protocol/${ident}_Event.hh" 1037#include "mem/protocol/${ident}_State.hh" 1038#include "mem/protocol/Types.hh" 1039#include "mem/ruby/common/Global.hh" 1040#include "mem/ruby/system/System.hh" 1041 1042#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1043 1044#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1045#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1046 1047TransitionResult 1048${ident}_Controller::doTransition(${ident}_Event event, 1049''') 1050 if self.EntryType != None: 1051 code(''' 1052 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1053''') 1054 if self.TBEType != None: 1055 code(''' 1056 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1057''') 1058 code(''' 1059 const Address &addr) 1060{ 1061''') 1062 if self.TBEType != None and self.EntryType != None: 1063 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1064 elif self.TBEType != None: 1065 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1066 elif self.EntryType != None: 1067 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1068 else: 1069 code('${ident}_State state = getState(addr);') 1070 1071 code(''' 1072 ${ident}_State next_state = state; 1073 1074 DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1075 *this, 1076 g_eventQueue_ptr->getTime(), 1077 ${ident}_State_to_string(state), 1078 ${ident}_Event_to_string(event), 1079 addr); 1080 1081 TransitionResult result = 1082''') 1083 if self.TBEType != None and self.EntryType != None: 1084 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1085 elif self.TBEType != None: 1086 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1087 elif self.EntryType != None: 1088 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1089 else: 1090 code('doTransitionWorker(event, state, next_state, addr);') 1091 1092 code(''' 1093 if (result == TransitionResult_Valid) { 1094 DPRINTF(RubyGenerated, "next_state: %s\\n", 1095 ${ident}_State_to_string(next_state)); 1096 m_profiler.countTransition(state, event); 1097 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1098 curTick(), m_version, "${ident}", 1099 ${ident}_Event_to_string(event), 1100 ${ident}_State_to_string(state), 1101 ${ident}_State_to_string(next_state), 1102 addr, GET_TRANSITION_COMMENT()); 1103 1104 CLEAR_TRANSITION_COMMENT(); 1105''') 1106 if self.TBEType != None and self.EntryType != None: 1107 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1108 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1109 elif self.TBEType != None: 1110 code('setState(m_tbe_ptr, addr, next_state);') 1111 code('setAccessPermission(addr, next_state);') 1112 elif self.EntryType != None: 1113 code('setState(m_cache_entry_ptr, addr, next_state);') 1114 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1115 else: 1116 code('setState(addr, next_state);') 1117 code('setAccessPermission(addr, next_state);') 1118 1119 code(''' 1120 } else if (result == TransitionResult_ResourceStall) { 1121 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1122 curTick(), m_version, "${ident}", 1123 ${ident}_Event_to_string(event), 1124 ${ident}_State_to_string(state), 1125 ${ident}_State_to_string(next_state), 1126 addr, "Resource Stall"); 1127 } else if (result == TransitionResult_ProtocolStall) { 1128 DPRINTF(RubyGenerated, "stalling\\n"); 1129 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1130 curTick(), m_version, "${ident}", 1131 ${ident}_Event_to_string(event), 1132 ${ident}_State_to_string(state), 1133 ${ident}_State_to_string(next_state), 1134 addr, "Protocol Stall"); 1135 } 1136 1137 return result; 1138} 1139 1140TransitionResult 1141${ident}_Controller::doTransitionWorker(${ident}_Event event, 1142 ${ident}_State state, 1143 ${ident}_State& next_state, 1144''') 1145 1146 if self.TBEType != None: 1147 code(''' 1148 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1149''') 1150 if self.EntryType != None: 1151 code(''' 1152 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1153''') 1154 code(''' 1155 const Address& addr) 1156{ 1157 switch(HASH_FUN(state, event)) { 1158''') 1159 1160 # This map will allow suppress generating duplicate code 1161 cases = orderdict() 1162 1163 for trans in self.transitions: 1164 case_string = "%s_State_%s, %s_Event_%s" % \ 1165 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1166 1167 case = self.symtab.codeFormatter() 1168 # Only set next_state if it changes 1169 if trans.state != trans.nextState: 1170 ns_ident = trans.nextState.ident 1171 case('next_state = ${ident}_State_${ns_ident};') 1172 1173 actions = trans.actions 1174 1175 # Check for resources 1176 case_sorter = [] 1177 res = trans.resources 1178 for key,val in res.iteritems(): 1179 if key.type.ident != "DNUCAStopTable": 1180 val = ''' 1181if (!%s.areNSlotsAvailable(%s)) 1182 return TransitionResult_ResourceStall; 1183''' % (key.code, val) 1184 case_sorter.append(val) 1185 1186 1187 # Emit the code sequences in a sorted order. This makes the 1188 # output deterministic (without this the output order can vary 1189 # since Map's keys() on a vector of pointers is not deterministic 1190 for c in sorted(case_sorter): 1191 case("$c") 1192 1193 # Figure out if we stall 1194 stall = False 1195 for action in actions: 1196 if action.ident == "z_stall": 1197 stall = True 1198 break 1199 1200 if stall: 1201 case('return TransitionResult_ProtocolStall;') 1202 else: 1203 if self.TBEType != None and self.EntryType != None: 1204 for action in actions: 1205 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1206 elif self.TBEType != None: 1207 for action in actions: 1208 case('${{action.ident}}(m_tbe_ptr, addr);') 1209 elif self.EntryType != None: 1210 for action in actions: 1211 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1212 else: 1213 for action in actions: 1214 case('${{action.ident}}(addr);') 1215 case('return TransitionResult_Valid;') 1216 1217 case = str(case) 1218 1219 # Look to see if this transition code is unique. 1220 if case not in cases: 1221 cases[case] = [] 1222 1223 cases[case].append(case_string) 1224 1225 # Walk through all of the unique code blocks and spit out the 1226 # corresponding case statement elements 1227 for case,transitions in cases.iteritems(): 1228 # Iterative over all the multiple transitions that share 1229 # the same code 1230 for trans in transitions: 1231 code(' case HASH_FUN($trans):') 1232 code(' $case') 1233 1234 code(''' 1235 default: 1236 fatal("Invalid transition\\n" 1237 "%s time: %d addr: %s event: %s state: %s\\n", 1238 name(), g_eventQueue_ptr->getTime(), addr, event, state); 1239 } 1240 return TransitionResult_Valid; 1241} 1242''') 1243 code.write(path, "%s_Transitions.cc" % self.ident) 1244 1245 def printProfileDumperHH(self, path): 1246 code = self.symtab.codeFormatter() 1247 ident = self.ident 1248 1249 code(''' 1250// Auto generated C++ code started by $__file__:$__line__ 1251// ${ident}: ${{self.short}} 1252 1253#ifndef __${ident}_PROFILE_DUMPER_HH__ 1254#define __${ident}_PROFILE_DUMPER_HH__ 1255 1256#include <cassert> 1257#include <iostream> 1258#include <vector> 1259 1260#include "${ident}_Event.hh" 1261#include "${ident}_Profiler.hh" 1262 1263typedef std::vector<${ident}_Profiler *> ${ident}_profilers; 1264 1265class ${ident}_ProfileDumper 1266{ 1267 public: 1268 ${ident}_ProfileDumper(); 1269 void registerProfiler(${ident}_Profiler* profiler); 1270 void dumpStats(std::ostream& out) const; 1271 1272 private: 1273 ${ident}_profilers m_profilers; 1274}; 1275 1276#endif // __${ident}_PROFILE_DUMPER_HH__ 1277''') 1278 code.write(path, "%s_ProfileDumper.hh" % self.ident) 1279 1280 def printProfileDumperCC(self, path): 1281 code = self.symtab.codeFormatter() 1282 ident = self.ident 1283 1284 code(''' 1285// Auto generated C++ code started by $__file__:$__line__ 1286// ${ident}: ${{self.short}} 1287 1288#include "mem/protocol/${ident}_ProfileDumper.hh" 1289 1290${ident}_ProfileDumper::${ident}_ProfileDumper() 1291{ 1292} 1293 1294void 1295${ident}_ProfileDumper::registerProfiler(${ident}_Profiler* profiler) 1296{ 1297 m_profilers.push_back(profiler); 1298} 1299 1300void 1301${ident}_ProfileDumper::dumpStats(std::ostream& out) const 1302{ 1303 out << " --- ${ident} ---\\n"; 1304 out << " - Event Counts -\\n"; 1305 for (${ident}_Event event = ${ident}_Event_FIRST; 1306 event < ${ident}_Event_NUM; 1307 ++event) { 1308 out << (${ident}_Event) event << " ["; 1309 uint64 total = 0; 1310 for (int i = 0; i < m_profilers.size(); i++) { 1311 out << m_profilers[i]->getEventCount(event) << " "; 1312 total += m_profilers[i]->getEventCount(event); 1313 } 1314 out << "] " << total << "\\n"; 1315 } 1316 out << "\\n"; 1317 out << " - Transitions -\\n"; 1318 for (${ident}_State state = ${ident}_State_FIRST; 1319 state < ${ident}_State_NUM; 1320 ++state) { 1321 for (${ident}_Event event = ${ident}_Event_FIRST; 1322 event < ${ident}_Event_NUM; 1323 ++event) { 1324 if (m_profilers[0]->isPossible(state, event)) { 1325 out << (${ident}_State) state << " " 1326 << (${ident}_Event) event << " ["; 1327 uint64 total = 0; 1328 for (int i = 0; i < m_profilers.size(); i++) { 1329 out << m_profilers[i]->getTransitionCount(state, event) << " "; 1330 total += m_profilers[i]->getTransitionCount(state, event); 1331 } 1332 out << "] " << total << "\\n"; 1333 } 1334 } 1335 out << "\\n"; 1336 } 1337} 1338''') 1339 code.write(path, "%s_ProfileDumper.cc" % self.ident) 1340 1341 def printProfilerHH(self, path): 1342 code = self.symtab.codeFormatter() 1343 ident = self.ident 1344 1345 code(''' 1346// Auto generated C++ code started by $__file__:$__line__ 1347// ${ident}: ${{self.short}} 1348 1349#ifndef __${ident}_PROFILER_HH__ 1350#define __${ident}_PROFILER_HH__ 1351 1352#include <cassert> 1353#include <iostream> 1354 1355#include "mem/protocol/${ident}_Event.hh" 1356#include "mem/protocol/${ident}_State.hh" 1357#include "mem/ruby/common/Global.hh" 1358 1359class ${ident}_Profiler 1360{ 1361 public: 1362 ${ident}_Profiler(); 1363 void setVersion(int version); 1364 void countTransition(${ident}_State state, ${ident}_Event event); 1365 void possibleTransition(${ident}_State state, ${ident}_Event event); 1366 uint64 getEventCount(${ident}_Event event); 1367 bool isPossible(${ident}_State state, ${ident}_Event event); 1368 uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 1369 void clearStats(); 1370 1371 private: 1372 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 1373 int m_event_counters[${ident}_Event_NUM]; 1374 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 1375 int m_version; 1376}; 1377 1378#endif // __${ident}_PROFILER_HH__ 1379''') 1380 code.write(path, "%s_Profiler.hh" % self.ident) 1381 1382 def printProfilerCC(self, path): 1383 code = self.symtab.codeFormatter() 1384 ident = self.ident 1385 1386 code(''' 1387// Auto generated C++ code started by $__file__:$__line__ 1388// ${ident}: ${{self.short}} 1389 1390#include <cassert> 1391 1392#include "mem/protocol/${ident}_Profiler.hh" 1393 1394${ident}_Profiler::${ident}_Profiler() 1395{ 1396 for (int state = 0; state < ${ident}_State_NUM; state++) { 1397 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1398 m_possible[state][event] = false; 1399 m_counters[state][event] = 0; 1400 } 1401 } 1402 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1403 m_event_counters[event] = 0; 1404 } 1405} 1406 1407void 1408${ident}_Profiler::setVersion(int version) 1409{ 1410 m_version = version; 1411} 1412 1413void 1414${ident}_Profiler::clearStats() 1415{ 1416 for (int state = 0; state < ${ident}_State_NUM; state++) { 1417 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1418 m_counters[state][event] = 0; 1419 } 1420 } 1421 1422 for (int event = 0; event < ${ident}_Event_NUM; event++) { 1423 m_event_counters[event] = 0; 1424 } 1425} 1426void 1427${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 1428{ 1429 assert(m_possible[state][event]); 1430 m_counters[state][event]++; 1431 m_event_counters[event]++; 1432} 1433void 1434${ident}_Profiler::possibleTransition(${ident}_State state, 1435 ${ident}_Event event) 1436{ 1437 m_possible[state][event] = true; 1438} 1439 1440uint64 1441${ident}_Profiler::getEventCount(${ident}_Event event) 1442{ 1443 return m_event_counters[event]; 1444} 1445 1446bool 1447${ident}_Profiler::isPossible(${ident}_State state, ${ident}_Event event) 1448{ 1449 return m_possible[state][event]; 1450} 1451 1452uint64 1453${ident}_Profiler::getTransitionCount(${ident}_State state, 1454 ${ident}_Event event) 1455{ 1456 return m_counters[state][event]; 1457} 1458 1459''') 1460 code.write(path, "%s_Profiler.cc" % self.ident) 1461 1462 # ************************** 1463 # ******* HTML Files ******* 1464 # ************************** 1465 def frameRef(self, click_href, click_target, over_href, over_num, text): 1466 code = self.symtab.codeFormatter(fix_newlines=False) 1467 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1468 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1469 parent.frames[$over_num].location='$over_href' 1470 }\"> 1471 ${{html.formatShorthand(text)}} 1472 </A>""") 1473 return str(code) 1474 1475 def writeHTMLFiles(self, path): 1476 # Create table with no row hilighted 1477 self.printHTMLTransitions(path, None) 1478 1479 # Generate transition tables 1480 for state in self.states.itervalues(): 1481 self.printHTMLTransitions(path, state) 1482 1483 # Generate action descriptions 1484 for action in self.actions.itervalues(): 1485 name = "%s_action_%s.html" % (self.ident, action.ident) 1486 code = html.createSymbol(action, "Action") 1487 code.write(path, name) 1488 1489 # Generate state descriptions 1490 for state in self.states.itervalues(): 1491 name = "%s_State_%s.html" % (self.ident, state.ident) 1492 code = html.createSymbol(state, "State") 1493 code.write(path, name) 1494 1495 # Generate event descriptions 1496 for event in self.events.itervalues(): 1497 name = "%s_Event_%s.html" % (self.ident, event.ident) 1498 code = html.createSymbol(event, "Event") 1499 code.write(path, name) 1500 1501 def printHTMLTransitions(self, path, active_state): 1502 code = self.symtab.codeFormatter() 1503 1504 code(''' 1505<HTML> 1506<BODY link="blue" vlink="blue"> 1507 1508<H1 align="center">${{html.formatShorthand(self.short)}}: 1509''') 1510 code.indent() 1511 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1512 mid = machine.ident 1513 if i != 0: 1514 extra = " - " 1515 else: 1516 extra = "" 1517 if machine == self: 1518 code('$extra$mid') 1519 else: 1520 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1521 code.dedent() 1522 1523 code(""" 1524</H1> 1525 1526<TABLE border=1> 1527<TR> 1528 <TH> </TH> 1529""") 1530 1531 for event in self.events.itervalues(): 1532 href = "%s_Event_%s.html" % (self.ident, event.ident) 1533 ref = self.frameRef(href, "Status", href, "1", event.short) 1534 code('<TH bgcolor=white>$ref</TH>') 1535 1536 code('</TR>') 1537 # -- Body of table 1538 for state in self.states.itervalues(): 1539 # -- Each row 1540 if state == active_state: 1541 color = "yellow" 1542 else: 1543 color = "white" 1544 1545 click = "%s_table_%s.html" % (self.ident, state.ident) 1546 over = "%s_State_%s.html" % (self.ident, state.ident) 1547 text = html.formatShorthand(state.short) 1548 ref = self.frameRef(click, "Table", over, "1", state.short) 1549 code(''' 1550<TR> 1551 <TH bgcolor=$color>$ref</TH> 1552''') 1553 1554 # -- One column for each event 1555 for event in self.events.itervalues(): 1556 trans = self.table.get((state,event), None) 1557 if trans is None: 1558 # This is the no transition case 1559 if state == active_state: 1560 color = "#C0C000" 1561 else: 1562 color = "lightgrey" 1563 1564 code('<TD bgcolor=$color> </TD>') 1565 continue 1566 1567 next = trans.nextState 1568 stall_action = False 1569 1570 # -- Get the actions 1571 for action in trans.actions: 1572 if action.ident == "z_stall" or \ 1573 action.ident == "zz_recycleMandatoryQueue": 1574 stall_action = True 1575 1576 # -- Print out "actions/next-state" 1577 if stall_action: 1578 if state == active_state: 1579 color = "#C0C000" 1580 else: 1581 color = "lightgrey" 1582 1583 elif active_state and next.ident == active_state.ident: 1584 color = "aqua" 1585 elif state == active_state: 1586 color = "yellow" 1587 else: 1588 color = "white" 1589 1590 code('<TD bgcolor=$color>') 1591 for action in trans.actions: 1592 href = "%s_action_%s.html" % (self.ident, action.ident) 1593 ref = self.frameRef(href, "Status", href, "1", 1594 action.short) 1595 code(' $ref') 1596 if next != state: 1597 if trans.actions: 1598 code('/') 1599 click = "%s_table_%s.html" % (self.ident, next.ident) 1600 over = "%s_State_%s.html" % (self.ident, next.ident) 1601 ref = self.frameRef(click, "Table", over, "1", next.short) 1602 code("$ref") 1603 code("</TD>") 1604 1605 # -- Each row 1606 if state == active_state: 1607 color = "yellow" 1608 else: 1609 color = "white" 1610 1611 click = "%s_table_%s.html" % (self.ident, state.ident) 1612 over = "%s_State_%s.html" % (self.ident, state.ident) 1613 ref = self.frameRef(click, "Table", over, "1", state.short) 1614 code(''' 1615 <TH bgcolor=$color>$ref</TH> 1616</TR> 1617''') 1618 code(''' 1619<!- Column footer-> 1620<TR> 1621 <TH> </TH> 1622''') 1623 1624 for event in self.events.itervalues(): 1625 href = "%s_Event_%s.html" % (self.ident, event.ident) 1626 ref = self.frameRef(href, "Status", href, "1", event.short) 1627 code('<TH bgcolor=white>$ref</TH>') 1628 code(''' 1629</TR> 1630</TABLE> 1631</BODY></HTML> 1632''') 1633 1634 1635 if active_state: 1636 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1637 else: 1638 name = "%s_table.html" % self.ident 1639 code.write(path, name) 1640 1641__all__ = [ "StateMachine" ] 1642