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