StateMachine.py revision 10307:6df951dcd7d9
12600SN/A# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 22600SN/A# Copyright (c) 2009 The Hewlett-Packard Development Company 32600SN/A# All rights reserved. 42600SN/A# 52600SN/A# Redistribution and use in source and binary forms, with or without 62600SN/A# modification, are permitted provided that the following conditions are 72600SN/A# met: redistributions of source code must retain the above copyright 82600SN/A# notice, this list of conditions and the following disclaimer; 92600SN/A# redistributions in binary form must reproduce the above copyright 102600SN/A# notice, this list of conditions and the following disclaimer in the 112600SN/A# documentation and/or other materials provided with the distribution; 122600SN/A# neither the name of the copyright holders nor the names of its 132600SN/A# contributors may be used to endorse or promote products derived from 142600SN/A# this software without specific prior written permission. 152600SN/A# 162600SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172600SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182600SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192600SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202600SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212600SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222600SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232600SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242600SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252600SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262600SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu 282665Ssaidi@eecs.umich.edufrom m5.util import orderdict 292600SN/A 302600SN/Afrom slicc.symbols.Symbol import Symbol 312600SN/Afrom slicc.symbols.Var import Var 322600SN/Aimport slicc.generate.html as html 332600SN/Aimport re 342600SN/A 352600SN/Apython_class_map = { 362680Sktlim@umich.edu "int": "Int", 372600SN/A "uint32_t" : "UInt32", 382600SN/A "std::string": "String", 392600SN/A "bool": "Bool", 402600SN/A "CacheMemory": "RubyCache", 412600SN/A "WireBuffer": "RubyWireBuffer", 422600SN/A "Sequencer": "RubySequencer", 432600SN/A "DirectoryMemory": "RubyDirectoryMemory", 442600SN/A "MemoryControl": "MemoryControl", 452600SN/A "DMASequencer": "DMASequencer", 462600SN/A "Prefetcher":"Prefetcher", 472600SN/A "Cycles":"Cycles", 483114Sgblack@eecs.umich.edu } 492680Sktlim@umich.edu 502600SN/Aclass StateMachine(Symbol): 512680Sktlim@umich.edu def __init__(self, symtab, ident, location, pairs, config_parameters): 522600SN/A super(StateMachine, self).__init__(symtab, ident, location, pairs) 532600SN/A self.table = None 542600SN/A self.config_parameters = config_parameters 552600SN/A self.prefetchers = [] 562600SN/A 572600SN/A for param in config_parameters: 582600SN/A if param.pointer: 592680Sktlim@umich.edu var = Var(symtab, param.name, location, param.type_ast.type, 602600SN/A "(*m_%s_ptr)" % param.name, {}, self) 612600SN/A else: 622600SN/A var = Var(symtab, param.name, location, param.type_ast.type, 632600SN/A "m_%s" % param.name, {}, self) 642600SN/A self.symtab.registerSym(param.name, var) 652600SN/A if str(param.type_ast.type) == "Prefetcher": 662600SN/A self.prefetchers.append(var) 672600SN/A 682600SN/A self.states = orderdict() 692600SN/A self.events = orderdict() 702600SN/A self.actions = orderdict() 712600SN/A self.request_types = orderdict() 722600SN/A self.transitions = [] 732600SN/A self.in_ports = [] 742600SN/A self.functions = [] 752600SN/A self.objects = [] 762600SN/A self.TBEType = None 772600SN/A self.EntryType = None 782600SN/A 792600SN/A def __repr__(self): 802600SN/A return "[StateMachine: %s]" % self.ident 812600SN/A 822600SN/A def addState(self, state): 832600SN/A assert self.table is None 842600SN/A self.states[state.ident] = state 852600SN/A 862600SN/A def addEvent(self, event): 872600SN/A assert self.table is None 882600SN/A self.events[event.ident] = event 892600SN/A 902600SN/A def addAction(self, action): 912600SN/A assert self.table is None 922600SN/A 932600SN/A # Check for duplicate action 942600SN/A for other in self.actions.itervalues(): 952600SN/A if action.ident == other.ident: 962600SN/A action.warning("Duplicate action definition: %s" % action.ident) 972600SN/A action.error("Duplicate action definition: %s" % action.ident) 982600SN/A if action.short == other.short: 992600SN/A other.warning("Duplicate action shorthand: %s" % other.ident) 1002600SN/A other.warning(" shorthand = %s" % other.short) 1012600SN/A action.warning("Duplicate action shorthand: %s" % action.ident) 1022600SN/A action.error(" shorthand = %s" % action.short) 1032600SN/A 1042600SN/A self.actions[action.ident] = action 1052600SN/A 1062600SN/A def addRequestType(self, request_type): 1072600SN/A assert self.table is None 1082600SN/A self.request_types[request_type.ident] = request_type 1092600SN/A 1102600SN/A def addTransition(self, trans): 1112600SN/A assert self.table is None 1122600SN/A self.transitions.append(trans) 1132600SN/A 1142600SN/A def addInPort(self, var): 1152600SN/A self.in_ports.append(var) 1162600SN/A 1172600SN/A def addFunc(self, func): 1182600SN/A # register func in the symbol table 1192600SN/A self.symtab.registerSym(str(func), func) 1202600SN/A self.functions.append(func) 1212600SN/A 1222600SN/A def addObject(self, obj): 1232600SN/A self.symtab.registerSym(str(obj), obj) 1242600SN/A self.objects.append(obj) 1252600SN/A 1262600SN/A def addType(self, type): 1272600SN/A type_ident = '%s' % type.c_ident 1282600SN/A 1292600SN/A if type_ident == "%s_TBE" %self.ident: 1302600SN/A if self.TBEType != None: 1312600SN/A self.error("Multiple Transaction Buffer types in a " \ 1322600SN/A "single machine."); 1332600SN/A self.TBEType = type 1342600SN/A 1352600SN/A elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 1362600SN/A if self.EntryType != None: 1372600SN/A self.error("Multiple AbstractCacheEntry types in a " \ 1382600SN/A "single machine."); 1392600SN/A self.EntryType = type 1402600SN/A 1412600SN/A # Needs to be called before accessing the table 1422600SN/A def buildTable(self): 1432600SN/A assert self.table is None 1442600SN/A 1452600SN/A table = {} 1462600SN/A 1472600SN/A for trans in self.transitions: 1482600SN/A # Track which actions we touch so we know if we use them 1492600SN/A # all -- really this should be done for all symbols as 1502600SN/A # part of the symbol table, then only trigger it for 1512600SN/A # Actions, States, Events, etc. 1522600SN/A 1532600SN/A for action in trans.actions: 1542600SN/A action.used = True 1552600SN/A 1562600SN/A index = (trans.state, trans.event) 1572600SN/A if index in table: 1582600SN/A table[index].warning("Duplicate transition: %s" % table[index]) 1592600SN/A trans.error("Duplicate transition: %s" % trans) 1602600SN/A table[index] = trans 1612600SN/A 1622600SN/A # Look at all actions to make sure we used them all 1632600SN/A for action in self.actions.itervalues(): 1642600SN/A if not action.used: 1652600SN/A error_msg = "Unused action: %s" % action.ident 1662600SN/A if "desc" in action: 1672600SN/A error_msg += ", " + action.desc 1682600SN/A action.warning(error_msg) 1692600SN/A self.table = table 1702600SN/A 1712600SN/A def writeCodeFiles(self, path, includes): 1722600SN/A self.printControllerPython(path) 1732600SN/A self.printControllerHH(path) 1742600SN/A self.printControllerCC(path, includes) 1752600SN/A self.printCSwitch(path) 1762600SN/A self.printCWakeup(path, includes) 1772600SN/A 1782600SN/A def printControllerPython(self, path): 1792600SN/A code = self.symtab.codeFormatter() 1802600SN/A ident = self.ident 1812600SN/A py_ident = "%s_Controller" % ident 1822600SN/A c_ident = "%s_Controller" % self.ident 1832600SN/A code(''' 1842600SN/Afrom m5.params import * 1852600SN/Afrom m5.SimObject import SimObject 1862600SN/Afrom Controller import RubyController 1872600SN/A 1882600SN/Aclass $py_ident(RubyController): 1892600SN/A type = '$py_ident' 1902600SN/A cxx_header = 'mem/protocol/${c_ident}.hh' 1912600SN/A''') 1922600SN/A code.indent() 1932600SN/A for param in self.config_parameters: 1942600SN/A dflt_str = '' 1952600SN/A if param.default is not None: 1962600SN/A dflt_str = str(param.default) + ', ' 1972600SN/A if python_class_map.has_key(param.type_ast.type.c_ident): 1982600SN/A python_type = python_class_map[param.type_ast.type.c_ident] 1992600SN/A code('${{param.name}} = Param.${{python_type}}(${dflt_str}"")') 2002600SN/A else: 2012600SN/A self.error("Unknown c++ to python class conversion for c++ " \ 2022600SN/A "type: '%s'. Please update the python_class_map " \ 2032600SN/A "in StateMachine.py", param.type_ast.type.c_ident) 2042600SN/A code.dedent() 2052600SN/A code.write(path, '%s.py' % py_ident) 2062600SN/A 2072600SN/A 2082600SN/A def printControllerHH(self, path): 2092600SN/A '''Output the method declarations for the class declaration''' 2102600SN/A code = self.symtab.codeFormatter() 2112600SN/A ident = self.ident 2122600SN/A c_ident = "%s_Controller" % self.ident 2132600SN/A 2142600SN/A code(''' 2152600SN/A/** \\file $c_ident.hh 2162600SN/A * 2172600SN/A * Auto generated C++ code started by $__file__:$__line__ 2182600SN/A * Created by slicc definition of Module "${{self.short}}" 2192600SN/A */ 2202600SN/A 2212600SN/A#ifndef __${ident}_CONTROLLER_HH__ 2222600SN/A#define __${ident}_CONTROLLER_HH__ 2232600SN/A 2242600SN/A#include <iostream> 2252600SN/A#include <sstream> 2262600SN/A#include <string> 2272600SN/A 2282600SN/A#include "mem/protocol/TransitionResult.hh" 2292600SN/A#include "mem/protocol/Types.hh" 2302600SN/A#include "mem/ruby/common/Consumer.hh" 2312600SN/A#include "mem/ruby/common/Global.hh" 2322600SN/A#include "mem/ruby/slicc_interface/AbstractController.hh" 2332600SN/A#include "params/$c_ident.hh" 2342600SN/A''') 2352600SN/A 2362600SN/A seen_types = set() 2372600SN/A has_peer = False 2382600SN/A for var in self.objects: 2392600SN/A if var.type.ident not in seen_types and not var.type.isPrimitive: 2402600SN/A code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 2412600SN/A if "network" in var and "physical_network" in var: 2422600SN/A has_peer = True 2432600SN/A seen_types.add(var.type.ident) 2442600SN/A 2452600SN/A # for adding information to the protocol debug trace 2462600SN/A code(''' 2472600SN/Aextern std::stringstream ${ident}_transitionComment; 2482600SN/A 2492600SN/Aclass $c_ident : public AbstractController 2502600SN/A{ 2512600SN/A public: 2522600SN/A typedef ${c_ident}Params Params; 2532600SN/A $c_ident(const Params *p); 2542600SN/A static int getNumControllers(); 2552600SN/A void init(); 2562600SN/A MessageBuffer* getMandatoryQueue() const; 2572600SN/A 2582600SN/A void print(std::ostream& out) const; 2592600SN/A void wakeup(); 2602600SN/A void resetStats(); 2612600SN/A void regStats(); 2622600SN/A void collateStats(); 2632600SN/A 2642600SN/A void recordCacheTrace(int cntrl, CacheRecorder* tr); 2652600SN/A Sequencer* getSequencer() const; 2662600SN/A 2672600SN/A bool functionalReadBuffers(PacketPtr&); 2682600SN/A uint32_t functionalWriteBuffers(PacketPtr&); 2692600SN/A 2702600SN/A void countTransition(${ident}_State state, ${ident}_Event event); 2712600SN/A void possibleTransition(${ident}_State state, ${ident}_Event event); 2722600SN/A uint64 getEventCount(${ident}_Event event); 2732600SN/A bool isPossible(${ident}_State state, ${ident}_Event event); 2742600SN/A uint64 getTransitionCount(${ident}_State state, ${ident}_Event event); 2752600SN/A 2762600SN/Aprivate: 2772600SN/A''') 2782600SN/A 2792600SN/A code.indent() 2802600SN/A # added by SS 2812600SN/A for param in self.config_parameters: 2822600SN/A if param.pointer: 2832600SN/A code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 2842600SN/A else: 2852600SN/A code('${{param.type_ast.type}} m_${{param.ident}};') 2862600SN/A 2872600SN/A code(''' 2882600SN/ATransitionResult doTransition(${ident}_Event event, 2892600SN/A''') 2902600SN/A 2912600SN/A if self.EntryType != None: 2922600SN/A code(''' 2932600SN/A ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 2942600SN/A''') 2952600SN/A if self.TBEType != None: 2962600SN/A code(''' 2972600SN/A ${{self.TBEType.c_ident}}* m_tbe_ptr, 2982600SN/A''') 2992600SN/A 3002600SN/A code(''' 3012600SN/A const Address addr); 3022600SN/A 3032600SN/ATransitionResult doTransitionWorker(${ident}_Event event, 3042600SN/A ${ident}_State state, 3052600SN/A ${ident}_State& next_state, 3062600SN/A''') 3072600SN/A 3082600SN/A if self.TBEType != None: 3092600SN/A code(''' 3102600SN/A ${{self.TBEType.c_ident}}*& m_tbe_ptr, 3112600SN/A''') 3122600SN/A if self.EntryType != None: 3132600SN/A code(''' 3142600SN/A ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 3152600SN/A''') 3162600SN/A 3172600SN/A code(''' 3182600SN/A const Address& addr); 3192600SN/A 3202600SN/Aint m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 3212600SN/Aint m_event_counters[${ident}_Event_NUM]; 3222600SN/Abool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 3232600SN/A 3242600SN/Astatic std::vector<Stats::Vector *> eventVec; 3252600SN/Astatic std::vector<std::vector<Stats::Vector *> > transVec; 3262600SN/Astatic int m_num_controllers; 3272600SN/A 3282600SN/A// Internal functions 3292600SN/A''') 3302600SN/A 3313114Sgblack@eecs.umich.edu for func in self.functions: 3323114Sgblack@eecs.umich.edu proto = func.prototype 3333114Sgblack@eecs.umich.edu if proto: 3343114Sgblack@eecs.umich.edu code('$proto') 3353114Sgblack@eecs.umich.edu 3363114Sgblack@eecs.umich.edu if has_peer: 3373114Sgblack@eecs.umich.edu code('void getQueuesFromPeer(AbstractController *);') 3382600SN/A if self.EntryType != None: 3393114Sgblack@eecs.umich.edu code(''' 3403114Sgblack@eecs.umich.edu 3412600SN/A// Set and Reset for cache_entry variable 3422600SN/Avoid set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 3432600SN/Avoid unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 3442600SN/A''') 3452600SN/A 3462600SN/A if self.TBEType != None: 3472600SN/A code(''' 3482600SN/A 3492600SN/A// Set and Reset for tbe variable 3502600SN/Avoid set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 3512600SN/Avoid unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 3522600SN/A''') 3532600SN/A 3542600SN/A # Prototype the actions that the controller can take 3552600SN/A code(''' 3562600SN/A 357// Actions 358''') 359 if self.TBEType != None and self.EntryType != None: 360 for action in self.actions.itervalues(): 361 code('/** \\brief ${{action.desc}} */') 362 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 363 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 364 'm_cache_entry_ptr, const Address& addr);') 365 elif self.TBEType != None: 366 for action in self.actions.itervalues(): 367 code('/** \\brief ${{action.desc}} */') 368 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 369 'm_tbe_ptr, const Address& addr);') 370 elif self.EntryType != None: 371 for action in self.actions.itervalues(): 372 code('/** \\brief ${{action.desc}} */') 373 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 374 'm_cache_entry_ptr, const Address& addr);') 375 else: 376 for action in self.actions.itervalues(): 377 code('/** \\brief ${{action.desc}} */') 378 code('void ${{action.ident}}(const Address& addr);') 379 380 # the controller internal variables 381 code(''' 382 383// Objects 384''') 385 for var in self.objects: 386 th = var.get("template", "") 387 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 388 389 code.dedent() 390 code('};') 391 code('#endif // __${ident}_CONTROLLER_H__') 392 code.write(path, '%s.hh' % c_ident) 393 394 def printControllerCC(self, path, includes): 395 '''Output the actions for performing the actions''' 396 397 code = self.symtab.codeFormatter() 398 ident = self.ident 399 c_ident = "%s_Controller" % self.ident 400 has_peer = False 401 402 code(''' 403/** \\file $c_ident.cc 404 * 405 * Auto generated C++ code started by $__file__:$__line__ 406 * Created by slicc definition of Module "${{self.short}}" 407 */ 408 409#include <sys/types.h> 410#include <unistd.h> 411 412#include <cassert> 413#include <sstream> 414#include <string> 415 416#include "base/compiler.hh" 417#include "base/cprintf.hh" 418#include "debug/RubyGenerated.hh" 419#include "debug/RubySlicc.hh" 420#include "mem/protocol/${ident}_Controller.hh" 421#include "mem/protocol/${ident}_Event.hh" 422#include "mem/protocol/${ident}_State.hh" 423#include "mem/protocol/Types.hh" 424#include "mem/ruby/common/Global.hh" 425#include "mem/ruby/system/System.hh" 426''') 427 for include_path in includes: 428 code('#include "${{include_path}}"') 429 430 code(''' 431 432using namespace std; 433''') 434 435 # include object classes 436 seen_types = set() 437 for var in self.objects: 438 if var.type.ident not in seen_types and not var.type.isPrimitive: 439 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 440 seen_types.add(var.type.ident) 441 442 num_in_ports = len(self.in_ports) 443 444 code(''' 445$c_ident * 446${c_ident}Params::create() 447{ 448 return new $c_ident(this); 449} 450 451int $c_ident::m_num_controllers = 0; 452std::vector<Stats::Vector *> $c_ident::eventVec; 453std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 454 455// for adding information to the protocol debug trace 456stringstream ${ident}_transitionComment; 457 458#ifndef NDEBUG 459#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 460#else 461#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 462#endif 463 464/** \\brief constructor */ 465$c_ident::$c_ident(const Params *p) 466 : AbstractController(p) 467{ 468 m_machineID.type = MachineType_${ident}; 469 m_machineID.num = m_version; 470 m_num_controllers++; 471 472 m_in_ports = $num_in_ports; 473''') 474 code.indent() 475 476 # 477 # After initializing the universal machine parameters, initialize the 478 # this machines config parameters. Also if these configuration params 479 # include a sequencer, connect the it to the controller. 480 # 481 for param in self.config_parameters: 482 if param.pointer: 483 code('m_${{param.name}}_ptr = p->${{param.name}};') 484 else: 485 code('m_${{param.name}} = p->${{param.name}};') 486 if re.compile("sequencer").search(param.name): 487 code('m_${{param.name}}_ptr->setController(this);') 488 489 for var in self.objects: 490 if var.ident.find("mandatoryQueue") >= 0: 491 code(''' 492m_${{var.ident}}_ptr = new ${{var.type.c_ident}}(); 493m_${{var.ident}}_ptr->setReceiver(this); 494''') 495 else: 496 if "network" in var and "physical_network" in var and \ 497 var["network"] == "To": 498 has_peer = True 499 code(''' 500m_${{var.ident}}_ptr = new ${{var.type.c_ident}}(); 501peerQueueMap[${{var["physical_network"]}}] = m_${{var.ident}}_ptr; 502m_${{var.ident}}_ptr->setSender(this); 503''') 504 505 code(''' 506if (p->peer != NULL) 507 connectWithPeer(p->peer); 508 509for (int state = 0; state < ${ident}_State_NUM; state++) { 510 for (int event = 0; event < ${ident}_Event_NUM; event++) { 511 m_possible[state][event] = false; 512 m_counters[state][event] = 0; 513 } 514} 515for (int event = 0; event < ${ident}_Event_NUM; event++) { 516 m_event_counters[event] = 0; 517} 518''') 519 code.dedent() 520 code(''' 521} 522 523void 524$c_ident::init() 525{ 526 MachineType machine_type = string_to_MachineType("${{var.machine.ident}}"); 527 int base M5_VAR_USED = MachineType_base_number(machine_type); 528 529 // initialize objects 530 531''') 532 533 code.indent() 534 for var in self.objects: 535 vtype = var.type 536 vid = "m_%s_ptr" % var.ident 537 if "network" not in var: 538 # Not a network port object 539 if "primitive" in vtype: 540 code('$vid = new ${{vtype.c_ident}};') 541 if "default" in var: 542 code('(*$vid) = ${{var["default"]}};') 543 else: 544 # Normal Object 545 if var.ident.find("mandatoryQueue") < 0: 546 th = var.get("template", "") 547 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 548 args = "" 549 if "non_obj" not in vtype and not vtype.isEnumeration: 550 args = var.get("constructor", "") 551 code('$expr($args);') 552 553 code('assert($vid != NULL);') 554 555 if "default" in var: 556 code('*$vid = ${{var["default"]}}; // Object default') 557 elif "default" in vtype: 558 comment = "Type %s default" % vtype.ident 559 code('*$vid = ${{vtype["default"]}}; // $comment') 560 561 # Set ordering 562 if "ordered" in var: 563 # A buffer 564 code('$vid->setOrdering(${{var["ordered"]}});') 565 566 # Set randomization 567 if "random" in var: 568 # A buffer 569 code('$vid->setRandomization(${{var["random"]}});') 570 571 # Set Priority 572 if vtype.isBuffer and "rank" in var: 573 code('$vid->setPriority(${{var["rank"]}});') 574 575 # Set sender and receiver for trigger queue 576 if var.ident.find("triggerQueue") >= 0: 577 code('$vid->setSender(this);') 578 code('$vid->setReceiver(this);') 579 elif vtype.c_ident == "TimerTable": 580 code('$vid->setClockObj(this);') 581 elif var.ident.find("optionalQueue") >= 0: 582 code('$vid->setSender(this);') 583 code('$vid->setReceiver(this);') 584 585 else: 586 # Network port object 587 network = var["network"] 588 ordered = var["ordered"] 589 590 if "virtual_network" in var: 591 vnet = var["virtual_network"] 592 vnet_type = var["vnet_type"] 593 594 assert var.machine is not None 595 code(''' 596$vid = m_net_ptr->get${network}NetQueue(m_version + base, $ordered, $vnet, "$vnet_type"); 597assert($vid != NULL); 598''') 599 600 # Set the end 601 if network == "To": 602 code('$vid->setSender(this);') 603 else: 604 code('$vid->setReceiver(this);') 605 606 # Set ordering 607 if "ordered" in var: 608 # A buffer 609 code('$vid->setOrdering(${{var["ordered"]}});') 610 611 # Set randomization 612 if "random" in var: 613 # A buffer 614 code('$vid->setRandomization(${{var["random"]}});') 615 616 # Set Priority 617 if "rank" in var: 618 code('$vid->setPriority(${{var["rank"]}})') 619 620 # Set buffer size 621 if vtype.isBuffer: 622 code(''' 623if (m_buffer_size > 0) { 624 $vid->resize(m_buffer_size); 625} 626''') 627 628 # set description (may be overriden later by port def) 629 code(''' 630$vid->setDescription("[Version " + to_string(m_version) + ", ${ident}, name=${{var.ident}}]"); 631 632''') 633 634 if vtype.isBuffer: 635 if "recycle_latency" in var: 636 code('$vid->setRecycleLatency( ' \ 637 'Cycles(${{var["recycle_latency"]}}));') 638 else: 639 code('$vid->setRecycleLatency(m_recycle_latency);') 640 641 # Set the prefetchers 642 code() 643 for prefetcher in self.prefetchers: 644 code('${{prefetcher.code}}.setController(this);') 645 646 code() 647 for port in self.in_ports: 648 # Set the queue consumers 649 code('${{port.code}}.setConsumer(this);') 650 # Set the queue descriptions 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('possibleTransition($state, $event);') 667 668 code.dedent() 669 code(''' 670 AbstractController::init(); 671 resetStats(); 672} 673''') 674 675 mq_ident = "NULL" 676 for port in self.in_ports: 677 if port.code.find("mandatoryQueue_ptr") >= 0: 678 mq_ident = "m_mandatoryQueue_ptr" 679 680 seq_ident = "NULL" 681 for param in self.config_parameters: 682 if param.name == "sequencer": 683 assert(param.pointer) 684 seq_ident = "m_%s_ptr" % param.name 685 686 code(''' 687 688void 689$c_ident::regStats() 690{ 691 AbstractController::regStats(); 692 693 if (m_version == 0) { 694 for (${ident}_Event event = ${ident}_Event_FIRST; 695 event < ${ident}_Event_NUM; ++event) { 696 Stats::Vector *t = new Stats::Vector(); 697 t->init(m_num_controllers); 698 t->name(g_system_ptr->name() + ".${c_ident}." + 699 ${ident}_Event_to_string(event)); 700 t->flags(Stats::pdf | Stats::total | Stats::oneline | 701 Stats::nozero); 702 703 eventVec.push_back(t); 704 } 705 706 for (${ident}_State state = ${ident}_State_FIRST; 707 state < ${ident}_State_NUM; ++state) { 708 709 transVec.push_back(std::vector<Stats::Vector *>()); 710 711 for (${ident}_Event event = ${ident}_Event_FIRST; 712 event < ${ident}_Event_NUM; ++event) { 713 714 Stats::Vector *t = new Stats::Vector(); 715 t->init(m_num_controllers); 716 t->name(g_system_ptr->name() + ".${c_ident}." + 717 ${ident}_State_to_string(state) + 718 "." + ${ident}_Event_to_string(event)); 719 720 t->flags(Stats::pdf | Stats::total | Stats::oneline | 721 Stats::nozero); 722 transVec[state].push_back(t); 723 } 724 } 725 } 726} 727 728void 729$c_ident::collateStats() 730{ 731 for (${ident}_Event event = ${ident}_Event_FIRST; 732 event < ${ident}_Event_NUM; ++event) { 733 for (unsigned int i = 0; i < m_num_controllers; ++i) { 734 std::map<uint32_t, AbstractController *>::iterator it = 735 g_abs_controls[MachineType_${ident}].find(i); 736 assert(it != g_abs_controls[MachineType_${ident}].end()); 737 (*eventVec[event])[i] = 738 (($c_ident *)(*it).second)->getEventCount(event); 739 } 740 } 741 742 for (${ident}_State state = ${ident}_State_FIRST; 743 state < ${ident}_State_NUM; ++state) { 744 745 for (${ident}_Event event = ${ident}_Event_FIRST; 746 event < ${ident}_Event_NUM; ++event) { 747 748 for (unsigned int i = 0; i < m_num_controllers; ++i) { 749 std::map<uint32_t, AbstractController *>::iterator it = 750 g_abs_controls[MachineType_${ident}].find(i); 751 assert(it != g_abs_controls[MachineType_${ident}].end()); 752 (*transVec[state][event])[i] = 753 (($c_ident *)(*it).second)->getTransitionCount(state, event); 754 } 755 } 756 } 757} 758 759void 760$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 761{ 762 assert(m_possible[state][event]); 763 m_counters[state][event]++; 764 m_event_counters[event]++; 765} 766void 767$c_ident::possibleTransition(${ident}_State state, 768 ${ident}_Event event) 769{ 770 m_possible[state][event] = true; 771} 772 773uint64 774$c_ident::getEventCount(${ident}_Event event) 775{ 776 return m_event_counters[event]; 777} 778 779bool 780$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 781{ 782 return m_possible[state][event]; 783} 784 785uint64 786$c_ident::getTransitionCount(${ident}_State state, 787 ${ident}_Event event) 788{ 789 return m_counters[state][event]; 790} 791 792int 793$c_ident::getNumControllers() 794{ 795 return m_num_controllers; 796} 797 798MessageBuffer* 799$c_ident::getMandatoryQueue() const 800{ 801 return $mq_ident; 802} 803 804Sequencer* 805$c_ident::getSequencer() const 806{ 807 return $seq_ident; 808} 809 810void 811$c_ident::print(ostream& out) const 812{ 813 out << "[$c_ident " << m_version << "]"; 814} 815 816void $c_ident::resetStats() 817{ 818 for (int state = 0; state < ${ident}_State_NUM; state++) { 819 for (int event = 0; event < ${ident}_Event_NUM; event++) { 820 m_counters[state][event] = 0; 821 } 822 } 823 824 for (int event = 0; event < ${ident}_Event_NUM; event++) { 825 m_event_counters[event] = 0; 826 } 827 828 AbstractController::resetStats(); 829} 830''') 831 832 if self.EntryType != None: 833 code(''' 834 835// Set and Reset for cache_entry variable 836void 837$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 838{ 839 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 840} 841 842void 843$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 844{ 845 m_cache_entry_ptr = 0; 846} 847''') 848 849 if self.TBEType != None: 850 code(''' 851 852// Set and Reset for tbe variable 853void 854$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 855{ 856 m_tbe_ptr = m_new_tbe; 857} 858 859void 860$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 861{ 862 m_tbe_ptr = NULL; 863} 864''') 865 866 code(''' 867 868void 869$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 870{ 871''') 872 # 873 # Record cache contents for all associated caches. 874 # 875 code.indent() 876 for param in self.config_parameters: 877 if param.type_ast.type.ident == "CacheMemory": 878 assert(param.pointer) 879 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 880 881 code.dedent() 882 code(''' 883} 884 885// Actions 886''') 887 if self.TBEType != None and self.EntryType != None: 888 for action in self.actions.itervalues(): 889 if "c_code" not in action: 890 continue 891 892 code(''' 893/** \\brief ${{action.desc}} */ 894void 895$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 896{ 897 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 898 ${{action["c_code"]}} 899} 900 901''') 902 elif self.TBEType != None: 903 for action in self.actions.itervalues(): 904 if "c_code" not in action: 905 continue 906 907 code(''' 908/** \\brief ${{action.desc}} */ 909void 910$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) 911{ 912 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 913 ${{action["c_code"]}} 914} 915 916''') 917 elif self.EntryType != None: 918 for action in self.actions.itervalues(): 919 if "c_code" not in action: 920 continue 921 922 code(''' 923/** \\brief ${{action.desc}} */ 924void 925$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) 926{ 927 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 928 ${{action["c_code"]}} 929} 930 931''') 932 else: 933 for action in self.actions.itervalues(): 934 if "c_code" not in action: 935 continue 936 937 code(''' 938/** \\brief ${{action.desc}} */ 939void 940$c_ident::${{action.ident}}(const Address& addr) 941{ 942 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 943 ${{action["c_code"]}} 944} 945 946''') 947 for func in self.functions: 948 code(func.generateCode()) 949 950 # Function for functional reads from messages buffered in the controller 951 code(''' 952bool 953$c_ident::functionalReadBuffers(PacketPtr& pkt) 954{ 955''') 956 for var in self.objects: 957 vtype = var.type 958 if vtype.isBuffer: 959 vid = "m_%s_ptr" % var.ident 960 code('if ($vid->functionalRead(pkt)) { return true; }') 961 code(''' 962 return false; 963} 964''') 965 966 # Function for functional writes to messages buffered in the controller 967 code(''' 968uint32_t 969$c_ident::functionalWriteBuffers(PacketPtr& pkt) 970{ 971 uint32_t num_functional_writes = 0; 972''') 973 for var in self.objects: 974 vtype = var.type 975 if vtype.isBuffer: 976 vid = "m_%s_ptr" % var.ident 977 code('num_functional_writes += $vid->functionalWrite(pkt);') 978 code(''' 979 return num_functional_writes; 980} 981''') 982 983 # Check if this controller has a peer, if yes then write the 984 # function for connecting to the peer. 985 if has_peer: 986 code(''' 987 988void 989$c_ident::getQueuesFromPeer(AbstractController *peer) 990{ 991''') 992 for var in self.objects: 993 if "network" in var and "physical_network" in var and \ 994 var["network"] == "From": 995 code(''' 996m_${{var.ident}}_ptr = peer->getPeerQueue(${{var["physical_network"]}}); 997assert(m_${{var.ident}}_ptr != NULL); 998m_${{var.ident}}_ptr->setReceiver(this); 999 1000''') 1001 code('}') 1002 1003 code.write(path, "%s.cc" % c_ident) 1004 1005 def printCWakeup(self, path, includes): 1006 '''Output the wakeup loop for the events''' 1007 1008 code = self.symtab.codeFormatter() 1009 ident = self.ident 1010 1011 outputRequest_types = True 1012 if len(self.request_types) == 0: 1013 outputRequest_types = False 1014 1015 code(''' 1016// Auto generated C++ code started by $__file__:$__line__ 1017// ${ident}: ${{self.short}} 1018 1019#include <sys/types.h> 1020#include <unistd.h> 1021 1022#include <cassert> 1023 1024#include "base/misc.hh" 1025#include "debug/RubySlicc.hh" 1026#include "mem/protocol/${ident}_Controller.hh" 1027#include "mem/protocol/${ident}_Event.hh" 1028#include "mem/protocol/${ident}_State.hh" 1029''') 1030 1031 if outputRequest_types: 1032 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1033 1034 code(''' 1035#include "mem/protocol/Types.hh" 1036#include "mem/ruby/common/Global.hh" 1037#include "mem/ruby/system/System.hh" 1038''') 1039 1040 1041 for include_path in includes: 1042 code('#include "${{include_path}}"') 1043 1044 code(''' 1045 1046using namespace std; 1047 1048void 1049${ident}_Controller::wakeup() 1050{ 1051 int counter = 0; 1052 while (true) { 1053 // Some cases will put us into an infinite loop without this limit 1054 assert(counter <= m_transitions_per_cycle); 1055 if (counter == m_transitions_per_cycle) { 1056 // Count how often we are fully utilized 1057 m_fully_busy_cycles++; 1058 1059 // Wakeup in another cycle and try again 1060 scheduleEvent(Cycles(1)); 1061 break; 1062 } 1063''') 1064 1065 code.indent() 1066 code.indent() 1067 1068 # InPorts 1069 # 1070 for port in self.in_ports: 1071 code.indent() 1072 code('// ${ident}InPort $port') 1073 if port.pairs.has_key("rank"): 1074 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1075 else: 1076 code('m_cur_in_port = 0;') 1077 code('${{port["c_code_in_port"]}}') 1078 code.dedent() 1079 1080 code('') 1081 1082 code.dedent() 1083 code.dedent() 1084 code(''' 1085 break; // If we got this far, we have nothing left todo 1086 } 1087} 1088''') 1089 1090 code.write(path, "%s_Wakeup.cc" % self.ident) 1091 1092 def printCSwitch(self, path): 1093 '''Output switch statement for transition table''' 1094 1095 code = self.symtab.codeFormatter() 1096 ident = self.ident 1097 1098 code(''' 1099// Auto generated C++ code started by $__file__:$__line__ 1100// ${ident}: ${{self.short}} 1101 1102#include <cassert> 1103 1104#include "base/misc.hh" 1105#include "base/trace.hh" 1106#include "debug/ProtocolTrace.hh" 1107#include "debug/RubyGenerated.hh" 1108#include "mem/protocol/${ident}_Controller.hh" 1109#include "mem/protocol/${ident}_Event.hh" 1110#include "mem/protocol/${ident}_State.hh" 1111#include "mem/protocol/Types.hh" 1112#include "mem/ruby/common/Global.hh" 1113#include "mem/ruby/system/System.hh" 1114 1115#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1116 1117#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1118#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1119 1120TransitionResult 1121${ident}_Controller::doTransition(${ident}_Event event, 1122''') 1123 if self.EntryType != None: 1124 code(''' 1125 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1126''') 1127 if self.TBEType != None: 1128 code(''' 1129 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1130''') 1131 code(''' 1132 const Address addr) 1133{ 1134''') 1135 code.indent() 1136 1137 if self.TBEType != None and self.EntryType != None: 1138 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1139 elif self.TBEType != None: 1140 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1141 elif self.EntryType != None: 1142 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1143 else: 1144 code('${ident}_State state = getState(addr);') 1145 1146 code(''' 1147${ident}_State next_state = state; 1148 1149DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", 1150 *this, curCycle(), ${ident}_State_to_string(state), 1151 ${ident}_Event_to_string(event), addr); 1152 1153TransitionResult result = 1154''') 1155 if self.TBEType != None and self.EntryType != None: 1156 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1157 elif self.TBEType != None: 1158 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1159 elif self.EntryType != None: 1160 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1161 else: 1162 code('doTransitionWorker(event, state, next_state, addr);') 1163 1164 code(''' 1165 1166if (result == TransitionResult_Valid) { 1167 DPRINTF(RubyGenerated, "next_state: %s\\n", 1168 ${ident}_State_to_string(next_state)); 1169 countTransition(state, event); 1170 1171 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %s %s\\n", 1172 curTick(), m_version, "${ident}", 1173 ${ident}_Event_to_string(event), 1174 ${ident}_State_to_string(state), 1175 ${ident}_State_to_string(next_state), 1176 addr, GET_TRANSITION_COMMENT()); 1177 1178 CLEAR_TRANSITION_COMMENT(); 1179''') 1180 if self.TBEType != None and self.EntryType != None: 1181 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1182 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1183 elif self.TBEType != None: 1184 code('setState(m_tbe_ptr, addr, next_state);') 1185 code('setAccessPermission(addr, next_state);') 1186 elif self.EntryType != None: 1187 code('setState(m_cache_entry_ptr, addr, next_state);') 1188 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1189 else: 1190 code('setState(addr, next_state);') 1191 code('setAccessPermission(addr, next_state);') 1192 1193 code(''' 1194} else if (result == TransitionResult_ResourceStall) { 1195 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1196 curTick(), m_version, "${ident}", 1197 ${ident}_Event_to_string(event), 1198 ${ident}_State_to_string(state), 1199 ${ident}_State_to_string(next_state), 1200 addr, "Resource Stall"); 1201} else if (result == TransitionResult_ProtocolStall) { 1202 DPRINTF(RubyGenerated, "stalling\\n"); 1203 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %s\\n", 1204 curTick(), m_version, "${ident}", 1205 ${ident}_Event_to_string(event), 1206 ${ident}_State_to_string(state), 1207 ${ident}_State_to_string(next_state), 1208 addr, "Protocol Stall"); 1209} 1210 1211return result; 1212''') 1213 code.dedent() 1214 code(''' 1215} 1216 1217TransitionResult 1218${ident}_Controller::doTransitionWorker(${ident}_Event event, 1219 ${ident}_State state, 1220 ${ident}_State& next_state, 1221''') 1222 1223 if self.TBEType != None: 1224 code(''' 1225 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1226''') 1227 if self.EntryType != None: 1228 code(''' 1229 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1230''') 1231 code(''' 1232 const Address& addr) 1233{ 1234 switch(HASH_FUN(state, event)) { 1235''') 1236 1237 # This map will allow suppress generating duplicate code 1238 cases = orderdict() 1239 1240 for trans in self.transitions: 1241 case_string = "%s_State_%s, %s_Event_%s" % \ 1242 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1243 1244 case = self.symtab.codeFormatter() 1245 # Only set next_state if it changes 1246 if trans.state != trans.nextState: 1247 ns_ident = trans.nextState.ident 1248 case('next_state = ${ident}_State_${ns_ident};') 1249 1250 actions = trans.actions 1251 request_types = trans.request_types 1252 1253 # Check for resources 1254 case_sorter = [] 1255 res = trans.resources 1256 for key,val in res.iteritems(): 1257 val = ''' 1258if (!%s.areNSlotsAvailable(%s)) 1259 return TransitionResult_ResourceStall; 1260''' % (key.code, val) 1261 case_sorter.append(val) 1262 1263 # Check all of the request_types for resource constraints 1264 for request_type in request_types: 1265 val = ''' 1266if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1267 return TransitionResult_ResourceStall; 1268} 1269''' % (self.ident, request_type.ident) 1270 case_sorter.append(val) 1271 1272 # Emit the code sequences in a sorted order. This makes the 1273 # output deterministic (without this the output order can vary 1274 # since Map's keys() on a vector of pointers is not deterministic 1275 for c in sorted(case_sorter): 1276 case("$c") 1277 1278 # Record access types for this transition 1279 for request_type in request_types: 1280 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1281 1282 # Figure out if we stall 1283 stall = False 1284 for action in actions: 1285 if action.ident == "z_stall": 1286 stall = True 1287 break 1288 1289 if stall: 1290 case('return TransitionResult_ProtocolStall;') 1291 else: 1292 if self.TBEType != None and self.EntryType != None: 1293 for action in actions: 1294 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1295 elif self.TBEType != None: 1296 for action in actions: 1297 case('${{action.ident}}(m_tbe_ptr, addr);') 1298 elif self.EntryType != None: 1299 for action in actions: 1300 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1301 else: 1302 for action in actions: 1303 case('${{action.ident}}(addr);') 1304 case('return TransitionResult_Valid;') 1305 1306 case = str(case) 1307 1308 # Look to see if this transition code is unique. 1309 if case not in cases: 1310 cases[case] = [] 1311 1312 cases[case].append(case_string) 1313 1314 # Walk through all of the unique code blocks and spit out the 1315 # corresponding case statement elements 1316 for case,transitions in cases.iteritems(): 1317 # Iterative over all the multiple transitions that share 1318 # the same code 1319 for trans in transitions: 1320 code(' case HASH_FUN($trans):') 1321 code(' $case\n') 1322 1323 code(''' 1324 default: 1325 fatal("Invalid transition\\n" 1326 "%s time: %d addr: %s event: %s state: %s\\n", 1327 name(), curCycle(), addr, event, state); 1328 } 1329 1330 return TransitionResult_Valid; 1331} 1332''') 1333 code.write(path, "%s_Transitions.cc" % self.ident) 1334 1335 1336 # ************************** 1337 # ******* HTML Files ******* 1338 # ************************** 1339 def frameRef(self, click_href, click_target, over_href, over_num, text): 1340 code = self.symtab.codeFormatter(fix_newlines=False) 1341 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1342 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1343 parent.frames[$over_num].location='$over_href' 1344 }\"> 1345 ${{html.formatShorthand(text)}} 1346 </A>""") 1347 return str(code) 1348 1349 def writeHTMLFiles(self, path): 1350 # Create table with no row hilighted 1351 self.printHTMLTransitions(path, None) 1352 1353 # Generate transition tables 1354 for state in self.states.itervalues(): 1355 self.printHTMLTransitions(path, state) 1356 1357 # Generate action descriptions 1358 for action in self.actions.itervalues(): 1359 name = "%s_action_%s.html" % (self.ident, action.ident) 1360 code = html.createSymbol(action, "Action") 1361 code.write(path, name) 1362 1363 # Generate state descriptions 1364 for state in self.states.itervalues(): 1365 name = "%s_State_%s.html" % (self.ident, state.ident) 1366 code = html.createSymbol(state, "State") 1367 code.write(path, name) 1368 1369 # Generate event descriptions 1370 for event in self.events.itervalues(): 1371 name = "%s_Event_%s.html" % (self.ident, event.ident) 1372 code = html.createSymbol(event, "Event") 1373 code.write(path, name) 1374 1375 def printHTMLTransitions(self, path, active_state): 1376 code = self.symtab.codeFormatter() 1377 1378 code(''' 1379<HTML> 1380<BODY link="blue" vlink="blue"> 1381 1382<H1 align="center">${{html.formatShorthand(self.short)}}: 1383''') 1384 code.indent() 1385 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1386 mid = machine.ident 1387 if i != 0: 1388 extra = " - " 1389 else: 1390 extra = "" 1391 if machine == self: 1392 code('$extra$mid') 1393 else: 1394 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1395 code.dedent() 1396 1397 code(""" 1398</H1> 1399 1400<TABLE border=1> 1401<TR> 1402 <TH> </TH> 1403""") 1404 1405 for event in self.events.itervalues(): 1406 href = "%s_Event_%s.html" % (self.ident, event.ident) 1407 ref = self.frameRef(href, "Status", href, "1", event.short) 1408 code('<TH bgcolor=white>$ref</TH>') 1409 1410 code('</TR>') 1411 # -- Body of table 1412 for state in self.states.itervalues(): 1413 # -- Each row 1414 if state == active_state: 1415 color = "yellow" 1416 else: 1417 color = "white" 1418 1419 click = "%s_table_%s.html" % (self.ident, state.ident) 1420 over = "%s_State_%s.html" % (self.ident, state.ident) 1421 text = html.formatShorthand(state.short) 1422 ref = self.frameRef(click, "Table", over, "1", state.short) 1423 code(''' 1424<TR> 1425 <TH bgcolor=$color>$ref</TH> 1426''') 1427 1428 # -- One column for each event 1429 for event in self.events.itervalues(): 1430 trans = self.table.get((state,event), None) 1431 if trans is None: 1432 # This is the no transition case 1433 if state == active_state: 1434 color = "#C0C000" 1435 else: 1436 color = "lightgrey" 1437 1438 code('<TD bgcolor=$color> </TD>') 1439 continue 1440 1441 next = trans.nextState 1442 stall_action = False 1443 1444 # -- Get the actions 1445 for action in trans.actions: 1446 if action.ident == "z_stall" or \ 1447 action.ident == "zz_recycleMandatoryQueue": 1448 stall_action = True 1449 1450 # -- Print out "actions/next-state" 1451 if stall_action: 1452 if state == active_state: 1453 color = "#C0C000" 1454 else: 1455 color = "lightgrey" 1456 1457 elif active_state and next.ident == active_state.ident: 1458 color = "aqua" 1459 elif state == active_state: 1460 color = "yellow" 1461 else: 1462 color = "white" 1463 1464 code('<TD bgcolor=$color>') 1465 for action in trans.actions: 1466 href = "%s_action_%s.html" % (self.ident, action.ident) 1467 ref = self.frameRef(href, "Status", href, "1", 1468 action.short) 1469 code(' $ref') 1470 if next != state: 1471 if trans.actions: 1472 code('/') 1473 click = "%s_table_%s.html" % (self.ident, next.ident) 1474 over = "%s_State_%s.html" % (self.ident, next.ident) 1475 ref = self.frameRef(click, "Table", over, "1", next.short) 1476 code("$ref") 1477 code("</TD>") 1478 1479 # -- Each row 1480 if state == active_state: 1481 color = "yellow" 1482 else: 1483 color = "white" 1484 1485 click = "%s_table_%s.html" % (self.ident, state.ident) 1486 over = "%s_State_%s.html" % (self.ident, state.ident) 1487 ref = self.frameRef(click, "Table", over, "1", state.short) 1488 code(''' 1489 <TH bgcolor=$color>$ref</TH> 1490</TR> 1491''') 1492 code(''' 1493<!- Column footer-> 1494<TR> 1495 <TH> </TH> 1496''') 1497 1498 for event in self.events.itervalues(): 1499 href = "%s_Event_%s.html" % (self.ident, event.ident) 1500 ref = self.frameRef(href, "Status", href, "1", event.short) 1501 code('<TH bgcolor=white>$ref</TH>') 1502 code(''' 1503</TR> 1504</TABLE> 1505</BODY></HTML> 1506''') 1507 1508 1509 if active_state: 1510 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1511 else: 1512 name = "%s_table.html" % self.ident 1513 code.write(path, name) 1514 1515__all__ = [ "StateMachine" ] 1516