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