1# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 2# Copyright (c) 2009 The Hewlett-Packard Development Company 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28from m5.util import code_formatter, orderdict 29 30from slicc.symbols.Symbol import Symbol 31from slicc.symbols.Var import Var 32import slicc.generate.html as html 33 34class StateMachine(Symbol): 35 def __init__(self, symtab, ident, location, pairs, config_parameters): 36 super(StateMachine, self).__init__(symtab, ident, location, pairs) 37 self.table = None 38 self.config_parameters = config_parameters 39 for param in config_parameters: 40 var = Var(symtab, param.name, location, param.type_ast.type, 41 "m_%s" % param.name, {}, self) 42 self.symtab.registerSym(param.name, var) 43 44 self.states = orderdict() 45 self.events = orderdict() 46 self.actions = orderdict() 47 self.transitions = [] 48 self.in_ports = [] 49 self.functions = [] 50 self.objects = [] 51 52 self.message_buffer_names = [] 53 54 def __repr__(self): 55 return "[StateMachine: %s]" % self.ident 56 57 def addState(self, state): 58 assert self.table is None 59 self.states[state.ident] = state 60 61 def addEvent(self, event): 62 assert self.table is None 63 self.events[event.ident] = event 64 65 def addAction(self, action): 66 assert self.table is None 67 68 # Check for duplicate action 69 for other in self.actions.itervalues(): 70 if action.ident == other.ident: 71 action.warning("Duplicate action definition: %s" % action.ident) 72 action.error("Duplicate action definition: %s" % action.ident) 73 if action.short == other.short: 74 other.warning("Duplicate action shorthand: %s" % other.ident) 75 other.warning(" shorthand = %s" % other.short) 76 action.warning("Duplicate action shorthand: %s" % action.ident) 77 action.error(" shorthand = %s" % action.short) 78 79 self.actions[action.ident] = action 80 81 def addTransition(self, trans): 82 assert self.table is None 83 self.transitions.append(trans) 84 85 def addInPort(self, var): 86 self.in_ports.append(var) 87 88 def addFunc(self, func): 89 # register func in the symbol table 90 self.symtab.registerSym(str(func), func) 91 self.functions.append(func) 92 93 def addObject(self, obj): 94 self.objects.append(obj) 95 96 # Needs to be called before accessing the table 97 def buildTable(self): 98 assert self.table is None 99 100 table = {} 101 102 for trans in self.transitions: 103 # Track which actions we touch so we know if we use them 104 # all -- really this should be done for all symbols as 105 # part of the symbol table, then only trigger it for 106 # Actions, States, Events, etc. 107 108 for action in trans.actions: 109 action.used = True 110 111 index = (trans.state, trans.event) 112 if index in table: 113 table[index].warning("Duplicate transition: %s" % table[index]) 114 trans.error("Duplicate transition: %s" % trans) 115 table[index] = trans 116 117 # Look at all actions to make sure we used them all 118 for action in self.actions.itervalues(): 119 if not action.used: 120 error_msg = "Unused action: %s" % action.ident 121 if "desc" in action: 122 error_msg += ", " + action.desc 123 action.warning(error_msg) 124 self.table = table 125 126 def writeCodeFiles(self, path):
|
127 self.printControllerPython(path) |
128 self.printControllerHH(path) 129 self.printControllerCC(path) 130 self.printCSwitch(path) 131 self.printCWakeup(path) 132 self.printProfilerCC(path) 133 self.printProfilerHH(path) 134 135 for func in self.functions: 136 func.writeCodeFiles(path) 137
|
138 def printControllerPython(self, path): 139 code = code_formatter() 140 ident = self.ident 141 py_ident = "%s_Controller" % ident 142 c_ident = "%s_Controller" % self.ident 143 code(''' 144from m5.params import * 145from m5.SimObject import SimObject 146from Controller import RubyController 147 148class $py_ident(RubyController): 149 type = '$py_ident' 150''') 151 code.indent() 152 for param in self.config_parameters: 153 dflt_str = '' 154 if param.default is not None: 155 dflt_str = str(param.default) + ', ' 156 code('${{param.name}} = Param.Int(${dflt_str}"")') 157 code.dedent() 158 code.write(path, '%s.py' % py_ident) 159 160 |
161 def printControllerHH(self, path): 162 '''Output the method declarations for the class declaration''' 163 code = code_formatter() 164 ident = self.ident 165 c_ident = "%s_Controller" % self.ident 166 167 self.message_buffer_names = [] 168 169 code(''' 170/** \\file $ident.hh 171 * 172 * Auto generated C++ code started by $__file__:$__line__ 173 * Created by slicc definition of Module "${{self.short}}" 174 */ 175 176#ifndef ${ident}_CONTROLLER_H 177#define ${ident}_CONTROLLER_H 178
|
179#include "params/$c_ident.hh" 180 |
181#include "mem/ruby/common/Global.hh" 182#include "mem/ruby/common/Consumer.hh" 183#include "mem/ruby/slicc_interface/AbstractController.hh" 184#include "mem/protocol/TransitionResult.hh" 185#include "mem/protocol/Types.hh" 186#include "mem/protocol/${ident}_Profiler.hh" 187''') 188 189 seen_types = set() 190 for var in self.objects: 191 if var.type.ident not in seen_types and not var.type.isPrimitive: 192 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 193 seen_types.add(var.type.ident) 194 195 # for adding information to the protocol debug trace 196 code(''' 197extern stringstream ${ident}_transitionComment; 198 199class $c_ident : public AbstractController { 200#ifdef CHECK_COHERENCE 201#endif /* CHECK_COHERENCE */ 202public:
|
177 $c_ident(const string & name);
|
203 typedef ${c_ident}Params Params; 204 $c_ident(const Params *p); |
205 static int getNumControllers();
|
179 void init(Network* net_ptr, const vector<string> & argv);
|
206 void init(); |
207 MessageBuffer* getMandatoryQueue() const; 208 const int & getVersion() const; 209 const string toString() const; 210 const string getName() const; 211 const MachineType getMachineType() const; 212 void print(ostream& out) const; 213 void printConfig(ostream& out) const; 214 void wakeup(); 215 void printStats(ostream& out) const { s_profiler.dumpStats(out); } 216 void clearStats() { s_profiler.clearStats(); } 217 void blockOnQueue(Address addr, MessageBuffer* port); 218 void unblock(Address addr); 219private: 220''') 221 222 code.indent() 223 # added by SS 224 for param in self.config_parameters: 225 code('int m_${{param.ident}};') 226 227 code(''' 228int m_number_of_TBEs; 229 230TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc 231TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc 232string m_name; 233int m_transitions_per_cycle; 234int m_buffer_size; 235int m_recycle_latency; 236map< string, string > m_cfg; 237NodeID m_version; 238Network* m_net_ptr; 239MachineID m_machineID; 240bool m_is_blocking; 241map< Address, MessageBuffer* > m_block_map; 242${ident}_Profiler s_profiler; 243static int m_num_controllers; 244// Internal functions 245''') 246 247 for func in self.functions: 248 proto = func.prototype 249 if proto: 250 code('$proto') 251 252 code(''' 253 254// Actions 255''') 256 for action in self.actions.itervalues(): 257 code('/** \\brief ${{action.desc}} */') 258 code('void ${{action.ident}}(const Address& addr);') 259 260 # the controller internal variables 261 code(''' 262 263// Object 264''') 265 for var in self.objects: 266 th = var.get("template_hack", "") 267 code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') 268 269 if var.type.ident == "MessageBuffer": 270 self.message_buffer_names.append("m_%s_ptr" % var.c_ident) 271 272 code.dedent() 273 code('};') 274 code('#endif // ${ident}_CONTROLLER_H') 275 code.write(path, '%s.hh' % c_ident) 276 277 def printControllerCC(self, path): 278 '''Output the actions for performing the actions''' 279 280 code = code_formatter() 281 ident = self.ident 282 c_ident = "%s_Controller" % self.ident 283 284 code(''' 285/** \\file $ident.cc 286 * 287 * Auto generated C++ code started by $__file__:$__line__ 288 * Created by slicc definition of Module "${{self.short}}" 289 */ 290 291#include "mem/ruby/common/Global.hh" 292#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 293#include "mem/protocol/${ident}_Controller.hh" 294#include "mem/protocol/${ident}_State.hh" 295#include "mem/protocol/${ident}_Event.hh" 296#include "mem/protocol/Types.hh" 297#include "mem/ruby/system/System.hh" 298''') 299 300 # include object classes 301 seen_types = set() 302 for var in self.objects: 303 if var.type.ident not in seen_types and not var.type.isPrimitive: 304 code('#include "mem/protocol/${{var.type.c_ident}}.hh"') 305 seen_types.add(var.type.ident) 306 307 code('''
|
308$c_ident * 309${c_ident}Params::create() 310{ 311 return new $c_ident(this); 312} 313 314 |
315int $c_ident::m_num_controllers = 0; 316 317stringstream ${ident}_transitionComment; 318#define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) 319/** \\brief constructor */
|
286$c_ident::$c_ident(const string &name)
287 : m_name(name)
|
320$c_ident::$c_ident(const Params *p) 321 : AbstractController(p) |
322{
|
323 m_version = p->version; 324 m_transitions_per_cycle = p->transitions_per_cycle; 325 m_buffer_size = p->buffer_size; 326 m_recycle_latency = p->recycle_latency; 327 m_number_of_TBEs = p->number_of_TBEs; |
328''') 329 code.indent()
|
330 for param in self.config_parameters: 331 code('m_${{param.name}} = p->${{param.name}};') |
332 333 code('m_num_controllers++;') 334 for var in self.objects: 335 if var.ident.find("mandatoryQueue") >= 0: 336 code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') 337 338 code.dedent() 339 code(''' 340} 341
|
301void $c_ident::init(Network *net_ptr, const vector<string> &argv)
|
342void $c_ident::init() |
343{
|
303 for (size_t i = 0; i < argv.size(); i += 2) {
304 if (argv[i] == "version")
305 m_version = atoi(argv[i+1].c_str());
306 else if (argv[i] == "transitions_per_cycle")
307 m_transitions_per_cycle = atoi(argv[i+1].c_str());
308 else if (argv[i] == "buffer_size")
309 m_buffer_size = atoi(argv[i+1].c_str());
310 else if (argv[i] == "recycle_latency")
311 m_recycle_latency = atoi(argv[i+1].c_str());
312 else if (argv[i] == "number_of_TBEs")
313 m_number_of_TBEs = atoi(argv[i+1].c_str());
314''')
315
316 code.indent()
317 code.indent()
318 for param in self.config_parameters:
319 code('else if (argv[i] == "${{param.name}}")')
320 if param.type_ast.type.ident == "int":
321 code(' m_${{param.name}} = atoi(argv[i+1].c_str());')
322 elif param.type_ast.type.ident == "bool":
323 code(' m_${{param.name}} = string_to_bool(argv[i+1]);')
324 else:
325 self.error("only int and bool parameters are "\
326 "currently supported")
327 code.dedent()
328 code.dedent()
329 code('''
330 }
331
332 m_net_ptr = net_ptr;
|
344 m_machineID.type = MachineType_${ident}; 345 m_machineID.num = m_version;
|
335 for (size_t i = 0; i < argv.size(); i += 2) {
336 if (argv[i] != "version")
337 m_cfg[argv[i]] = argv[i+1];
338 }
|
346 347 // Objects 348 s_profiler.setVersion(m_version); 349''') 350 351 code.indent() 352 for var in self.objects: 353 vtype = var.type 354 vid = "m_%s_ptr" % var.c_ident 355 if "network" not in var: 356 # Not a network port object 357 if "primitive" in vtype: 358 code('$vid = new ${{vtype.c_ident}};') 359 if "default" in var: 360 code('(*$vid) = ${{var["default"]}};') 361 else: 362 # Normal Object 363 # added by SS 364 if "factory" in var: 365 code('$vid = ${{var["factory"]}};') 366 elif var.ident.find("mandatoryQueue") < 0: 367 th = var.get("template_hack", "") 368 expr = "%s = new %s%s" % (vid, vtype.c_ident, th) 369 370 args = "" 371 if "non_obj" not in vtype and not vtype.isEnumeration: 372 if expr.find("TBETable") >= 0: 373 args = "m_number_of_TBEs" 374 else: 375 args = var.get("constructor_hack", "") 376 args = "(%s)" % args 377 378 code('$expr$args;') 379 else: 380 code(';') 381 382 code('assert($vid != NULL);') 383 384 if "default" in var: 385 code('(*$vid) = ${{var["default"]}}; // Object default') 386 elif "default" in vtype: 387 code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') 388 389 # Set ordering 390 if "ordered" in var and "trigger_queue" not in var: 391 # A buffer 392 code('$vid->setOrdering(${{var["ordered"]}});') 393 394 # Set randomization 395 if "random" in var: 396 # A buffer 397 code('$vid->setRandomization(${{var["random"]}});') 398 399 # Set Priority 400 if vtype.isBuffer and \ 401 "rank" in var and "trigger_queue" not in var: 402 code('$vid->setPriority(${{var["rank"]}});') 403 else: 404 # Network port object 405 network = var["network"] 406 ordered = var["ordered"] 407 vnet = var["virtual_network"] 408 409 assert var.machine is not None 410 code(''' 411$vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); 412''') 413 414 code('assert($vid != NULL);') 415 416 # Set ordering 417 if "ordered" in var: 418 # A buffer 419 code('$vid->setOrdering(${{var["ordered"]}});') 420 421 # Set randomization 422 if "random" in var: 423 # A buffer 424 code('$vid->setRandomization(${{var["random"]}})') 425 426 # Set Priority 427 if "rank" in var: 428 code('$vid->setPriority(${{var["rank"]}})') 429 430 # Set buffer size 431 if vtype.isBuffer: 432 code(''' 433if (m_buffer_size > 0) { 434 $vid->setSize(m_buffer_size); 435} 436''') 437 438 # set description (may be overriden later by port def) 439 code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') 440 441 # Set the queue consumers 442 code.insert_newline() 443 for port in self.in_ports: 444 code('${{port.code}}.setConsumer(this);') 445 446 # Set the queue descriptions 447 code.insert_newline() 448 for port in self.in_ports: 449 code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') 450 451 # Initialize the transition profiling 452 code.insert_newline() 453 for trans in self.transitions: 454 # Figure out if we stall 455 stall = False 456 for action in trans.actions: 457 if action.ident == "z_stall": 458 stall = True 459 460 # Only possible if it is not a 'z' case 461 if not stall: 462 state = "%s_State_%s" % (self.ident, trans.state.ident) 463 event = "%s_Event_%s" % (self.ident, trans.event.ident) 464 code('s_profiler.possibleTransition($state, $event);') 465 466 # added by SS to initialize recycle_latency of message buffers 467 for buf in self.message_buffer_names: 468 code("$buf->setRecycleLatency(m_recycle_latency);") 469 470 code.dedent() 471 code('}') 472 473 has_mandatory_q = False 474 for port in self.in_ports: 475 if port.code.find("mandatoryQueue_ptr") >= 0: 476 has_mandatory_q = True 477 478 if has_mandatory_q: 479 mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident 480 else: 481 mq_ident = "NULL" 482 483 code(''' 484int $c_ident::getNumControllers() { 485 return m_num_controllers; 486} 487 488MessageBuffer* $c_ident::getMandatoryQueue() const { 489 return $mq_ident; 490} 491 492const int & $c_ident::getVersion() const{ 493 return m_version; 494} 495 496const string $c_ident::toString() const{ 497 return "$c_ident"; 498} 499 500const string $c_ident::getName() const{ 501 return m_name; 502} 503const MachineType $c_ident::getMachineType() const{ 504 return MachineType_${ident}; 505} 506 507void $c_ident::blockOnQueue(Address addr, MessageBuffer* port) { 508 m_is_blocking = true; 509 m_block_map[addr] = port; 510} 511void $c_ident::unblock(Address addr) { 512 m_block_map.erase(addr); 513 if (m_block_map.size() == 0) { 514 m_is_blocking = false; 515 } 516} 517 518void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } 519 520void $c_ident::printConfig(ostream& out) const { 521 out << "$c_ident config: " << m_name << endl; 522 out << " version: " << m_version << endl; 523 for (map<string, string>::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { 524 out << " " << (*it).first << ": " << (*it).second << endl; 525 } 526} 527 528// Actions 529''') 530 531 for action in self.actions.itervalues(): 532 if "c_code" not in action: 533 continue 534 535 code(''' 536/** \\brief ${{action.desc}} */ 537void $c_ident::${{action.ident}}(const Address& addr) 538{ 539 DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); 540 ${{action["c_code"]}} 541} 542 543''') 544 code.write(path, "%s.cc" % c_ident) 545 546 def printCWakeup(self, path): 547 '''Output the wakeup loop for the events''' 548 549 code = code_formatter() 550 ident = self.ident 551 552 code(''' 553// Auto generated C++ code started by $__file__:$__line__ 554// ${ident}: ${{self.short}} 555 556#include "mem/ruby/common/Global.hh" 557#include "mem/ruby/slicc_interface/RubySlicc_includes.hh" 558#include "mem/protocol/${ident}_Controller.hh" 559#include "mem/protocol/${ident}_State.hh" 560#include "mem/protocol/${ident}_Event.hh" 561#include "mem/protocol/Types.hh" 562#include "mem/ruby/system/System.hh" 563 564void ${ident}_Controller::wakeup() 565{ 566 567 int counter = 0; 568 while (true) { 569 // Some cases will put us into an infinite loop without this limit 570 assert(counter <= m_transitions_per_cycle); 571 if (counter == m_transitions_per_cycle) { 572 g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized 573 g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again 574 break; 575 } 576''') 577 578 code.indent() 579 code.indent() 580 581 # InPorts 582 # 583 for port in self.in_ports: 584 code.indent() 585 code('// ${ident}InPort $port') 586 code('${{port["c_code_in_port"]}}') 587 code.dedent() 588 589 code('') 590 591 code.dedent() 592 code.dedent() 593 code(''' 594 break; // If we got this far, we have nothing left todo 595 } 596} 597''') 598 599 code.write(path, "%s_Wakeup.cc" % self.ident) 600 601 def printCSwitch(self, path): 602 '''Output switch statement for transition table''' 603 604 code = code_formatter() 605 ident = self.ident 606 607 code(''' 608// Auto generated C++ code started by $__file__:$__line__ 609// ${ident}: ${{self.short}} 610 611#include "mem/ruby/common/Global.hh" 612#include "mem/protocol/${ident}_Controller.hh" 613#include "mem/protocol/${ident}_State.hh" 614#include "mem/protocol/${ident}_Event.hh" 615#include "mem/protocol/Types.hh" 616#include "mem/ruby/system/System.hh" 617 618#define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) 619 620#define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) 621#define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) 622 623TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr 624) 625{ 626 ${ident}_State next_state = state; 627 628 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 629 DEBUG_MSG(GENERATED_COMP, MedPrio, *this); 630 DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); 631 DEBUG_EXPR(GENERATED_COMP, MedPrio,state); 632 DEBUG_EXPR(GENERATED_COMP, MedPrio,event); 633 DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); 634 635 TransitionResult result = doTransitionWorker(event, state, next_state, addr); 636 637 if (result == TransitionResult_Valid) { 638 DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); 639 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 640 s_profiler.countTransition(state, event); 641 if (Debug::getProtocolTrace()) { 642 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 643 ${ident}_State_to_string(state), 644 ${ident}_Event_to_string(event), 645 ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); 646 } 647 CLEAR_TRANSITION_COMMENT(); 648 ${ident}_setState(addr, next_state); 649 650 } else if (result == TransitionResult_ResourceStall) { 651 if (Debug::getProtocolTrace()) { 652 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 653 ${ident}_State_to_string(state), 654 ${ident}_Event_to_string(event), 655 ${ident}_State_to_string(next_state), 656 "Resource Stall"); 657 } 658 } else if (result == TransitionResult_ProtocolStall) { 659 DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); 660 DEBUG_NEWLINE(GENERATED_COMP, MedPrio); 661 if (Debug::getProtocolTrace()) { 662 g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, 663 ${ident}_State_to_string(state), 664 ${ident}_Event_to_string(event), 665 ${ident}_State_to_string(next_state), 666 "Protocol Stall"); 667 } 668 } 669 670 return result; 671} 672 673TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr 674) 675{ 676 switch(HASH_FUN(state, event)) { 677''') 678 679 # This map will allow suppress generating duplicate code 680 cases = orderdict() 681 682 for trans in self.transitions: 683 case_string = "%s_State_%s, %s_Event_%s" % \ 684 (self.ident, trans.state.ident, self.ident, trans.event.ident) 685 686 case = code_formatter() 687 # Only set next_state if it changes 688 if trans.state != trans.nextState: 689 ns_ident = trans.nextState.ident 690 case('next_state = ${ident}_State_${ns_ident};') 691 692 actions = trans.actions 693 694 # Check for resources 695 case_sorter = [] 696 res = trans.resources 697 for key,val in res.iteritems(): 698 if key.type.ident != "DNUCAStopTable": 699 val = ''' 700if (!%s.areNSlotsAvailable(%s)) { 701 return TransitionResult_ResourceStall; 702} 703''' % (key.code, val) 704 case_sorter.append(val) 705 706 707 # Emit the code sequences in a sorted order. This makes the 708 # output deterministic (without this the output order can vary 709 # since Map's keys() on a vector of pointers is not deterministic 710 for c in sorted(case_sorter): 711 case("$c") 712 713 # Figure out if we stall 714 stall = False 715 for action in actions: 716 if action.ident == "z_stall": 717 stall = True 718 break 719 720 if stall: 721 case('return TransitionResult_ProtocolStall;') 722 else: 723 for action in actions: 724 case('${{action.ident}}(addr);') 725 case('return TransitionResult_Valid;') 726 727 case = str(case) 728 729 # Look to see if this transition code is unique. 730 if case not in cases: 731 cases[case] = [] 732 733 cases[case].append(case_string) 734 735 # Walk through all of the unique code blocks and spit out the 736 # corresponding case statement elements 737 for case,transitions in cases.iteritems(): 738 # Iterative over all the multiple transitions that share 739 # the same code 740 for trans in transitions: 741 code(' case HASH_FUN($trans):') 742 code(' {') 743 code(' $case') 744 code(' }') 745 746 code(''' 747 default: 748 WARN_EXPR(m_version); 749 WARN_EXPR(g_eventQueue_ptr->getTime()); 750 WARN_EXPR(addr); 751 WARN_EXPR(event); 752 WARN_EXPR(state); 753 ERROR_MSG(\"Invalid transition\"); 754 } 755 return TransitionResult_Valid; 756} 757''') 758 code.write(path, "%s_Transitions.cc" % self.ident) 759 760 def printProfilerHH(self, path): 761 code = code_formatter() 762 ident = self.ident 763 764 code(''' 765// Auto generated C++ code started by $__file__:$__line__ 766// ${ident}: ${{self.short}} 767 768#ifndef ${ident}_PROFILER_H 769#define ${ident}_PROFILER_H 770 771#include "mem/ruby/common/Global.hh" 772#include "mem/protocol/${ident}_State.hh" 773#include "mem/protocol/${ident}_Event.hh" 774 775class ${ident}_Profiler { 776 public: 777 ${ident}_Profiler(); 778 void setVersion(int version); 779 void countTransition(${ident}_State state, ${ident}_Event event); 780 void possibleTransition(${ident}_State state, ${ident}_Event event); 781 void dumpStats(ostream& out) const; 782 void clearStats(); 783 784 private: 785 int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; 786 int m_event_counters[${ident}_Event_NUM]; 787 bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; 788 int m_version; 789}; 790 791#endif // ${ident}_PROFILER_H 792''') 793 code.write(path, "%s_Profiler.hh" % self.ident) 794 795 def printProfilerCC(self, path): 796 code = code_formatter() 797 ident = self.ident 798 799 code(''' 800// Auto generated C++ code started by $__file__:$__line__ 801// ${ident}: ${{self.short}} 802 803#include "mem/protocol/${ident}_Profiler.hh" 804 805${ident}_Profiler::${ident}_Profiler() 806{ 807 for (int state = 0; state < ${ident}_State_NUM; state++) { 808 for (int event = 0; event < ${ident}_Event_NUM; event++) { 809 m_possible[state][event] = false; 810 m_counters[state][event] = 0; 811 } 812 } 813 for (int event = 0; event < ${ident}_Event_NUM; event++) { 814 m_event_counters[event] = 0; 815 } 816} 817void ${ident}_Profiler::setVersion(int version) 818{ 819 m_version = version; 820} 821void ${ident}_Profiler::clearStats() 822{ 823 for (int state = 0; state < ${ident}_State_NUM; state++) { 824 for (int event = 0; event < ${ident}_Event_NUM; event++) { 825 m_counters[state][event] = 0; 826 } 827 } 828 829 for (int event = 0; event < ${ident}_Event_NUM; event++) { 830 m_event_counters[event] = 0; 831 } 832} 833void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) 834{ 835 assert(m_possible[state][event]); 836 m_counters[state][event]++; 837 m_event_counters[event]++; 838} 839void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) 840{ 841 m_possible[state][event] = true; 842} 843void ${ident}_Profiler::dumpStats(ostream& out) const 844{ 845 out << " --- ${ident} " << m_version << " ---" << endl; 846 out << " - Event Counts -" << endl; 847 for (int event = 0; event < ${ident}_Event_NUM; event++) { 848 int count = m_event_counters[event]; 849 out << (${ident}_Event) event << " " << count << endl; 850 } 851 out << endl; 852 out << " - Transitions -" << endl; 853 for (int state = 0; state < ${ident}_State_NUM; state++) { 854 for (int event = 0; event < ${ident}_Event_NUM; event++) { 855 if (m_possible[state][event]) { 856 int count = m_counters[state][event]; 857 out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; 858 if (count == 0) { 859 out << " <-- "; 860 } 861 out << endl; 862 } 863 } 864 out << endl; 865 } 866} 867''') 868 code.write(path, "%s_Profiler.cc" % self.ident) 869 870 # ************************** 871 # ******* HTML Files ******* 872 # ************************** 873 def frameRef(self, click_href, click_target, over_href, over_target_num, 874 text): 875 code = code_formatter(fix_newlines=False) 876 code("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""") 877 return str(code) 878 879 def writeHTMLFiles(self, path): 880 # Create table with no row hilighted 881 self.printHTMLTransitions(path, None) 882 883 # Generate transition tables 884 for state in self.states.itervalues(): 885 self.printHTMLTransitions(path, state) 886 887 # Generate action descriptions 888 for action in self.actions.itervalues(): 889 name = "%s_action_%s.html" % (self.ident, action.ident) 890 code = html.createSymbol(action, "Action") 891 code.write(path, name) 892 893 # Generate state descriptions 894 for state in self.states.itervalues(): 895 name = "%s_State_%s.html" % (self.ident, state.ident) 896 code = html.createSymbol(state, "State") 897 code.write(path, name) 898 899 # Generate event descriptions 900 for event in self.events.itervalues(): 901 name = "%s_Event_%s.html" % (self.ident, event.ident) 902 code = html.createSymbol(event, "Event") 903 code.write(path, name) 904 905 def printHTMLTransitions(self, path, active_state): 906 code = code_formatter() 907 908 code(''' 909<HTML><BODY link="blue" vlink="blue"> 910 911<H1 align="center">${{html.formatShorthand(self.short)}}: 912''') 913 code.indent() 914 for i,machine in enumerate(self.symtab.getAllType(StateMachine)): 915 mid = machine.ident 916 if i != 0: 917 extra = " - " 918 else: 919 extra = "" 920 if machine == self: 921 code('$extra$mid') 922 else: 923 code('$extra<A target="Table" href="${mid}_table.html">$mid</A>') 924 code.dedent() 925 926 code(""" 927</H1> 928 929<TABLE border=1> 930<TR> 931 <TH> </TH> 932""") 933 934 for event in self.events.itervalues(): 935 href = "%s_Event_%s.html" % (self.ident, event.ident) 936 ref = self.frameRef(href, "Status", href, "1", event.short) 937 code('<TH bgcolor=white>$ref</TH>') 938 939 code('</TR>') 940 # -- Body of table 941 for state in self.states.itervalues(): 942 # -- Each row 943 if state == active_state: 944 color = "yellow" 945 else: 946 color = "white" 947 948 click = "%s_table_%s.html" % (self.ident, state.ident) 949 over = "%s_State_%s.html" % (self.ident, state.ident) 950 text = html.formatShorthand(state.short) 951 ref = self.frameRef(click, "Table", over, "1", state.short) 952 code(''' 953<TR> 954 <TH bgcolor=$color>$ref</TH> 955''') 956 957 # -- One column for each event 958 for event in self.events.itervalues(): 959 trans = self.table.get((state,event), None) 960 if trans is None: 961 # This is the no transition case 962 if state == active_state: 963 color = "#C0C000" 964 else: 965 color = "lightgrey" 966 967 code('<TD bgcolor=$color> </TD>') 968 continue 969 970 next = trans.nextState 971 stall_action = False 972 973 # -- Get the actions 974 for action in trans.actions: 975 if action.ident == "z_stall" or \ 976 action.ident == "zz_recycleMandatoryQueue": 977 stall_action = True 978 979 # -- Print out "actions/next-state" 980 if stall_action: 981 if state == active_state: 982 color = "#C0C000" 983 else: 984 color = "lightgrey" 985 986 elif active_state and next.ident == active_state.ident: 987 color = "aqua" 988 elif state == active_state: 989 color = "yellow" 990 else: 991 color = "white" 992 993 fix = code.nofix() 994 code('<TD bgcolor=$color>') 995 for action in trans.actions: 996 href = "%s_action_%s.html" % (self.ident, action.ident) 997 ref = self.frameRef(href, "Status", href, "1", 998 action.short) 999 code(' $ref\n') 1000 if next != state: 1001 if trans.actions: 1002 code('/') 1003 click = "%s_table_%s.html" % (self.ident, next.ident) 1004 over = "%s_State_%s.html" % (self.ident, next.ident) 1005 ref = self.frameRef(click, "Table", over, "1", next.short) 1006 code("$ref") 1007 code("</TD>\n") 1008 code.fix(fix) 1009 1010 # -- Each row 1011 if state == active_state: 1012 color = "yellow" 1013 else: 1014 color = "white" 1015 1016 click = "%s_table_%s.html" % (self.ident, state.ident) 1017 over = "%s_State_%s.html" % (self.ident, state.ident) 1018 ref = self.frameRef(click, "Table", over, "1", state.short) 1019 code(''' 1020 <TH bgcolor=$color>$ref</TH> 1021</TR> 1022''') 1023 code(''' 1024<TR> 1025 <TH> </TH> 1026''') 1027 1028 for event in self.events.itervalues(): 1029 href = "%s_Event_%s.html" % (self.ident, event.ident) 1030 ref = self.frameRef(href, "Status", href, "1", event.short) 1031 code('<TH bgcolor=white>$ref</TH>') 1032 code(''' 1033</TR> 1034</TABLE> 1035</BODY></HTML> 1036''') 1037 1038 1039 if active_state: 1040 name = "%s_table_%s.html" % (self.ident, active_state.ident) 1041 else: 1042 name = "%s_table.html" % self.ident 1043 code.write(path, name) 1044 1045__all__ = [ "StateMachine" ]
|