StateMachine.py revision 11118
16928SBrad.Beckmann@amd.com# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 26928SBrad.Beckmann@amd.com# Copyright (c) 2009 The Hewlett-Packard Development Company 36928SBrad.Beckmann@amd.com# Copyright (c) 2013 Advanced Micro Devices, Inc. 46928SBrad.Beckmann@amd.com# All rights reserved. 56928SBrad.Beckmann@amd.com# 66928SBrad.Beckmann@amd.com# Redistribution and use in source and binary forms, with or without 76928SBrad.Beckmann@amd.com# modification, are permitted provided that the following conditions are 86928SBrad.Beckmann@amd.com# met: redistributions of source code must retain the above copyright 96928SBrad.Beckmann@amd.com# notice, this list of conditions and the following disclaimer; 106928SBrad.Beckmann@amd.com# redistributions in binary form must reproduce the above copyright 116928SBrad.Beckmann@amd.com# notice, this list of conditions and the following disclaimer in the 126928SBrad.Beckmann@amd.com# documentation and/or other materials provided with the distribution; 136928SBrad.Beckmann@amd.com# neither the name of the copyright holders nor the names of its 146928SBrad.Beckmann@amd.com# contributors may be used to endorse or promote products derived from 156928SBrad.Beckmann@amd.com# this software without specific prior written permission. 166928SBrad.Beckmann@amd.com# 176928SBrad.Beckmann@amd.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 186928SBrad.Beckmann@amd.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 196928SBrad.Beckmann@amd.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 206928SBrad.Beckmann@amd.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 216928SBrad.Beckmann@amd.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 226928SBrad.Beckmann@amd.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 236928SBrad.Beckmann@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 246928SBrad.Beckmann@amd.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 256928SBrad.Beckmann@amd.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 266928SBrad.Beckmann@amd.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 276928SBrad.Beckmann@amd.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286928SBrad.Beckmann@amd.com 296928SBrad.Beckmann@amd.comfrom m5.util import orderdict 306928SBrad.Beckmann@amd.com 316928SBrad.Beckmann@amd.comfrom slicc.symbols.Symbol import Symbol 326928SBrad.Beckmann@amd.comfrom slicc.symbols.Var import Var 336928SBrad.Beckmann@amd.comimport slicc.generate.html as html 346928SBrad.Beckmann@amd.comimport re 356928SBrad.Beckmann@amd.com 366928SBrad.Beckmann@amd.compython_class_map = { 3711670Sandreas.hansson@arm.com "int": "Int", 386928SBrad.Beckmann@amd.com "uint32_t" : "UInt32", 3911670Sandreas.hansson@arm.com "std::string": "String", 4011682Sandreas.hansson@arm.com "bool": "Bool", 416928SBrad.Beckmann@amd.com "CacheMemory": "RubyCache", 426928SBrad.Beckmann@amd.com "WireBuffer": "RubyWireBuffer", 438920Snilay@cs.wisc.edu "Sequencer": "RubySequencer", 446928SBrad.Beckmann@amd.com "DirectoryMemory": "RubyDirectoryMemory", 457570SBrad.Beckmann@amd.com "MemoryControl": "MemoryControl", 467570SBrad.Beckmann@amd.com "MessageBuffer": "MessageBuffer", 476928SBrad.Beckmann@amd.com "DMASequencer": "DMASequencer", 486928SBrad.Beckmann@amd.com "Prefetcher":"Prefetcher", 496928SBrad.Beckmann@amd.com "Cycles":"Cycles", 506928SBrad.Beckmann@amd.com } 517570SBrad.Beckmann@amd.com 527570SBrad.Beckmann@amd.comclass StateMachine(Symbol): 537570SBrad.Beckmann@amd.com def __init__(self, symtab, ident, location, pairs, config_parameters): 547570SBrad.Beckmann@amd.com super(StateMachine, self).__init__(symtab, ident, location, pairs) 557570SBrad.Beckmann@amd.com self.table = None 567570SBrad.Beckmann@amd.com 577570SBrad.Beckmann@amd.com # Data members in the State Machine that have been declared before 587570SBrad.Beckmann@amd.com # the opening brace '{' of the machine. Note that these along with 597570SBrad.Beckmann@amd.com # the members in self.objects form the entire set of data members. 607570SBrad.Beckmann@amd.com self.config_parameters = config_parameters 617570SBrad.Beckmann@amd.com 629841Snilay@cs.wisc.edu self.prefetchers = [] 637570SBrad.Beckmann@amd.com 648933SBrad.Beckmann@amd.com for param in config_parameters: 658933SBrad.Beckmann@amd.com if param.pointer: 668933SBrad.Beckmann@amd.com var = Var(symtab, param.ident, location, param.type_ast.type, 678933SBrad.Beckmann@amd.com "(*m_%s_ptr)" % param.ident, {}, self) 688933SBrad.Beckmann@amd.com else: 697570SBrad.Beckmann@amd.com var = Var(symtab, param.ident, location, param.type_ast.type, 706928SBrad.Beckmann@amd.com "m_%s" % param.ident, {}, self) 716928SBrad.Beckmann@amd.com 728933SBrad.Beckmann@amd.com self.symtab.registerSym(param.ident, var) 738940SBrad.Beckmann@amd.com 746928SBrad.Beckmann@amd.com if str(param.type_ast.type) == "Prefetcher": 7510300Scastilloe@unican.es self.prefetchers.append(var) 7610300Scastilloe@unican.es 7710524Snilay@cs.wisc.edu self.states = orderdict() 7810300Scastilloe@unican.es self.events = orderdict() 799827Sakash.bagdia@arm.com self.actions = orderdict() 809827Sakash.bagdia@arm.com self.request_types = orderdict() 819827Sakash.bagdia@arm.com self.transitions = [] 829827Sakash.bagdia@arm.com self.in_ports = [] 836928SBrad.Beckmann@amd.com self.functions = [] 849826Sandreas.hansson@arm.com 859826Sandreas.hansson@arm.com # Data members in the State Machine that have been declared inside 8610519Snilay@cs.wisc.edu # the {} machine. Note that these along with the config params 876928SBrad.Beckmann@amd.com # form the entire set of data members of the machine. 889793Sakash.bagdia@arm.com self.objects = [] 899827Sakash.bagdia@arm.com self.TBEType = None 909827Sakash.bagdia@arm.com self.EntryType = None 919793Sakash.bagdia@arm.com self.debug_flags = set() 9210120Snilay@cs.wisc.edu self.debug_flags.add('RubyGenerated') 936928SBrad.Beckmann@amd.com self.debug_flags.add('RubySlicc') 9411267SBrad.Beckmann@amd.com 9511267SBrad.Beckmann@amd.com def __repr__(self): 966928SBrad.Beckmann@amd.com return "[StateMachine: %s]" % self.ident 976928SBrad.Beckmann@amd.com 986928SBrad.Beckmann@amd.com def addState(self, state): 996928SBrad.Beckmann@amd.com assert self.table is None 1006928SBrad.Beckmann@amd.com self.states[state.ident] = state 1016928SBrad.Beckmann@amd.com 10210120Snilay@cs.wisc.edu def addEvent(self, event): 1036928SBrad.Beckmann@amd.com assert self.table is None 1048940SBrad.Beckmann@amd.com self.events[event.ident] = event 1056928SBrad.Beckmann@amd.com 10611267SBrad.Beckmann@amd.com def addAction(self, action): 10711267SBrad.Beckmann@amd.com assert self.table is None 10811267SBrad.Beckmann@amd.com 10911267SBrad.Beckmann@amd.com # Check for duplicate action 11011267SBrad.Beckmann@amd.com for other in self.actions.itervalues(): 11111267SBrad.Beckmann@amd.com if action.ident == other.ident: 11211267SBrad.Beckmann@amd.com action.warning("Duplicate action definition: %s" % action.ident) 11311267SBrad.Beckmann@amd.com action.error("Duplicate action definition: %s" % action.ident) 11411267SBrad.Beckmann@amd.com if action.short == other.short: 1156928SBrad.Beckmann@amd.com other.warning("Duplicate action shorthand: %s" % other.ident) 1166928SBrad.Beckmann@amd.com other.warning(" shorthand = %s" % other.short) 1176928SBrad.Beckmann@amd.com action.warning("Duplicate action shorthand: %s" % action.ident) 1186928SBrad.Beckmann@amd.com action.error(" shorthand = %s" % action.short) 1196928SBrad.Beckmann@amd.com 1206928SBrad.Beckmann@amd.com self.actions[action.ident] = action 1216928SBrad.Beckmann@amd.com 1226928SBrad.Beckmann@amd.com def addDebugFlag(self, flag): 1236928SBrad.Beckmann@amd.com self.debug_flags.add(flag) 1246928SBrad.Beckmann@amd.com 1256928SBrad.Beckmann@amd.com def addRequestType(self, request_type): 1268801Sgblack@eecs.umich.edu assert self.table is None 1276928SBrad.Beckmann@amd.com self.request_types[request_type.ident] = request_type 1286928SBrad.Beckmann@amd.com 1296928SBrad.Beckmann@amd.com def addTransition(self, trans): 1306928SBrad.Beckmann@amd.com assert self.table is None 131 self.transitions.append(trans) 132 133 def addInPort(self, var): 134 self.in_ports.append(var) 135 136 def addFunc(self, func): 137 # register func in the symbol table 138 self.symtab.registerSym(str(func), func) 139 self.functions.append(func) 140 141 def addObject(self, obj): 142 self.symtab.registerSym(str(obj), obj) 143 self.objects.append(obj) 144 145 def addType(self, type): 146 type_ident = '%s' % type.c_ident 147 148 if type_ident == "%s_TBE" %self.ident: 149 if self.TBEType != None: 150 self.error("Multiple Transaction Buffer types in a " \ 151 "single machine."); 152 self.TBEType = type 153 154 elif "interface" in type and "AbstractCacheEntry" == type["interface"]: 155 if "main" in type and "false" == type["main"].lower(): 156 pass # this isn't the EntryType 157 else: 158 if self.EntryType != None: 159 self.error("Multiple AbstractCacheEntry types in a " \ 160 "single machine."); 161 self.EntryType = type 162 163 # Needs to be called before accessing the table 164 def buildTable(self): 165 assert self.table is None 166 167 table = {} 168 169 for trans in self.transitions: 170 # Track which actions we touch so we know if we use them 171 # all -- really this should be done for all symbols as 172 # part of the symbol table, then only trigger it for 173 # Actions, States, Events, etc. 174 175 for action in trans.actions: 176 action.used = True 177 178 index = (trans.state, trans.event) 179 if index in table: 180 table[index].warning("Duplicate transition: %s" % table[index]) 181 trans.error("Duplicate transition: %s" % trans) 182 table[index] = trans 183 184 # Look at all actions to make sure we used them all 185 for action in self.actions.itervalues(): 186 if not action.used: 187 error_msg = "Unused action: %s" % action.ident 188 if "desc" in action: 189 error_msg += ", " + action.desc 190 action.warning(error_msg) 191 self.table = table 192 193 # determine the port->msg buffer mappings 194 def getBufferMaps(self, ident): 195 msg_bufs = [] 196 port_to_buf_map = {} 197 in_msg_bufs = {} 198 for port in self.in_ports: 199 buf_name = "m_%s_ptr" % port.pairs["buffer_expr"].name 200 msg_bufs.append(buf_name) 201 port_to_buf_map[port] = msg_bufs.index(buf_name) 202 if buf_name not in in_msg_bufs: 203 in_msg_bufs[buf_name] = [port] 204 else: 205 in_msg_bufs[buf_name].append(port) 206 return port_to_buf_map, in_msg_bufs, msg_bufs 207 208 def writeCodeFiles(self, path, includes): 209 self.printControllerPython(path) 210 self.printControllerHH(path) 211 self.printControllerCC(path, includes) 212 self.printCSwitch(path) 213 self.printCWakeup(path, includes) 214 215 def printControllerPython(self, path): 216 code = self.symtab.codeFormatter() 217 ident = self.ident 218 219 py_ident = "%s_Controller" % ident 220 c_ident = "%s_Controller" % self.ident 221 222 code(''' 223from m5.params import * 224from m5.SimObject import SimObject 225from Controller import RubyController 226 227class $py_ident(RubyController): 228 type = '$py_ident' 229 cxx_header = 'mem/protocol/${c_ident}.hh' 230''') 231 code.indent() 232 for param in self.config_parameters: 233 dflt_str = '' 234 235 if param.rvalue is not None: 236 dflt_str = str(param.rvalue.inline()) + ', ' 237 238 if python_class_map.has_key(param.type_ast.type.c_ident): 239 python_type = python_class_map[param.type_ast.type.c_ident] 240 code('${{param.ident}} = Param.${{python_type}}(${dflt_str}"")') 241 242 else: 243 self.error("Unknown c++ to python class conversion for c++ " \ 244 "type: '%s'. Please update the python_class_map " \ 245 "in StateMachine.py", param.type_ast.type.c_ident) 246 247 code.dedent() 248 code.write(path, '%s.py' % py_ident) 249 250 251 def printControllerHH(self, path): 252 '''Output the method declarations for the class declaration''' 253 code = self.symtab.codeFormatter() 254 ident = self.ident 255 c_ident = "%s_Controller" % self.ident 256 257 code(''' 258/** \\file $c_ident.hh 259 * 260 * Auto generated C++ code started by $__file__:$__line__ 261 * Created by slicc definition of Module "${{self.short}}" 262 */ 263 264#ifndef __${ident}_CONTROLLER_HH__ 265#define __${ident}_CONTROLLER_HH__ 266 267#include <iostream> 268#include <sstream> 269#include <string> 270 271#include "mem/protocol/TransitionResult.hh" 272#include "mem/protocol/Types.hh" 273#include "mem/ruby/common/Consumer.hh" 274#include "mem/ruby/slicc_interface/AbstractController.hh" 275#include "params/$c_ident.hh" 276 277''') 278 279 seen_types = set() 280 for var in self.objects: 281 if var.type.ident not in seen_types and not var.type.isPrimitive: 282 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 283 seen_types.add(var.type.ident) 284 285 # for adding information to the protocol debug trace 286 code(''' 287extern std::stringstream ${ident}_transitionComment; 288 289class $c_ident : public AbstractController 290{ 291 public: 292 typedef ${c_ident}Params Params; 293 $c_ident(const Params *p); 294 static int getNumControllers(); 295 void init(); 296 297 MessageBuffer *getMandatoryQueue() const; 298 MessageBuffer *getMemoryQueue() const; 299 void initNetQueues(); 300 301 void print(std::ostream& out) const; 302 void wakeup(); 303 void resetStats(); 304 void regStats(); 305 void collateStats(); 306 307 void recordCacheTrace(int cntrl, CacheRecorder* tr); 308 Sequencer* getSequencer() const; 309 310 int functionalWriteBuffers(PacketPtr&); 311 312 void countTransition(${ident}_State state, ${ident}_Event event); 313 void possibleTransition(${ident}_State state, ${ident}_Event event); 314 uint64_t getEventCount(${ident}_Event event); 315 bool isPossible(${ident}_State state, ${ident}_Event event); 316 uint64_t getTransitionCount(${ident}_State state, ${ident}_Event event); 317 318private: 319''') 320 321 code.indent() 322 # added by SS 323 for param in self.config_parameters: 324 if param.pointer: 325 code('${{param.type_ast.type}}* m_${{param.ident}}_ptr;') 326 else: 327 code('${{param.type_ast.type}} m_${{param.ident}};') 328 329 code(''' 330TransitionResult doTransition(${ident}_Event event, 331''') 332 333 if self.EntryType != None: 334 code(''' 335 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 336''') 337 if self.TBEType != None: 338 code(''' 339 ${{self.TBEType.c_ident}}* m_tbe_ptr, 340''') 341 342 code(''' 343 Addr addr); 344 345TransitionResult doTransitionWorker(${ident}_Event event, 346 ${ident}_State state, 347 ${ident}_State& next_state, 348''') 349 350 if self.TBEType != None: 351 code(''' 352 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 353''') 354 if self.EntryType != None: 355 code(''' 356 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 357''') 358 359 code(''' 360 Addr addr); 361 362int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 363int m_event_counters[${ident}_Event_NUM]; 364bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 365 366static std::vector<Stats::Vector *> eventVec; 367static std::vector<std::vector<Stats::Vector *> > transVec; 368static int m_num_controllers; 369 370// Internal functions 371''') 372 373 for func in self.functions: 374 proto = func.prototype 375 if proto: 376 code('$proto') 377 378 if self.EntryType != None: 379 code(''' 380 381// Set and Reset for cache_entry variable 382void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); 383void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); 384''') 385 386 if self.TBEType != None: 387 code(''' 388 389// Set and Reset for tbe variable 390void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); 391void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); 392''') 393 394 # Prototype the actions that the controller can take 395 code(''' 396 397// Actions 398''') 399 if self.TBEType != None and self.EntryType != None: 400 for action in self.actions.itervalues(): 401 code('/** \\brief ${{action.desc}} */') 402 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 403 'm_tbe_ptr, ${{self.EntryType.c_ident}}*& ' 404 'm_cache_entry_ptr, Addr addr);') 405 elif self.TBEType != None: 406 for action in self.actions.itervalues(): 407 code('/** \\brief ${{action.desc}} */') 408 code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& ' 409 'm_tbe_ptr, Addr addr);') 410 elif self.EntryType != None: 411 for action in self.actions.itervalues(): 412 code('/** \\brief ${{action.desc}} */') 413 code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& ' 414 'm_cache_entry_ptr, Addr addr);') 415 else: 416 for action in self.actions.itervalues(): 417 code('/** \\brief ${{action.desc}} */') 418 code('void ${{action.ident}}(Addr addr);') 419 420 # the controller internal variables 421 code(''' 422 423// Objects 424''') 425 for var in self.objects: 426 th = var.get("template", "") 427 code('${{var.type.c_ident}}$th* m_${{var.ident}}_ptr;') 428 429 code.dedent() 430 code('};') 431 code('#endif // __${ident}_CONTROLLER_H__') 432 code.write(path, '%s.hh' % c_ident) 433 434 def printControllerCC(self, path, includes): 435 '''Output the actions for performing the actions''' 436 437 code = self.symtab.codeFormatter() 438 ident = self.ident 439 c_ident = "%s_Controller" % self.ident 440 441 code(''' 442/** \\file $c_ident.cc 443 * 444 * Auto generated C++ code started by $__file__:$__line__ 445 * Created by slicc definition of Module "${{self.short}}" 446 */ 447 448#include <sys/types.h> 449#include <unistd.h> 450 451#include <cassert> 452#include <sstream> 453#include <string> 454#include <typeinfo> 455 456#include "base/compiler.hh" 457#include "base/cprintf.hh" 458 459''') 460 for f in self.debug_flags: 461 code('#include "debug/${{f}}.hh"') 462 code(''' 463#include "mem/protocol/${ident}_Controller.hh" 464#include "mem/protocol/${ident}_Event.hh" 465#include "mem/protocol/${ident}_State.hh" 466#include "mem/protocol/Types.hh" 467#include "mem/ruby/system/RubySystem.hh" 468 469''') 470 for include_path in includes: 471 code('#include "${{include_path}}"') 472 473 code(''' 474 475using namespace std; 476''') 477 478 # include object classes 479 seen_types = set() 480 for var in self.objects: 481 if var.type.ident not in seen_types and not var.type.isPrimitive: 482 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 483 seen_types.add(var.type.ident) 484 485 num_in_ports = len(self.in_ports) 486 487 code(''' 488$c_ident * 489${c_ident}Params::create() 490{ 491 return new $c_ident(this); 492} 493 494int $c_ident::m_num_controllers = 0; 495std::vector<Stats::Vector *> $c_ident::eventVec; 496std::vector<std::vector<Stats::Vector *> > $c_ident::transVec; 497 498// for adding information to the protocol debug trace 499stringstream ${ident}_transitionComment; 500 501#ifndef NDEBUG 502#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 503#else 504#define APPEND_TRANSITION_COMMENT(str) do {} while (0) 505#endif 506 507/** \\brief constructor */ 508$c_ident::$c_ident(const Params *p) 509 : AbstractController(p) 510{ 511 m_machineID.type = MachineType_${ident}; 512 m_machineID.num = m_version; 513 m_num_controllers++; 514 515 m_in_ports = $num_in_ports; 516''') 517 code.indent() 518 519 # 520 # After initializing the universal machine parameters, initialize the 521 # this machines config parameters. Also if these configuration params 522 # include a sequencer, connect the it to the controller. 523 # 524 for param in self.config_parameters: 525 if param.pointer: 526 code('m_${{param.ident}}_ptr = p->${{param.ident}};') 527 else: 528 code('m_${{param.ident}} = p->${{param.ident}};') 529 530 if re.compile("sequencer").search(param.ident): 531 code('m_${{param.ident}}_ptr->setController(this);') 532 533 code(''' 534 535for (int state = 0; state < ${ident}_State_NUM; state++) { 536 for (int event = 0; event < ${ident}_Event_NUM; event++) { 537 m_possible[state][event] = false; 538 m_counters[state][event] = 0; 539 } 540} 541for (int event = 0; event < ${ident}_Event_NUM; event++) { 542 m_event_counters[event] = 0; 543} 544''') 545 code.dedent() 546 code(''' 547} 548 549void 550$c_ident::initNetQueues() 551{ 552 MachineType machine_type = string_to_MachineType("${{self.ident}}"); 553 int base M5_VAR_USED = MachineType_base_number(machine_type); 554 555''') 556 code.indent() 557 558 # set for maintaining the vnet, direction pairs already seen for this 559 # machine. This map helps in implementing the check for avoiding 560 # multiple message buffers being mapped to the same vnet. 561 vnet_dir_set = set() 562 563 for var in self.config_parameters: 564 vid = "m_%s_ptr" % var.ident 565 if "network" in var: 566 vtype = var.type_ast.type 567 code('assert($vid != NULL);') 568 569 # Network port object 570 network = var["network"] 571 572 if "virtual_network" in var: 573 vnet = var["virtual_network"] 574 vnet_type = var["vnet_type"] 575 576 assert (vnet, network) not in vnet_dir_set 577 vnet_dir_set.add((vnet,network)) 578 579 code(''' 580m_net_ptr->set${network}NetQueue(m_version + base, $vid->getOrdered(), $vnet, 581 "$vnet_type", $vid); 582''') 583 # Set Priority 584 if "rank" in var: 585 code('$vid->setPriority(${{var["rank"]}})') 586 587 code.dedent() 588 code(''' 589} 590 591void 592$c_ident::init() 593{ 594 // initialize objects 595''') 596 597 code.indent() 598 599 for var in self.objects: 600 vtype = var.type 601 vid = "m_%s_ptr" % var.ident 602 if "network" not in var: 603 # Not a network port object 604 if "primitive" in vtype: 605 code('$vid = new ${{vtype.c_ident}};') 606 if "default" in var: 607 code('(*$vid) = ${{var["default"]}};') 608 else: 609 # Normal Object 610 th = var.get("template", "") 611 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 612 args = "" 613 if "non_obj" not in vtype and not vtype.isEnumeration: 614 args = var.get("constructor", "") 615 616 code('$expr($args);') 617 code('assert($vid != NULL);') 618 619 if "default" in var: 620 code('*$vid = ${{var["default"]}}; // Object default') 621 elif "default" in vtype: 622 comment = "Type %s default" % vtype.ident 623 code('*$vid = ${{vtype["default"]}}; // $comment') 624 625 # Set the prefetchers 626 code() 627 for prefetcher in self.prefetchers: 628 code('${{prefetcher.code}}.setController(this);') 629 630 code() 631 for port in self.in_ports: 632 # Set the queue consumers 633 code('${{port.code}}.setConsumer(this);') 634 635 # Initialize the transition profiling 636 code() 637 for trans in self.transitions: 638 # Figure out if we stall 639 stall = False 640 for action in trans.actions: 641 if action.ident == "z_stall": 642 stall = True 643 644 # Only possible if it is not a 'z' case 645 if not stall: 646 state = "%s_State_%s" % (self.ident, trans.state.ident) 647 event = "%s_Event_%s" % (self.ident, trans.event.ident) 648 code('possibleTransition($state, $event);') 649 650 code.dedent() 651 code(''' 652 AbstractController::init(); 653 resetStats(); 654} 655''') 656 657 mq_ident = "NULL" 658 for port in self.in_ports: 659 if port.code.find("mandatoryQueue_ptr") >= 0: 660 mq_ident = "m_mandatoryQueue_ptr" 661 662 memq_ident = "NULL" 663 for port in self.in_ports: 664 if port.code.find("responseFromMemory_ptr") >= 0: 665 memq_ident = "m_responseFromMemory_ptr" 666 667 seq_ident = "NULL" 668 for param in self.config_parameters: 669 if param.ident == "sequencer": 670 assert(param.pointer) 671 seq_ident = "m_%s_ptr" % param.ident 672 673 code(''' 674 675void 676$c_ident::regStats() 677{ 678 AbstractController::regStats(); 679 680 if (m_version == 0) { 681 for (${ident}_Event event = ${ident}_Event_FIRST; 682 event < ${ident}_Event_NUM; ++event) { 683 Stats::Vector *t = new Stats::Vector(); 684 t->init(m_num_controllers); 685 t->name(params()->ruby_system->name() + ".${c_ident}." + 686 ${ident}_Event_to_string(event)); 687 t->flags(Stats::pdf | Stats::total | Stats::oneline | 688 Stats::nozero); 689 690 eventVec.push_back(t); 691 } 692 693 for (${ident}_State state = ${ident}_State_FIRST; 694 state < ${ident}_State_NUM; ++state) { 695 696 transVec.push_back(std::vector<Stats::Vector *>()); 697 698 for (${ident}_Event event = ${ident}_Event_FIRST; 699 event < ${ident}_Event_NUM; ++event) { 700 701 Stats::Vector *t = new Stats::Vector(); 702 t->init(m_num_controllers); 703 t->name(params()->ruby_system->name() + ".${c_ident}." + 704 ${ident}_State_to_string(state) + 705 "." + ${ident}_Event_to_string(event)); 706 707 t->flags(Stats::pdf | Stats::total | Stats::oneline | 708 Stats::nozero); 709 transVec[state].push_back(t); 710 } 711 } 712 } 713} 714 715void 716$c_ident::collateStats() 717{ 718 for (${ident}_Event event = ${ident}_Event_FIRST; 719 event < ${ident}_Event_NUM; ++event) { 720 for (unsigned int i = 0; i < m_num_controllers; ++i) { 721 RubySystem *rs = params()->ruby_system; 722 std::map<uint32_t, AbstractController *>::iterator it = 723 rs->m_abstract_controls[MachineType_${ident}].find(i); 724 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 725 (*eventVec[event])[i] = 726 (($c_ident *)(*it).second)->getEventCount(event); 727 } 728 } 729 730 for (${ident}_State state = ${ident}_State_FIRST; 731 state < ${ident}_State_NUM; ++state) { 732 733 for (${ident}_Event event = ${ident}_Event_FIRST; 734 event < ${ident}_Event_NUM; ++event) { 735 736 for (unsigned int i = 0; i < m_num_controllers; ++i) { 737 RubySystem *rs = params()->ruby_system; 738 std::map<uint32_t, AbstractController *>::iterator it = 739 rs->m_abstract_controls[MachineType_${ident}].find(i); 740 assert(it != rs->m_abstract_controls[MachineType_${ident}].end()); 741 (*transVec[state][event])[i] = 742 (($c_ident *)(*it).second)->getTransitionCount(state, event); 743 } 744 } 745 } 746} 747 748void 749$c_ident::countTransition(${ident}_State state, ${ident}_Event event) 750{ 751 assert(m_possible[state][event]); 752 m_counters[state][event]++; 753 m_event_counters[event]++; 754} 755void 756$c_ident::possibleTransition(${ident}_State state, 757 ${ident}_Event event) 758{ 759 m_possible[state][event] = true; 760} 761 762uint64_t 763$c_ident::getEventCount(${ident}_Event event) 764{ 765 return m_event_counters[event]; 766} 767 768bool 769$c_ident::isPossible(${ident}_State state, ${ident}_Event event) 770{ 771 return m_possible[state][event]; 772} 773 774uint64_t 775$c_ident::getTransitionCount(${ident}_State state, 776 ${ident}_Event event) 777{ 778 return m_counters[state][event]; 779} 780 781int 782$c_ident::getNumControllers() 783{ 784 return m_num_controllers; 785} 786 787MessageBuffer* 788$c_ident::getMandatoryQueue() const 789{ 790 return $mq_ident; 791} 792 793MessageBuffer* 794$c_ident::getMemoryQueue() const 795{ 796 return $memq_ident; 797} 798 799Sequencer* 800$c_ident::getSequencer() const 801{ 802 return $seq_ident; 803} 804 805void 806$c_ident::print(ostream& out) const 807{ 808 out << "[$c_ident " << m_version << "]"; 809} 810 811void $c_ident::resetStats() 812{ 813 for (int state = 0; state < ${ident}_State_NUM; state++) { 814 for (int event = 0; event < ${ident}_Event_NUM; event++) { 815 m_counters[state][event] = 0; 816 } 817 } 818 819 for (int event = 0; event < ${ident}_Event_NUM; event++) { 820 m_event_counters[event] = 0; 821 } 822 823 AbstractController::resetStats(); 824} 825''') 826 827 if self.EntryType != None: 828 code(''' 829 830// Set and Reset for cache_entry variable 831void 832$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) 833{ 834 m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; 835} 836 837void 838$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) 839{ 840 m_cache_entry_ptr = 0; 841} 842''') 843 844 if self.TBEType != None: 845 code(''' 846 847// Set and Reset for tbe variable 848void 849$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) 850{ 851 m_tbe_ptr = m_new_tbe; 852} 853 854void 855$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) 856{ 857 m_tbe_ptr = NULL; 858} 859''') 860 861 code(''' 862 863void 864$c_ident::recordCacheTrace(int cntrl, CacheRecorder* tr) 865{ 866''') 867 # 868 # Record cache contents for all associated caches. 869 # 870 code.indent() 871 for param in self.config_parameters: 872 if param.type_ast.type.ident == "CacheMemory": 873 assert(param.pointer) 874 code('m_${{param.ident}}_ptr->recordCacheContents(cntrl, tr);') 875 876 code.dedent() 877 code(''' 878} 879 880// Actions 881''') 882 if self.TBEType != None and self.EntryType != None: 883 for action in self.actions.itervalues(): 884 if "c_code" not in action: 885 continue 886 887 code(''' 888/** \\brief ${{action.desc}} */ 889void 890$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 891{ 892 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 893 try { 894 ${{action["c_code"]}} 895 } catch (const RejectException & e) { 896 fatal("Error in action ${{ident}}:${{action.ident}}: " 897 "executed a peek statement with the wrong message " 898 "type specified. "); 899 } 900} 901 902''') 903 elif self.TBEType != None: 904 for action in self.actions.itervalues(): 905 if "c_code" not in action: 906 continue 907 908 code(''' 909/** \\brief ${{action.desc}} */ 910void 911$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, Addr addr) 912{ 913 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 914 ${{action["c_code"]}} 915} 916 917''') 918 elif self.EntryType != None: 919 for action in self.actions.itervalues(): 920 if "c_code" not in action: 921 continue 922 923 code(''' 924/** \\brief ${{action.desc}} */ 925void 926$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, Addr addr) 927{ 928 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 929 ${{action["c_code"]}} 930} 931 932''') 933 else: 934 for action in self.actions.itervalues(): 935 if "c_code" not in action: 936 continue 937 938 code(''' 939/** \\brief ${{action.desc}} */ 940void 941$c_ident::${{action.ident}}(Addr addr) 942{ 943 DPRINTF(RubyGenerated, "executing ${{action.ident}}\\n"); 944 ${{action["c_code"]}} 945} 946 947''') 948 for func in self.functions: 949 code(func.generateCode()) 950 951 # Function for functional writes to messages buffered in the controller 952 code(''' 953int 954$c_ident::functionalWriteBuffers(PacketPtr& pkt) 955{ 956 int num_functional_writes = 0; 957''') 958 for var in self.objects: 959 vtype = var.type 960 if vtype.isBuffer: 961 vid = "m_%s_ptr" % var.ident 962 code('num_functional_writes += $vid->functionalWrite(pkt);') 963 964 for var in self.config_parameters: 965 vtype = var.type_ast.type 966 if vtype.isBuffer: 967 vid = "m_%s_ptr" % var.ident 968 code('num_functional_writes += $vid->functionalWrite(pkt);') 969 970 code(''' 971 return num_functional_writes; 972} 973''') 974 975 code.write(path, "%s.cc" % c_ident) 976 977 def printCWakeup(self, path, includes): 978 '''Output the wakeup loop for the events''' 979 980 code = self.symtab.codeFormatter() 981 ident = self.ident 982 983 outputRequest_types = True 984 if len(self.request_types) == 0: 985 outputRequest_types = False 986 987 code(''' 988// Auto generated C++ code started by $__file__:$__line__ 989// ${ident}: ${{self.short}} 990 991#include <sys/types.h> 992#include <unistd.h> 993 994#include <cassert> 995#include <typeinfo> 996 997#include "base/misc.hh" 998 999''') 1000 for f in self.debug_flags: 1001 code('#include "debug/${{f}}.hh"') 1002 code(''' 1003#include "mem/protocol/${ident}_Controller.hh" 1004#include "mem/protocol/${ident}_Event.hh" 1005#include "mem/protocol/${ident}_State.hh" 1006 1007''') 1008 1009 if outputRequest_types: 1010 code('''#include "mem/protocol/${ident}_RequestType.hh"''') 1011 1012 code(''' 1013#include "mem/protocol/Types.hh" 1014#include "mem/ruby/system/RubySystem.hh" 1015 1016''') 1017 1018 1019 for include_path in includes: 1020 code('#include "${{include_path}}"') 1021 1022 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1023 1024 code(''' 1025 1026using namespace std; 1027 1028void 1029${ident}_Controller::wakeup() 1030{ 1031 int counter = 0; 1032 while (true) { 1033 unsigned char rejected[${{len(msg_bufs)}}]; 1034 memset(rejected, 0, sizeof(unsigned char)*${{len(msg_bufs)}}); 1035 // Some cases will put us into an infinite loop without this limit 1036 assert(counter <= m_transitions_per_cycle); 1037 if (counter == m_transitions_per_cycle) { 1038 // Count how often we are fully utilized 1039 m_fully_busy_cycles++; 1040 1041 // Wakeup in another cycle and try again 1042 scheduleEvent(Cycles(1)); 1043 break; 1044 } 1045''') 1046 1047 code.indent() 1048 code.indent() 1049 1050 # InPorts 1051 # 1052 for port in self.in_ports: 1053 code.indent() 1054 code('// ${ident}InPort $port') 1055 if port.pairs.has_key("rank"): 1056 code('m_cur_in_port = ${{port.pairs["rank"]}};') 1057 else: 1058 code('m_cur_in_port = 0;') 1059 if port in port_to_buf_map: 1060 code('try {') 1061 code.indent() 1062 code('${{port["c_code_in_port"]}}') 1063 1064 if port in port_to_buf_map: 1065 code.dedent() 1066 code(''' 1067 } catch (const RejectException & e) { 1068 rejected[${{port_to_buf_map[port]}}]++; 1069 } 1070''') 1071 code.dedent() 1072 code('') 1073 1074 code.dedent() 1075 code.dedent() 1076 code(''' 1077 // If we got this far, we have nothing left todo or something went 1078 // wrong''') 1079 for buf_name, ports in in_msg_bufs.items(): 1080 if len(ports) > 1: 1081 # only produce checks when a buffer is shared by multiple ports 1082 code(''' 1083 if (${{buf_name}}->isReady(clockEdge()) && rejected[${{port_to_buf_map[ports[0]]}}] == ${{len(ports)}}) 1084 { 1085 // no port claimed the message on the top of this buffer 1086 panic("Runtime Error at Ruby Time: %d. " 1087 "All ports rejected a message. " 1088 "You are probably sending a message type to this controller " 1089 "over a virtual network that do not define an in_port for " 1090 "the incoming message type.\\n", 1091 Cycles(1)); 1092 } 1093''') 1094 code(''' 1095 break; 1096 } 1097} 1098''') 1099 1100 code.write(path, "%s_Wakeup.cc" % self.ident) 1101 1102 def printCSwitch(self, path): 1103 '''Output switch statement for transition table''' 1104 1105 code = self.symtab.codeFormatter() 1106 ident = self.ident 1107 1108 code(''' 1109// Auto generated C++ code started by $__file__:$__line__ 1110// ${ident}: ${{self.short}} 1111 1112#include <cassert> 1113 1114#include "base/misc.hh" 1115#include "base/trace.hh" 1116#include "debug/ProtocolTrace.hh" 1117#include "debug/RubyGenerated.hh" 1118#include "mem/protocol/${ident}_Controller.hh" 1119#include "mem/protocol/${ident}_Event.hh" 1120#include "mem/protocol/${ident}_State.hh" 1121#include "mem/protocol/Types.hh" 1122#include "mem/ruby/system/RubySystem.hh" 1123 1124#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 1125 1126#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 1127#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 1128 1129TransitionResult 1130${ident}_Controller::doTransition(${ident}_Event event, 1131''') 1132 if self.EntryType != None: 1133 code(''' 1134 ${{self.EntryType.c_ident}}* m_cache_entry_ptr, 1135''') 1136 if self.TBEType != None: 1137 code(''' 1138 ${{self.TBEType.c_ident}}* m_tbe_ptr, 1139''') 1140 code(''' 1141 Addr addr) 1142{ 1143''') 1144 code.indent() 1145 1146 if self.TBEType != None and self.EntryType != None: 1147 code('${ident}_State state = getState(m_tbe_ptr, m_cache_entry_ptr, addr);') 1148 elif self.TBEType != None: 1149 code('${ident}_State state = getState(m_tbe_ptr, addr);') 1150 elif self.EntryType != None: 1151 code('${ident}_State state = getState(m_cache_entry_ptr, addr);') 1152 else: 1153 code('${ident}_State state = getState(addr);') 1154 1155 code(''' 1156${ident}_State next_state = state; 1157 1158DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %#x\\n", 1159 *this, curCycle(), ${ident}_State_to_string(state), 1160 ${ident}_Event_to_string(event), addr); 1161 1162TransitionResult result = 1163''') 1164 if self.TBEType != None and self.EntryType != None: 1165 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') 1166 elif self.TBEType != None: 1167 code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') 1168 elif self.EntryType != None: 1169 code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') 1170 else: 1171 code('doTransitionWorker(event, state, next_state, addr);') 1172 1173 port_to_buf_map, in_msg_bufs, msg_bufs = self.getBufferMaps(ident) 1174 1175 code(''' 1176 1177if (result == TransitionResult_Valid) { 1178 DPRINTF(RubyGenerated, "next_state: %s\\n", 1179 ${ident}_State_to_string(next_state)); 1180 countTransition(state, event); 1181 1182 DPRINTFR(ProtocolTrace, "%15d %3s %10s%20s %6s>%-6s %#x %s\\n", 1183 curTick(), m_version, "${ident}", 1184 ${ident}_Event_to_string(event), 1185 ${ident}_State_to_string(state), 1186 ${ident}_State_to_string(next_state), 1187 printAddress(addr), GET_TRANSITION_COMMENT()); 1188 1189 CLEAR_TRANSITION_COMMENT(); 1190''') 1191 if self.TBEType != None and self.EntryType != None: 1192 code('setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') 1193 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1194 elif self.TBEType != None: 1195 code('setState(m_tbe_ptr, addr, next_state);') 1196 code('setAccessPermission(addr, next_state);') 1197 elif self.EntryType != None: 1198 code('setState(m_cache_entry_ptr, addr, next_state);') 1199 code('setAccessPermission(m_cache_entry_ptr, addr, next_state);') 1200 else: 1201 code('setState(addr, next_state);') 1202 code('setAccessPermission(addr, next_state);') 1203 1204 code(''' 1205} else if (result == TransitionResult_ResourceStall) { 1206 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1207 curTick(), m_version, "${ident}", 1208 ${ident}_Event_to_string(event), 1209 ${ident}_State_to_string(state), 1210 ${ident}_State_to_string(next_state), 1211 printAddress(addr), "Resource Stall"); 1212} else if (result == TransitionResult_ProtocolStall) { 1213 DPRINTF(RubyGenerated, "stalling\\n"); 1214 DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\\n", 1215 curTick(), m_version, "${ident}", 1216 ${ident}_Event_to_string(event), 1217 ${ident}_State_to_string(state), 1218 ${ident}_State_to_string(next_state), 1219 printAddress(addr), "Protocol Stall"); 1220} 1221 1222return result; 1223''') 1224 code.dedent() 1225 code(''' 1226} 1227 1228TransitionResult 1229${ident}_Controller::doTransitionWorker(${ident}_Event event, 1230 ${ident}_State state, 1231 ${ident}_State& next_state, 1232''') 1233 1234 if self.TBEType != None: 1235 code(''' 1236 ${{self.TBEType.c_ident}}*& m_tbe_ptr, 1237''') 1238 if self.EntryType != None: 1239 code(''' 1240 ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, 1241''') 1242 code(''' 1243 Addr addr) 1244{ 1245 switch(HASH_FUN(state, event)) { 1246''') 1247 1248 # This map will allow suppress generating duplicate code 1249 cases = orderdict() 1250 1251 for trans in self.transitions: 1252 case_string = "%s_State_%s, %s_Event_%s" % \ 1253 (self.ident, trans.state.ident, self.ident, trans.event.ident) 1254 1255 case = self.symtab.codeFormatter() 1256 # Only set next_state if it changes 1257 if trans.state != trans.nextState: 1258 if trans.nextState.isWildcard(): 1259 # When * is encountered as an end state of a transition, 1260 # the next state is determined by calling the 1261 # machine-specific getNextState function. The next state 1262 # is determined before any actions of the transition 1263 # execute, and therefore the next state calculation cannot 1264 # depend on any of the transitionactions. 1265 case('next_state = getNextState(addr);') 1266 else: 1267 ns_ident = trans.nextState.ident 1268 case('next_state = ${ident}_State_${ns_ident};') 1269 1270 actions = trans.actions 1271 request_types = trans.request_types 1272 1273 # Check for resources 1274 case_sorter = [] 1275 res = trans.resources 1276 for key,val in res.iteritems(): 1277 val = ''' 1278if (!%s.areNSlotsAvailable(%s, clockEdge())) 1279 return TransitionResult_ResourceStall; 1280''' % (key.code, val) 1281 case_sorter.append(val) 1282 1283 # Check all of the request_types for resource constraints 1284 for request_type in request_types: 1285 val = ''' 1286if (!checkResourceAvailable(%s_RequestType_%s, addr)) { 1287 return TransitionResult_ResourceStall; 1288} 1289''' % (self.ident, request_type.ident) 1290 case_sorter.append(val) 1291 1292 # Emit the code sequences in a sorted order. This makes the 1293 # output deterministic (without this the output order can vary 1294 # since Map's keys() on a vector of pointers is not deterministic 1295 for c in sorted(case_sorter): 1296 case("$c") 1297 1298 # Record access types for this transition 1299 for request_type in request_types: 1300 case('recordRequestType(${ident}_RequestType_${{request_type.ident}}, addr);') 1301 1302 # Figure out if we stall 1303 stall = False 1304 for action in actions: 1305 if action.ident == "z_stall": 1306 stall = True 1307 break 1308 1309 if stall: 1310 case('return TransitionResult_ProtocolStall;') 1311 else: 1312 if self.TBEType != None and self.EntryType != None: 1313 for action in actions: 1314 case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') 1315 elif self.TBEType != None: 1316 for action in actions: 1317 case('${{action.ident}}(m_tbe_ptr, addr);') 1318 elif self.EntryType != None: 1319 for action in actions: 1320 case('${{action.ident}}(m_cache_entry_ptr, addr);') 1321 else: 1322 for action in actions: 1323 case('${{action.ident}}(addr);') 1324 case('return TransitionResult_Valid;') 1325 1326 case = str(case) 1327 1328 # Look to see if this transition code is unique. 1329 if case not in cases: 1330 cases[case] = [] 1331 1332 cases[case].append(case_string) 1333 1334 # Walk through all of the unique code blocks and spit out the 1335 # corresponding case statement elements 1336 for case,transitions in cases.iteritems(): 1337 # Iterative over all the multiple transitions that share 1338 # the same code 1339 for trans in transitions: 1340 code(' case HASH_FUN($trans):') 1341 code(' $case\n') 1342 1343 code(''' 1344 default: 1345 panic("Invalid transition\\n" 1346 "%s time: %d addr: %s event: %s state: %s\\n", 1347 name(), curCycle(), addr, event, state); 1348 } 1349 1350 return TransitionResult_Valid; 1351} 1352''') 1353 code.write(path, "%s_Transitions.cc" % self.ident) 1354 1355 1356 # ************************** 1357 # ******* HTML Files ******* 1358 # ************************** 1359 def frameRef(self, click_href, click_target, over_href, over_num, text): 1360 code = self.symtab.codeFormatter(fix_newlines=False) 1361 code("""<A href=\"$click_href\" target=\"$click_target\" onmouseover=\" 1362 if (parent.frames[$over_num].location != parent.location + '$over_href') { 1363 parent.frames[$over_num].location='$over_href' 1364 }\"> 1365 ${{html.formatShorthand(text)}} 1366 </A>""") 1367 return str(code) 1368 1369 def writeHTMLFiles(self, path): 1370 # Create table with no row hilighted 1371 self.printHTMLTransitions(path, None) 1372 1373 # Generate transition tables 1374 for state in self.states.itervalues(): 1375 self.printHTMLTransitions(path, state) 1376 1377 # Generate action descriptions 1378 for action in self.actions.itervalues(): 1379 name = "%s_action_%s.html" % (self.ident, action.ident) 1380 code = html.createSymbol(action, "Action") 1381 code.write(path, name) 1382 1383 # Generate state descriptions 1384 for state in self.states.itervalues(): 1385 name = "%s_State_%s.html" % (self.ident, state.ident) 1386 code = html.createSymbol(state, "State") 1387 code.write(path, name) 1388 1389 # Generate event descriptions 1390 for event in self.events.itervalues(): 1391 name = "%s_Event_%s.html" % (self.ident, event.ident) 1392 code = html.createSymbol(event, "Event") 1393 code.write(path, name) 1394 1395 def printHTMLTransitions(self, path, active_state): 1396 code = self.symtab.codeFormatter() 1397 1398 code(''' 1399<HTML> 1400<BODY link="blue" vlink="blue"> 1401 1402<H1 align="center">${{html.formatShorthand(self.short)}}: 1403''') 1404 code.indent() 1405 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 1406 mid = machine.ident 1407 if i != 0: 1408 extra = " - " 1409 else: 1410 extra = "" 1411 if machine == self: 1412 code('$extra$mid') 1413 else: 1414 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 1415 code.dedent() 1416 1417 code(""" 1418</H1> 1419 1420<TABLE border=1> 1421<TR> 1422 <TH> </TH> 1423""") 1424 1425 for event in self.events.itervalues(): 1426 href = "%s_Event_%s.html" % (self.ident, event.ident) 1427 ref = self.frameRef(href, "Status", href, "1", event.short) 1428 code('<TH bgcolor=white>$ref</TH>') 1429 1430 code('</TR>') 1431 # -- Body of table 1432 for state in self.states.itervalues(): 1433 # -- Each row 1434 if state == active_state: 1435 color = "yellow" 1436 else: 1437 color = "white" 1438 1439 click = "%s_table_%s.html" % (self.ident, state.ident) 1440 over = "%s_State_%s.html" % (self.ident, state.ident) 1441 text = html.formatShorthand(state.short) 1442 ref = self.frameRef(click, "Table", over, "1", state.short) 1443 code(''' 1444<TR> 1445 <TH bgcolor=$color>$ref</TH> 1446''') 1447 1448 # -- One column for each event 1449 for event in self.events.itervalues(): 1450 trans = self.table.get((state,event), None) 1451 if trans is None: 1452 # This is the no transition case 1453 if state == active_state: 1454 color = "#C0C000" 1455 else: 1456 color = "lightgrey" 1457 1458 code('<TD bgcolor=$color> </TD>') 1459 continue 1460 1461 next = trans.nextState 1462 stall_action = False 1463 1464 # -- Get the actions 1465 for action in trans.actions: 1466 if action.ident == "z_stall" or \ 1467 action.ident == "zz_recycleMandatoryQueue": 1468 stall_action = True 1469 1470 # -- Print out "actions/next-state" 1471 if stall_action: 1472 if state == active_state: 1473 color = "#C0C000" 1474 else: 1475 color = "lightgrey" 1476 1477 elif active_state and next.ident == active_state.ident: 1478 color = "aqua" 1479 elif state == active_state: 1480 color = "yellow" 1481 else: 1482 color = "white" 1483 1484 code('<TD bgcolor=$color>') 1485 for action in trans.actions: 1486 href = "%s_action_%s.html" % (self.ident, action.ident) 1487 ref = self.frameRef(href, "Status", href, "1", 1488 action.short) 1489 code(' $ref') 1490 if next != state: 1491 if trans.actions: 1492 code('/') 1493 click = "%s_table_%s.html" % (self.ident, next.ident) 1494 over = "%s_State_%s.html" % (self.ident, next.ident) 1495 ref = self.frameRef(click, "Table", over, "1", next.short) 1496 code("$ref") 1497 code("</TD>") 1498 1499 # -- Each row 1500 if state == active_state: 1501 color = "yellow" 1502 else: 1503 color = "white" 1504 1505 click = "%s_table_%s.html" % (self.ident, state.ident) 1506 over = "%s_State_%s.html" % (self.ident, state.ident) 1507 ref = self.frameRef(click, "Table", over, "1", state.short) 1508 code(''' 1509 <TH bgcolor=$color>$ref</TH> 1510</TR> 1511''') 1512 code(''' 1513<!- Column footer-> 1514<TR> 1515 <TH> </TH> 1516''') 1517 1518 for event in self.events.itervalues(): 1519 href = "%s_Event_%s.html" % (self.ident, event.ident) 1520 ref = self.frameRef(href, "Status", href, "1", event.short) 1521 code('<TH bgcolor=white>$ref</TH>') 1522 code(''' 1523</TR> 1524</TABLE> 1525</BODY></HTML> 1526''') 1527 1528 1529 if active_state: 1530 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1531 else: 1532 name = "%s_table.html" % self.ident 1533 code.write(path, name) 1534 1535__all__ = [ "StateMachine" ] 1536